Пакетный обмен данными по UART

Введение

На сегодняшний день существует много способов организовать обмен данными между Desktop-приложением и устройствами на микроконтроллерах: Wi-Fi, Bluetooth, RF, USB, преобразователи интерфейсов и т.д.

В большинстве из вышеперечисленных вариантов реализован пакетный обмен данными между хостом и устройством. Передаваемые данными с гарантией целостности и доставки будут переданы от передатчика к приемнику.

В случае использования интерфейсов RS-232, RS-485, RS-422 или чистого UART организация пакетного обмена данными ложится на программиста.

В данной статье я хотел бы рассказать о своей реализации обмена данными между устройствами

Постановка задачи

Нужно отправить из Qt-приложения пакет данных на устройство с микроконтроллером STM8. К компьютеру присоединён USB-RS485 преобразователь, а на устройстве соответственно преобразователь RS485-UART. Нужно учесть, что на линии связи возможен высокий уровень помех. В этой ситуации было принято решение написать быструю и легкую библиотеку для гарантии целостности принятых данных. *Гарантию доставки данных брала на себе бизнес-логика. Библиотеку решил назвать Sheller.

Требования к разрабатываемой библиотеки были следующие:

  • Фиксированная длинна пакета: количество байт, которые пользователь хочет передать не влияют на общую длину пакета, она остается фиксированной;

  • Минимальное количество внутренних буферов;

  • Наличие надежной, быстровычисляемой контрольной суммы;

  • Побайтного занесения данных;

  • Возможность работы в условиях поврежденных и потерянных байт в пакете;

Выполнение задачи

Принцип работы: определимся с понятием пакета. Пакет представляет собой стартовый байт, данные пользователя и два байта контрольной суммы CRC-16:

В начале использовался алгоритм контрольной суммы CRC8, однако в ходе тестов было выяснено, что при длине пакета в 8 байт количество коллизий было слишком высоким. Тест заключался в следующем: некоторые пакеты специально отправлялись битыми (менялись значения или вовсе удалялся байт из пакета). В итоге на каждый 50000й пакет происходила коллизия CRC и неправильный пакет передавался в бизнес-логику.

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

А во втором случае часть побитого пакета с частью целого пакета соединялись в один пакет, который проходил по контрольной сумме:

*Красной чертой обозначен пакет, последние байты которого не дошли до приемника. Зеленой чертой показан нормальный пакет. Синей чертой изображен пакет, который был отправлен в бизнес-логику.
*Красной чертой обозначен пакет, последние байты которого не дошли до приемника. Зеленой чертой показан нормальный пакет. Синей чертой изображен пакет, который был отправлен в бизнес-логику.

Поэтому было принято решение перейти на CRC16. При запуске тоже теста было пройдено более 2млн пакетов без коллизий и тест был завершен удачно. Вычисление контрольной суммы происходит по табличному методу для ускорения работы.

В качестве StartByte используется значение 0x23. С помощью этого числа парсер делает предположение, что с этого места начинается пакет. Далее парсер проверяет количество байт в буфере и если их столько же или больше чем длинна пакета, то производится подсчет контрольной суммы. Если подсчитанная и принятая контрольные суммы совпадают, то пакет выдается и бизнес логику приложения.

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

Работу всей библиотеки можно описать следующей схемой:

Данная библиотека реализована на Си и на C++. C++ версия предназначена в основном для Arduino.

Для проверки работы Sheller на микроконтроллере был написан ShellerTerminal:

*представляет собой обычный COM-port терминал с использованием алгоритма Sheller.
*представляет собой обычный COM-port терминал с использованием алгоритма Sheller.

Информацию по использованию библиотеку вы можете найти на GitHub.

Источник 📢