Медленная серийная передача Arduino
Я проверяю скорость серийной передачи моего Arduino UNO. Для моих требований я должен перенести 3KB/s с главного компьютера на Arduino. Я написал очень простую программу, которая отвечает на результат Serial.available()
и затем проверил это в Серийном мониторе Arduino IDE. Я начал посылать символы, пока не достиг максимума, который составляет 63 байта. Я был довольно удивлен этим, потому что я где-то читал, что Arduino имеет 128-байтовый последовательный буфер.
В любом случае, я составил очень простой протокол, который передает данные в 48-байтовых пакетах (фактически 49 байтов из-за символа заголовка). Хост отправляет d
символ, то 48 байтов данных. Для проверки достоверности передачи я отправляю простую последовательность байтов от 0 до 47, которая проверяется на стороне Arduino. Если проверка не пройдена, UNO начинает мигать встроенным светодиодом на PIN13. Как только байты отправлены, хост ожидает подтверждения, которое является простым k
персонаж. Arduino отправляет это, когда завершает обработку фактического пакета.
Хост-программа измеряет количество переданных пакетов и отображает его через 1 секунду. Со скоростью передачи 9600 бод ПК успешно передает ~16 пакетов в секунду (~800 байт / с), что вполне нормально. Я попытался улучшить это, увеличив скорость передачи данных с обеих сторон до 57600; однако количество отправляемых пакетов увеличивается лишь незначительно. Я не знаю, в чем проблема. Может быть, я достиг какого-то предела последовательного USB-конвертера?
Вот мой код
ПК (Java, я использую jSSC для связи через последовательный порт)
package hu.inagy.tapduino.server;
import jssc.SerialPort;
import jssc.SerialPortException;
/**
* Test Arduino communication.
*/
public class App
{
private static void testComm(SerialPort port) throws SerialPortException {
long runningSeconds = 0;
long time = System.currentTimeMillis();
long numberOfPackets = 0;
boolean packetSent = false;
while (runningSeconds < 10) {
long currentTime = System.currentTimeMillis();
if (currentTime - time > 1000) {
runningSeconds++;
time = currentTime;
System.out.println(numberOfPackets + " packets/s");
numberOfPackets = 0;
}
if (!packetSent) {
packetSent = true;
port.writeByte((byte) 'd');
for (int i = 0; i < 48; i++) {
port.writeByte((byte) i);
}
} else {
byte[] received = port.readBytes();
if (received != null) {
if (received.length > 1) {
throw new IllegalStateException("One byte expected, instead got: " + received.length);
}
char cmd = (char) received[0];
if ('k' != cmd) {
throw new IllegalStateException("Expected response 'k', instead got: " + cmd);
}
packetSent = false;
numberOfPackets++;
}
}
}
}
public static void main(String[] args)
{
SerialPort port = new SerialPort("COM7");
try {
if (!port.openPort()) {
throw new IllegalStateException("Failed to open port.");
}
port.setParams(57600, 8, 1, 0);
} catch (SerialPortException e) {
throw new IllegalStateException("Exception while setting up port.", e);
}
try {
// Wait 1.5sec for Arduino to boot successfully.
Thread.sleep(1500);
} catch (InterruptedException e) {
throw new IllegalStateException("Interrupt while waiting?", e);
}
try {
testComm(port);
} catch (SerialPortException exc) {
throw new IllegalStateException("Failure while testing communication.", exc);
} finally {
try {
if (!port.closePort()) {
throw new IllegalStateException("Failed to close port.");
}
} catch (SerialPortException e) {
throw new IllegalStateException("Exception while closing port.", e);
}
}
}
}
Arduino
void setup() {
pinMode(13, OUTPUT);
Serial.begin(57600);
}
boolean error = false;
void loop() {
if (error) {
digitalWrite(13, HIGH);
delay(1000);
digitalWrite(13, LOW);
delay(1000);
} else {
while (Serial.available()<49);
char cmd = Serial.read();
if ('d'!=cmd) {
error=true;
return;
}
for (int i=0; i<48; i++) {
int r = Serial.read();
if (r!=i) {
error=true;
return;
}
}
Serial.write('k');
}
}
4 ответа
NagyI, jSSC метод writeByte(байт b) - это тот же writeBytes(новый байт []{b}). Например:
serialPort.writeByte((byte)0xFF);
serialPort.writeBytes(new byte[]{(byte)0xFF});
Эти строки эквивалентны. Метод writeByte() создает новый байтовый массив для каждого байта, который вы хотите отправить. Создание объекта - это дорогостоящая операция в Java, поэтому, если вам нужна высокоскоростная передача данных, используйте готовые байтовые массивы, как в вашем ответе. С уважением, Алексей.
Вы пытались добавить эту строку в функцию Arduino setup()?:
Serial.setTimeout(100); //this will make the Arduino wait a max of only 100ms per incoming set of serial data, before moving on
Читайте здесь: http://arduino.cc/en/Serial/SetTimeout
По умолчанию Arduino имеет тайм-аут в 1 секунду, который должен истечь, если вы просто используете Serial.read() для чтения новых данных. Смотрите мой ответ здесь для получения дополнительной информации и более чистого способа справиться с этим: последовательный интерфейс Matlab с Arduino очень медленный
Я нашел решение. Функция writeByte jSSC в этом случае крайне неэффективна. Если я предварительно сделал 49-байтовый буфер в Java, то сразу передал его в jSSC, и я получил очень большой прирост скорости.
byte[] sendBuffer = new byte[49];
sendBuffer[0] = 'd';
for (byte i = 0; i < 48; i++) {
sendBuffer[i + 1] = i;
}
port.writeBytes(sendBuffer);
На форуме Arduino один из участников предложил мне скорость передачи 345600, что дает мне ~240 пакетов / сек (~12 КБ / сек).
Недавно я использовал это руководство для подключения устройства Arduino UNO к ПК через кабель: Arduino и Java.