Как Arduino справляется с переполнением последовательного буфера?

27

Как Arduino справляется с переполнением последовательного буфера? Он выбрасывает новейшие входящие данные или самые старые? Сколько байтов может содержать буфер?


источник

Ответы:

13

Для аппаратных последовательных портов вы можете увидеть в HardwareSerial.cpp, что размер буфера варьируется в зависимости от объема ОЗУ, доступного на конкретном AVR:

#if (RAMEND < 1000)
    #define SERIAL_BUFFER_SIZE 16
#else
    #define SERIAL_BUFFER_SIZE 64
#endif

Для программного последовательного порта в SoftwareSerial.h размер буфера приемника _SS_MAX_RX_BUFFопределен как 64 байта. В обоих случаях прекращается попытка вставить полученные данные в очередь, когда она заполнена, поэтому вы можете получить смесь старых и новых данных в зависимости от того, как вы извлекаете данные из очереди.

В идеале было бы лучше убедиться, что буфер всегда очищается быстро, чтобы избежать заполнения буфера. Может быть, посмотрите на таймеры и реализацию простого конечного автомата, если ваша проблема связана с другим кодом, блокирующим основной цикл.

PeterJ
источник
У меня складывается впечатление, что если я передам данные в Arduino и у меня не будет активного «сборщика» данных на стороне Arduino, то, если поступит больше данных, чем может поместиться в буфере, они будут отброшены. Вы можете это подтвердить? Я наивно предполагал, что передатчик будет блокироваться до тех пор, пока не станет доступным пространство для хранения данных.
Колбан
Я только что просмотрел весь этот код (в / usr / share / arduino / hardware / arduino / core / arduino / HardwareSer‌ ial.cpp) и могу подтвердить, что вы написали здесь. Единственное, что я хотел бы добавить, это то, что, поскольку SRAM равен 2 КБ (RAMEND> 1000), тогда оператор if будет всегда использовать 64, а не 16 в Nano или Uno. Так что если кто-то захочет увеличить размер кольцевого буфера, это будет место для его изменения
SDsolar
5

получающий

Вы можете видеть из источника HardwareSerial, что если входящий байт находит кольцевой буфер заполненным, он отбрасывается:

inline void store_char(unsigned char c, ring_buffer *buffer)
{
  int i = (unsigned int)(buffer->head + 1) % SERIAL_BUFFER_SIZE;

  // if we should be storing the received character into the location
  // just before the tail (meaning that the head would advance to the
  // current location of the tail), we're about to overflow the buffer
  // and so we don't write the character or advance the head.
  if (i != buffer->tail) {
    buffer->buffer[buffer->head] = c;
    buffer->head = i;
  }
}

У меня складывается впечатление, что если я передам данные в Arduino и у меня не будет активного «сборщика» данных на стороне Arduino, то, если поступит больше данных, чем может поместиться в буфере, они будут отброшены. Вы можете это подтвердить?

Да, это будет отброшено. Там нет программного или аппаратного контроля потока, если вы не реализуете свой собственный.

Однако с 64-байтовым буфером и приемом данных (скажем) 9600 бод вы получаете один байт каждые 1,04 мс, и, таким образом, для заполнения буфера требуется 66,6 мс. На 16 МГц процессоре вы должны быть в состоянии проверять буфер достаточно часто, чтобы он не заполнялся. Все, что вам действительно нужно сделать, это переместить данные из буфера HardwareSerial в свой собственный, если вы не хотите обрабатывать его прямо сейчас.

Из #if (RAMEND < 1000)проверки видно, что процессоры с 1000+ байтами ОЗУ получают 64-байтовый буфер, а те, которые меньше ОЗУ, получают 16-байтовый буфер.


Отправка

Данные, которые вы пишете, помещаются в буфер одинакового размера (16 или 64 байта). В случае отправки, если буфер заполняет код, «блокирует» ожидание прерывания для отправки следующего байта через последовательный порт.

Если прерывания отключены, этого никогда не произойдет, поэтому вы не выполняете последовательную печать внутри подпрограммы обработки прерываний.

Ник Гаммон
источник
Я полагаю, что вы отключены на порядок: при 9600 бод вы получаете байт каждые ~ 0,1 мс, поэтому заполнение буфера занимает всего 6,6 мс.
Эрик Дэнд
1
При скорости 9600 бод вы получаете 9600 бит в секунду. Поскольку каждый байт равен 10 битам (8 данных + 1 стартовый бит + 1 стоповый бит), вы получаете 960 байтов в секунду. 1/960 = 0.001042 s- это один байт каждые 1,04 мс.
Ник Гэммон
Ах, конечно, биты, а не байты! Спасибо за исправление.
Эрик Дэнд
Ник, пожалуйста, ответь мне: если у меня есть Pi, на котором запущен Python, и он сидит в ser.readline (), ожидая ввода в качестве регистратора данных, и Arduino передает его через последовательный порт, получая показания, а затем отправляя их как пакет с табуляцией делимметры, затем с использованием задержки (120000), чтобы пакеты приходили каждые две минуты, внутренности Python, вероятно, сразу читают каждый символ, пока не встретят символ новой строки, после чего он освобождает всю строку как возвращаемое значение. Так что мне не нужно беспокоиться о размере буфера Arduino, даже если я отправляю всего 80 символов, а? Это было бы хорошим предположением?
SDsolar
Да, размер буфера отправки не имеет значения в этом сценарии. Небольшой буфер замедлит отправку (немного), но если вы делаете длительную задержку, вам все равно.
Ник Гэммон