Медленная серийная передача 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.

Другие вопросы по тегам