@antonwx

Как уменьшить время ответа по COM-порту Arduino в Java?

Используя эту статью на хабре в качестве основы, написал тестовое приложение на Java для передачи и получения данных на/с Arduino.
Привожу код полностью:
package test;

import com.fazecast.jSerialComm.SerialPort;

import arduino.Arduino;

public class test {

	public static void main(String[] args) throws InterruptedException {
        Arduino arduino = new Arduino("COM5", 9600);

        boolean connected = arduino.openConnection();
        System.out.println("Соединение установлено: " + connected);
        Thread.sleep(2000);

        new Reader(arduino).start();
        
        while (true) {
        	Thread.sleep(10);
        	arduino.serialWrite('1');
        }
	}

}

class Reader extends Thread{
	Arduino a;
	public Reader(Arduino a) {
		this.a = a;
	}
	
	@Override
	public void run() {
		try {
			SerialPort comPort = a.getSerialPort();
		   while (true)
		   {
			   long t = System.currentTimeMillis();
		      while (comPort.bytesAvailable() == 0)
		         Thread.sleep(20);

		      byte[] readBuffer = new byte[comPort.bytesAvailable()];
		      comPort.readBytes(readBuffer, readBuffer.length);
		      System.out.println(new String(readBuffer) + " ms since last read: "+(System.currentTimeMillis()-t));
		   }
		} catch (Exception e) { e.printStackTrace(); }
	}
}

А также код на Arduino:
void setup() {
  Serial.begin(9600);
}

void loop() {
  if (Serial.available() != 0) {  
    byte b = Serial.read();
    Serial.print("Received byte: ");
    Serial.println(b);
  }
}

По сути в цикле программа просто передаёт данные на ардуину так быстро, как сможет, пока другой поток читает данные с порта. Проблема в том, что передач в секунду очень мало: почему-то очень большая задержка между вызовом arduino.serialWrite('1'); и фактическим приёмом данных на ардуине. Причём проблема точно в программной части Java, так как если открыть Serial monitor из Arduino IDE, то там задержка крайне малая, и в секунду можно раз 20 точно можно передать. В чём проблема?
5de97d7174b11585409233.png
  • Вопрос задан
  • 177 просмотров
Решения вопроса 1
@antonwx Автор вопроса
В общем категория вопросов уровня "сам спросил - сам ответил".
Нашёл код, отвечающий за отправку данных на ардуину:
public void serialWrite(char c){
		//writes the entire string at once.
		comPort.setComPortTimeouts(SerialPort.TIMEOUT_SCANNER, 0, 0);
		try{Thread.sleep(5);} catch(Exception e){}
		PrintWriter pout = new PrintWriter(comPort.getOutputStream());pout.write(c);
		pout.flush();
	}

удалил его и написал вот так:
public void serialWrite(char c){
		byte[] b = {(byte)c};
		comPort.writeBytes(b, b.length);
	}

Не знаю насколько правильно, но работает как надо. Гуру, скажите, насколько такое решение верно.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
@vanyamba-electronics
При выводе данных на терминал по COM-порту везде применяется кэширование, поскольку компьютер не может ждать столько времени, выводя символ за символом в медленный COM-порт.
Алгоритм кэширования в свою очередь выводит данные построчно. То есть отправляет данные на терминал, только получив символ '\n'.
Чтобы отправить данные немедленно, нужно вызвать функцию flush().
Ответ написан
Комментировать
@evgeniy_lm
поменяйте 9600 на 115200 и будет вам счастье
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
Bell Integrator Ульяновск
До 400 000 ₽
Bell Integrator Хабаровск
До 400 000 ₽
Bell Integrator Ижевск
До 400 000 ₽