Использование Serial.write() для отправки uint32_t, отправки одного байта x4 или отправки 4 байтов x1

В библиотеке IRremote ИК-сигналы декодируются и сохраняются в results.value. В моем проекте используется 32-битный протокол NEC, поэтому ИК-код всегда будет 4-байтовым.

uint32_t dCodedIR;
//
// здесь есть код, который мы можем игнорировать
//
dCodedIR = results.value

Этот декодированный сигнал затем отправляется через последовательный порт на второй MCU, который будет ожидать входящие данные:

while (!Serial.available())  {
}

После этого в FIFO в идеале должен находиться полный код из 4 байтов. Я допускаю случаи, когда < 4 байта готовы (проверить еще, время ожидания истекло? NO:loop YES:reset), но это должно происходить редко. Поэтому я хочу оптимизировать код отправки, чтобы у получателя было больше шансов избежать разделения групп. Теоретически, что лучше: писать как отдельные байты и повторять 4 раза, или сделать 4-байтовый массив для отправки один раз?

Serial.write(dCodedIR & 255);
Serial.write((dCodedIR >> 8) & 255);
Serial.write((dCodedIR >> 16) & 255);
Serial.write((dCodedIR >> 24) & 255);

или

byte sendBuf[4];
//
// 
sendBuf[3] = (byte) dCodedIR & 255;
sendBuf[2] = (byte) (dCodedIR >> 8) & 255;
sendBuf[1] = (byte) (dCodedIR >> 16) & 255;
sendBuf[0] = (byte) (dCodedIR >> 24) & 255;
Serial.write(sendBuf, 4);

(Поскольку для кода будет достаточно места для хранения кода, а производительность является приоритетом, я решил не использовать циклы for, поскольку обновление индекса, его тестирование и выполнение циклов, похоже, добавили бы накладные расходы. .)

, 👍1


1 ответ


Лучший ответ:

2

Если вы не используете очень высокие скорости передачи данных (по крайней мере, выше 115,2 кбит/с), разницы не должно быть.

Причина в том, что любая версия вашего кода должна работать быстрее, чем УАПП. Serial.write() не ожидает отправки байтов проволока. Вместо этого он просто сохраняет эти байты в кольцевом буфере, который принадлежит в библиотеку HardwareSerial. Когда UART готов принять исходящий байт, он вызывает прерывание. Соответствующий ISR занимает один байт из кольцевого буфера и передает его в UART. Так как UART сама буферизуется дважды, все это происходит, пока предыдущий байт отправляется.

Конечным результатом является то, что с любой версией вашего кода вы в конечном итоге с непрерывным потоком байтов. Приходит стартовый бит второго байта сразу после стопового бита первого байта и т. д. Поток не приостанавливается, пока не будет отправлено полное сообщение. То есть, если у вас нет где-то в вашей программе слишком длинные критические секции, которые могут навязывать чрезмерная задержка для всего процесса.

Примечание: если ваш микроконтроллер работает с прямым порядком байтов (как у большинства Arduino), вы можно также избежать одной копии и просто сделать

Serial.write((byte *) &dCodedIR, 4);

Дополнение. Детали могут зависеть от используемого вами MCU. На Uno или аналогичные платы на основе AVR, UART не знает программный кольцевой буфер. Поднимает флаг UDRE0 (пустой регистр данных) всякий раз, когда он готов принять исходящий байт в своих данных отправителя регистр. Когда в буфере есть данные, программа разрешает Прерывание пустого регистра данных, привязанное к флагу UDRE0.

,

Относительно обработки прерываний: см. расширенный ответ. Re Serial.available(): я не знаю, как работает синхронизация вашего кода получения., @Edgar Bonet