Простой последовательный протокол связи точка-точка
Мне нужен простой протокол связи между двумя устройствами (ПК и микроконтроллера). ПК должен отправить некоторые команды и параметры к микро. Микро должен передавать массив байтов (данные от датчика).
данные должны быть защита от шума (кроме проверки четности, я думаю, что мне нужен какой-то другой метод коррекции данных).
есть ли стандартное решение для этого? (Мне нужна только идея, а не полное решение).
С. П. Любые советы приветствуются. P. P. S извините за любые грамматические ошибки, я надеюсь, вы понимаете.
изменить 1. я еще не решил, будет ли он будет master / slave протокол или обе стороны могут начать сообщение. ПК должен знать, когда микро сделали работу и может отправлять данные. Он может непрерывно опрашивать микро, если данные готовы, или микро может отправлять данные, когда работа сделана. Я не знаю, что лучше и упроститься.
Edit 2.оборудование и физический уровень протокол. С RS-232C серийный стандарт, используемый в ПК, я буду использовать асинхронная связь. Я буду использовать только сигналы RxD, TxD и GND. Я не могу использовать дополнительные провода, потому что микроконтроллер AFAIK не поддерживает их. Кстати я использую AVR чип микроконтроллера atmega128.
поэтому я буду использовать фиксированную скорость передачи данных, 8 бит данных, 2 стоп-бит, без проверки четности (или с?).
протокол передачи данных. Это то, что мой вопрос в первую очередь касается. Спасибо за предложение HDLC,PPP и Modbus протоколов. Я буду исследовать его.
12 ответов:
Я хотел бы использовать HDLC. У меня была удача с ним в прошлом. Я бы для сериала точка-точка просто использовал асинхронный кадрирования и забудьте обо всех других контрольных вещах, поскольку это, вероятно, будет излишним.
В дополнение к использованию HDLC для создания пакета. Я форматирую свой пакет следующим образом. Вот как параметры передаются с помощью 802.11
U8 cmd; U8 len; u8 payload[len];
общий размер каждого командного пакета-len +2
затем вы определяете команды типа
#define TRIGGER_SENSOR 0x01 #define SENSOR_RESPONSE 0x02
другое преимущество заключается в том, что вы можете добавлять новые команды, и если вы правильно создадите свой парсер, чтобы игнорировать неопределенные команды, тогда у вас будет некоторая обратная совместимость.
Итак, собрав все это вместе, пакет будет выглядеть следующим образом.
// total packet length minus flags len+4 U8 sflag; //0x7e start of packet end of packet flag from HDLC U8 cmd; //tells the other side what to do. U8 len; // payload length U8 payload[len]; // could be zero len U16 crc; U8 eflag; //end of frame flag
затем система будет отслеживать последовательный поток для флага 0x7e, и когда он там, вы проверяете длину, чтобы увидеть, является ли он pklen >= 4 и pklen=len+4 и что crc действителен. Примечание не полагайтесь только на crc для небольших пакетов вы получите много ложных срабатываний также проверить длину. Если длина или crc не совпадают, просто сбросьте длину и crc и начните с декодирования нового кадра. Если это совпадение, скопируйте пакет в новый буфер и передайте его в функцию обработки команд. Всегда сбрасывайте длину и crc при получении флага.
для вашей функции обработки команд возьмите cmd и len, а затем используйте переключитесь на обработку каждого типа команд. Я также требую, чтобы определенные события отправляли ответ, поэтому система ведет себя как удаленный вызов процедуры, который управляется событиями.
Так например прибор датчика может иметь отметчик времени или ответить к команде для того чтобы принять чтение. Затем он отформатирует пакет и отправит его на ПК, и ПК ответит, что он получил пакет. Если нет, то сенсорное устройство может повторно отправить тайм-аут.
также, Когда вы делаете сетевую передачу вы должны создать его как сетевой стек, как OSI modle как Foredecker очки не забывайте о материал физического уровня. Мой пост с HDLC-это уровень канала передачи данных и обработка RPC и команд-это уровень приложения.
протоколы RS232 являются сложными. Предложение использовать HDLC, является хорошим, но это не все решение. Есть и другие вещи, которые вы должны решить:
- как скорость передачи данных между двумя устройствами определяется? Автобуад? Предопределенный или задайте изложить?
- вы будете делать управление потоком в программном или аппаратном обеспечении или обоих? Обратите внимание, если вы используете аппаратное управление потоком, то вы должны убедитесь, что кабели построены правильно.
- говоря о кабелях, это огромная боль с RS233. В зависимости от устройства, вы можете использовать прямой кабель или перекрестный кабель, или вариант.
- использование программного механизма управления потоком может быть эффективным, поскольку он позволяет использовать самый простой кабель-всего три проводных (TX, RX и common).
- вы выбираете 7 или 8 бит слово?
- проверка четности HW или программных ошибок.
Я предлагаю вам идите с 8 битами данных, без аппаратной четности, 1 стоп-бит и используйте программное обеспечение для управления потоком. Вы должны использовать autobaud если ваше оборудование поддерживает его. Если нет, то autobaud чертовски трудно сделать в программном обеспечении.
здесь есть несколько хороших ответов, вот некоторые полезные указатели:
даже если ваши пакеты не разделены по времени, байт синхронизации является важным способом уменьшения количества мест, из которых вам нужно попытаться построить пакет. Вашим устройствам часто приходится иметь дело с кучей ненужных данных (т. е. конец пакета в полете, когда они включены, или результат аппаратного столкновения). Без байта синхронизации вам придется попытаться сделать пакет из каждого байта, который вы получаете. Байт синхронизации означает, что только 1/255 байт случайного шума может быть первым байтом вашего пакета. Также фантастический, когда вы хотите, чтобы шпионить за вашим протоколом.
наличие адреса на ваших пакетах или даже просто немного говорит master / slave или pc / device полезно, когда вы смотрите на пакеты через snoop tool того или иного типа. Вы можете сделать это, имея другой байт синхронизации для ПК, чем устройство. Кроме того, это будет означать, что устройство не будет реагировать на собственные эхо.
вы можете посмотреть на исправление ошибок (например,Хэмминга). Вы упаковываете 8 бит данных в 12-битный защищенный байт. Любой из этих 12 бит может быть перевернут по пути, и исходные 8 бит будут извлечены. Полезно для хранения данных (используется на компакт-дисках) или там, где устройство не может легко повторно отправить (спутниковые каналы, односторонний rf).
номера пакетов облегчают жизнь. Отправленный пакет несет номер, ответы несут тот же номер флаг, говорящий "ответ". Это означает, что пакеты, которые никогда не поступали (sync corrupted say), легко обнаруживаются отправителем и в полнодуплексном режиме с медленной связью, две команды могут быть отправлены до получения первого ответа. Это также упрощает анализ протокола (третья сторона может понять, какие пакеты были получены без знания базового протокола)
наличие одного мастера является удивительным упрощением. Тем не менее, в полнодуплексной среде это не имеет большого значения. Достаточно чтобы сказать, что вы всегда должны делать это, если вы не пытаетесь сэкономить энергию или вы делаете что-то событие, управляемое на конце устройства (состояние ввода изменено, образец готов).
мое предложение-modbus. Это эффективный и простой стандартный протокол для связи с устройствами, которые имеют датчики и параметры (например, ПЛК). Вы можете получить спецификации на http://www.modbus.org это было вокруг с 1979 года и набирает популярность, вы не будете иметь никаких проблем с поиском примеров и библиотек.
Я прочитал этот вопрос несколько месяцев назад, имея точно такую же проблему, и на самом деле не нашел ничего достаточно эффективного для крошечного 8-битного Микро с небольшим количеством оперативной памяти. Так вдохновленный CAN и LIN, я построил что-то, чтобы сделать эту работу. Я назвал его MIN (Microcontroller Interconnect Network), и я загрузил его в GitHub здесь:
https://github.com/min-protocol/min
там есть две реализации: одна в embedded C, одна в Python для ПК. Плюс небольшая тестовая программа" hello world", где ПК отправляет команды, а прошивка загорается светодиодом. Я писал о этом и работает на плате Arduino здесь:
https://kentindell.wordpress.com/2015/02/18/micrcontroller-interconnect-network-min-version-1-0/
мин довольно просто. Я исправил представление уровня 0 (8 бит данных, 1 стоп-бит, без четности), но оставил скорость передачи данных открытой. Каждый кадр начинается с трех 0xaa байт, которые в двоичном формате это 1010101010, хороший pulsetrain, чтобы сделать обнаружение скорости autobaud, если один конец хочет динамически адаптироваться к другому. Фреймы представляют собой 0-15 байт полезной нагрузки, с 16-битной контрольной суммой Флетчера, а также управляющим байтом и 8-битным идентификатором (чтобы сообщить приложению, что содержат данные полезной нагрузки).
протокол использует начинку символов, так что 0xAA 0xAA 0xAA всегда указывает на начало кадра. Это означает, что если устройство выходит из режима сброса, оно всегда синхронизируется с началом следующего кадра (цель дизайна для MIN никогда не должна была пройти вверх по неполной или неправильной рамке). Это также означает, что нет необходимости иметь определенный Интер-байт и межкадрового временные ограничения. Полная информация о протоколе находится в GitHub repo wiki.
есть место для будущих улучшений с MIN. Я оставил там несколько крючков для передачи блочных сообщений (4 бита управляющего байта зарезервированы) и для более высокого уровня согласования возможностей (идентификатор 0xFF зарезервирован), поэтому есть много область для добавления поддержки обычно необходимых функций.
вот альтернативный протокол:
u8 Sync // A constant value which always marks the start of a packet u16 Length // Number of bytes in payload u8 Data[Length] // The payload u16 Crc // CRC
используйте RS232 / UART, так как ПК (последовательный порт) и процессор (UART) уже могут справиться с этим с минимальной суетой (просто нужно MAX232 чип или аналогичный, чтобы сделать сдвиг уровня).
и используя RS232/UART, вам не нужно беспокоиться о master / slave, если это не имеет отношения. Регулирование потока доступно при необходимости.
предложенное програмное обеспечение ПК: или напишите ваши, или Docklight для простой мониторинг и контроль (ознакомительная версия бесплатно).
больше ошибок, простая проверка четности, или если вам нужно что-то более мощное, возможно кодирование сверточных.
в любом случае, что бы вы ни делали: держите его просто!
EDIT: использование RS232 с ПК еще проще, чем раньше, так как теперь вы можете получить USB-преобразователи RS232/TTL. Один конец входит в USB-разъем вашего ПК и появляется как обычный последовательный порт; другой выходит на 5 В или 3,3 В сигналы, которые могут быть подключены напрямую для вашего процессора, без необходимости сдвига уровня.
мы использовали TTL-232R-3V3 от Обломока FDTI, который работает совершенно для этого вида применения.
мое единственное предложение - если вам нужна шумостойкость, вы можете использовать полнодуплексный RS-422/485. Вы можете использовать IC, подобный этой на стороне AVR, затем конвертер RS-232->RS-422 на стороне ПК, например 485PTBR здесь. Если вы можете найти или сделать экранированный кабель (две скрученные экранированные пары), то у вас будет еще больше защиты. И все это незаметно для микро-и ПК - никаких изменений программного обеспечения.
Что бы вы ни делали убедитесь, что вы использование полнодуплексной системы и убедитесь, что строки разрешения чтения/записи утверждены на IC.
вы можете посмотреть на
Telemetry
и связанная с ним настольная реализация в pythonPytelemetry
основные возможности
это опционально-на основании протокола, но в отличие от MQTT это протокол точка-точка,нет.
как и любой протокол pubsub, вы можете публикации С одного конца на
topic
и уведомления на другом конце по этой теме.на встроенная сторона, публикация в теме так же просто, как:
publish("someTopic","someMessage")
номера:
publish_f32("foo",1.23e-4) publish_u32("bar",56789)
этот способ отправки переменных может показаться ограниченным, но следующая веха намерена добавить дополнительный смысл к разбору темы, делая такие вещи:
// Add an indexing meaning to the topic publish("foo:1",45) // foo with index = 1 publish("foo:2",56) // foo with index = 2 // Add a grouping meaning to the topic publish("bar/foo",67) // foo is under group 'bar' // Combine publish("bar/foo:45",54)
это хорошо, если вам нужно отправить массивы, сложные структуры данных и т. д.
кроме того, шаблон PubSub отлично подходит из-за его гибкости. Вы можете построить master / slave приложения, устройства и т. д.
библиотеки C
библиотека C очень проста для добавления на любое новое устройство, если у вас есть приличная библиотека UART на нем.
вам просто нужно создать экземпляр структуры данных под названием
TM_transport
(определеноTelemetry
), и назначить 4 указателя функцииread
readable
write
writeable
.// your device's uart library function signatures (usually you already have them) int32_t read(void * buf, uint32_t sizeToRead); int32_t readable(); int32_t write(void * buf, uint32_t sizeToWrite); int32_t writeable();
чтобы использовать телеметрию, вам просто нужно добавить следующее код
// At the beginning of main function, this is the ONLY code you have to add to support a new device with telemetry TM_transport transport; transport.read = read; transport.write = write; transport.readable = readable; transport.writeable = writeable; // Init telemetry with the transport structure init_telemetry(&transport); // and you're good to start publishing publish_i32("foobar",...
библиотека Python
на стороне рабочего стола, есть
pytelemetry
модуль, реализующий протокол.если вы знаете python, следующий код подключается к последовательному порту, публикуется один раз по теме
foo
, печатает все полученные темы в течение 3 секунд, затем прекращается.import runner import pytelemetry.pytelemetry as tm import pytelemetry.transports.serialtransport as transports import time transport = transports.SerialTransport() telemetry = tm.pytelemetry(transport) app = runner.Runner(transport,telemetry) def printer(topic, data): print(topic," : ", data) options = dict() options['port'] = "COM20" options['baudrate'] = 9600 app.connect(options) telemetry.subscribe(None, printer) telemetry.publish('bar',1354,'int32') time.sleep(3) app.terminate()
если вы не знаете Python, вы можете использовать интерфейс командной строки
Pytelemetry CLI
командная строка может начинаться с
pytlm
тут вы можете
connect
,ls
(список) получили темы,pub
(опубликовать) по теме, или открытьplot
по теме для отображения полученных данных в реальном времени
Что касается проверки четности (как это было несколько раз здесь):
Они в основном бесполезны. Если вы обеспокоены тем, что один бит может быть изменен по ошибке, то весьма вероятно, что второй бит также может измениться и вы получите ложно-положительный результат проверки четности.
Используйте что - то легкое, как CRC16 с таблицей поиска-он может быть рассчитан по мере получения каждого байта и в основном просто XOR. Предложение Стива Мельникова отлично подходит для маленьких микро.
Я бы также предложил передавать читаемые человеком данные, а не необработанный двоичный файл (если производительность не является вашим первым приоритетом). Это сделает отладку и лог-файлы намного приятнее.
вы не указываете точно, как ведет себя микроконтроллер, но будет ли все, что передается от микро, быть прямым ответом на команду с ПК? Если это так, то кажется, что вы можете использовать какой-то протокол master/slave (это, как правило, самое простое решение). Если обе стороны могут инициировать связь, вам нужен более общий протокол уровня канала передачи данных. HDLC - Это классический протокол для этого. Хотя полный протокол, вероятно, является излишним для ваших нужд, вы могли бы, например, по крайней мере использовать тот же формат кадра. Вы также можете посмотреть на PPP чтобы увидеть, если есть что-то полезное частей.
может быть, этот вопрос может быть совершенно глупым, но кто-нибудь рассматривал использование одного из МОДЕМ X/Y/Z протоколы?
главным преимуществом использования одного из вышеуказанных протоколов является большая доступность готовых к использованию реализаций в различных средах программирования.
скольжения и UDP. Серьезно.
все ПК и подобные устройства говорят на нем.
есть хорошая книга и примеры от TCP Lean
Джереми Бентам тайком получил рис, делающий рабочий TCP / IP. AVR так же хорош, как и PIC, верно ?
Я бы рекомендовал UDP вместо этого, это довольно легко.