Когда следует переходить с ASCII на расширенные последовательные протоколы?


28

Все мои микроконтроллерные устройства, которые связываются с ПК через UART, используют строки ASCII для отправки команд и получения данных (как реализовано в Arduino). Это то, что я узнал, когда я начал копаться в электронике, и я всегда находил достаточным посылку голых струн. Однако я заметил, что большинство устройств, с которыми я сталкивался, используют сложные двоичные протоколы, которые включают коды функций, адреса и проверку ошибок CRC.

Когда приемлема базовая связь ASCII и когда мне следует рассмотреть что-то более продвинутое, например, Modbus? Коммерческие устройства используют такие ASCII? Промышленные?


3
Краткий ответ: когда ваше приложение нуждается в этом. Да, коммерческие устройства используют ASCII. Возьмите GPS NMEA в качестве примера. (И снова я напишу здесь свой вопрос )
Евгений Ш.


@EugeneSh .: Стоит отметить, что в NMEA есть поле контрольной суммы, и сброс одного пакета выборки из-за сбоя контрольной суммы (что происходит чаще, чем вы думаете), как правило, не является критическим. Это вполне может быть не так для других протоколов ... и существует множество двоичных протоколов GPS (например, Garmin) для приложений, в которых оно действительно может быть критическим (или в которых частота дискретизации выше 1 Гц требуется, для чего NMEA слишком многословен). Хотя это действительно только укрепляет вашу точку зрения.
Легкость гонок с Моникой

Ответы:


28
  1. ASCII и CRC не являются взаимоисключающими. ASCII - это кодировка, а CRC - для проверки ошибок.

  2. НИЧЕГО можно отправить как ASCII. Мы, старики, наверняка помним UUEncoding, который превращает что-либо в строку ASCII.

  3. А) Для меня это обычно вопрос скорости и эффективности. Отправка большого 32-разрядного числа с помощью ASCII может занять много времени, но для его передачи в двоичном виде через последовательный протокол требуется всего 4 байта.

    B) Отправка NUMBERS через ASCII означает, что вам нужно преобразовать число в ASCII, что является явным дополнительным шагом (это часть того, что делает «printf»).

  4. Если вы каким-то образом потеряете свое место, облажаетесь, теряете формат, получаете неправильный порядковый номер и т. Д., Бинарный протокол связи может облажаться. Если вы отправляете ASCII, вам будет проще восстановиться после взлома, просто войдя в систему и посмотрев на поток данных.


12
+1 для "ASCII - это кодировка". Это не протокол; протоколы могут быть построены поверх ASCII.
Пит Беккер

8
Автоматическое восстановление после сбоя по сути не проще для текстового протокола, чем двоичного, но его проверка и отладка, безусловно, будут.
Ник Джонсон

1
@NickJohnson - абсолютно. Как только вы на пороге открытия файла в шестнадцатеричном редакторе, чтобы увидеть, что вы можете восстановить, вы уже в FUBAR, так что SOP идет
Скотт Сейдман

1
@nickjohnson, это не совсем так. ASCII предоставляет вам множество опций внешнего формирования кадров / разделителей, чтобы помочь синхронизации и восстановлению, что потребует дополнительного экранирования, вставки битов, временного интервала или других приемов, если канал используется для двоичных данных полной ширины.
Крис Страттон

2
Я всегда предпочитаю ASCII при написании протоколов для всех очевидных преимуществ (удобочитаемость, журналируемость и т. Д.). Существует два случая, когда двоичный код имеет больше смысла: во-первых, если скорость является проблемой, и вам нужен двоичный файл, чтобы поместить как можно больше данных в поток, и, во-вторых, незначительно, если вы намеренно пытаетесь запутать или даже зашифровать данные поток, чтобы помешать или предотвратить обратное проектирование. При этом я разработал бинарные протоколы с обратной инженерией, и это во многом меня раздражало, а не мешало.
J ...

10

Вот несколько мыслей по этому поводу:

  • ASCII хорош, потому что вы можете использовать последовательный монитор для ручного просмотра того, что отправляется.
  • если ваше соединение ненадежно, вы должны ожидать ошибок передачи и должны использовать CRC для проверки целостности каждого полученного сообщения. Это также может быть сделано в сообщениях ASCII.
  • если ваше соединение слишком медленное, вы можете уменьшить размер ваших сообщений, переключившись на двоичный формат
  • Специализированный двоичный формат может быть легче декодировать на стороне приемника, чем ASCII

7

На простейшем уровне можно сказать, что простой протокол связи имеет три уровня: физический, транспортный и прикладной. (Есть модели с большим количеством, таких как OSI с 7 или TCP / IP с 4. Количество уровней не очень важно в контексте этого вопроса.)

Прикладной уровень - это уровень, с которым вы работаете непосредственно в своем коде, и фокус вопроса. Что касается транспортного уровня, то байт, который вы передали ему в send_data, является просто двоичным шаблоном, но вы можете интерпретировать его в коде приложения как букву «A». Расчет CRC или контрольной суммы будет одинаковым независимо от того, считаете ли вы, что байт равен «A», «0x41» или «0b01000001».

Транспортный уровень - это уровень пакета, где у вас есть заголовки сообщений и проверка ошибок, будь то CRC или базовая контрольная сумма. В контексте прошивки у вас может быть такая функция, как send_data, где вы передаете ей байт для отправки. Внутри этой функции она помещается в пакет, который говорит: «Эй, это нормальное сообщение, требуется подтверждение, контрольная сумма равна 0x47, текущее время - X». Этот пакет отправляется через физический уровень принимающему узлу.

На физическом уровне определяются электроника и интерфейс: разъемы, уровни напряжения, синхронизация и т. Д. Этот уровень может варьироваться от пары трассировок, запускающих сигналы TTL для базового UART на печатной плате, до полностью изолированной дифференциальной пары, как в некоторых CAN реализации.

На принимающем узле пакет поступает на физическом уровне, распаковывается на транспортном уровне, и затем ваш двоичный шаблон становится доступным для прикладного уровня. Прикладной уровень принимающего узла должен знать, должен ли этот шаблон интерпретироваться как «A», «0x41» или «0b01000001», и что с ним делать.

В заключение, почти всегда приемлемо посылать символы ASCII, если этого требует приложение. Важно понять вашу схему связи и включить механизм проверки ошибок.


Протоколы Ascii также могут включать контрольную сумму. Я встречал варианты Hex-as-ascii, используя представление чисел ascii.
Евгений Ш.

@EugeneSh. Уточнил этот момент
Мэтт Янг

Не для придирки, но TCP не четырехслойный; это считается подходящим для четвертого уровня модели OSI. Последовательная связь не очень подходит для модели OSI.
Batsplatsterson

@batsplatsterson Это придирчиво и довольно неуместно с точки зрения, которую я делаю.
Мэтт Янг

5

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

(*) 0xFF - называется уничтожением, потому что тот, кто вводит ошибочный символ при вводе данных на бумажную ленту, может нажать кнопку «пошаговая лента назад» и нажать «потер», чтобы заменить ошибочно перфорированный символ на 0xFF, что игнорируется большинством получателей).


2

Одним из преимуществ отправки строк ASCII является то, что управляющие коды могут затем использоваться для сигнализации начала / конца сообщения. например, STX (символ 2) и ETX (символ 3) могут сигнализировать о начале и окончании передачи. В качестве альтернативы вы можете добавить простой перевод строки, чтобы отметить конец передачи.

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


3
Многие двоичные протоколы действительно резервируют один или несколько битовых шаблонов в качестве управляющих кодов, но они также включают механизм перехода для обработки этих кодов, когда они появляются в данных.
Дэйв Твид

Вы можете зарезервировать любой шаблон, чтобы пометить все, что вы хотите в двоичном виде. Например, я работаю над проектами с быстрым потоком данных и медленным потоком данных, выходящим из одного и того же uart. Я зарезервировал самый большой отрицательный int32 в качестве флага для моих медленных данных, и просто насытил свои отрицательные данные на самый большой отрицательный + 1.
Скотт Сейдман

Согласовано. Я уточнил это в отредактированном ответе, я надеюсь.
Транзистор

2

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

Еще один бонус - я использую последовательные радиоустройства для передачи сообщений между arduinos, и я могу использовать последовательный монитор, подключенный к моему ноутбуку, и вводить сообщения, чтобы определенные вещи происходили. Отлично подходит для тестирования.

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


2

Вместо Modbus рассмотрим HDLC . Вы получаете обнаружение ошибок (что важно на шумных последовательных линиях). Синхронизация надежна, экранирование надежно.

Я использовал HDLC в сетях RS-485 без проблем, и PPP также использует его.


2
Было бы неплохо, если бы вы указали, почему вы предлагаете это по Modbus.
Я понятия не имею, что я делаю

1

ASCII над UART является наиболее популярным отчасти потому, что:

  • Он удобен для чтения при отладке (мне еще предстоит увидеть логический анализатор, который не декодирует ASCII).

  • Это очень легко реализовать, у вас есть ASCII-таблица через быстрый Google, который хорошо стандартизирован.

  • Он имеет встроенную синхронизацию со стартовыми / стоповыми битами.

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

Затем вы попадаете в ситуацию, когда начинаете отправлять определенную кодировку, такую ​​как отправка в памяти представления числа с плавающей запятой по сравнению с преобразованием числа с плавающей запятой в ASCII, отправка этого по последовательному каналу, длина которого может превышать 4 байта, и затем преобразование этого обратно в представлении в памяти на хосте. Вместо этого вы просто отправляете 4-байтовое представление каждый раз. Конечно, вы можете начать обрабатывать кодировку самостоятельно, но затем вам нужно установить начальный / конечный теги, порядок и т. Д.

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.