Простой последовательный двухточечный протокол связи - PullRequest
53 голосов
/ 03 мая 2009

Мне нужен простой протокол связи между двумя устройствами (ПК и микроконтроллером). ПК должен отправить некоторые команды и параметры на микро. Микро должен передавать массив байтов (данные от датчика).

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

Есть ли стандартное решение для этого? (Мне нужна только идея, а не полное решение).

P.S. Любой совет приветствуется. P.P.S Извините за любые грамматические ошибки, я надеюсь, вы понимаете.

Редактировать 1. Я не решил, будет ли это протокол ведущий / ведомый , или обе стороны могут инициировать связь. ПК должен знать, когда Micro выполнил задание, и может отправлять данные. Он может непрерывно опрашивать микро, если данные готовы, или микро может отправлять данные, когда работа выполнена. Я не знаю, что лучше и проще.

Редактировать 2. Аппаратное обеспечение и физический уровень * протокол 1026 *. Поскольку Используется серийный стандарт RS-232 C в ПК я буду использовать асинхронную связь . Я буду использовать только сигналы RxD, TxD и GND. Я не могу использовать дополнительные провода, потому что микроконтроллер AFAIK их не поддерживает. Кстати, я использую чип AVR ATmega128.

Поэтому я буду использовать фиксированную скорость передачи данных, 8 бит данных, 2 стоповых бита без проверки на четность (или с?).

Протокол передачи данных . Это то, что мой вопрос в первую очередь касается. Спасибо за предложение HDLC , PPP и Modbus протоколов. Я буду исследовать это.

Ответы [ 12 ]

37 голосов
/ 03 мая 2009

Я бы использовал 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 и обработка команд - прикладной уровень .

10 голосов
/ 03 мая 2009

Протоколы RS232 сложны. Предложение об использовании HDLC является хорошим, но это не полное решение. Есть и другие вещи, которые вам нужно решить:

  • Как будет определяться скорость передачи данных между двумя устройствами? Autobuad? Предопределено или установлено экспликация?
  • Будете ли вы управлять потоком в программном или аппаратном обеспечении или в обоих? Обратите внимание, что если вы используете аппаратное управление потоком, то необходимо убедиться, что кабели собраны правильно.
  • Говоря о кабелях, это огромная боль для RS233. В зависимости от устройства вам может понадобиться прямой кабель, перекрестный кабель или другой вариант.
  • Использование программного механизма управления потоком может быть эффективным, поскольку позволяет использовать самый простой кабель - всего три проводных (TX, RX и обычный).
  • Вы выбираете 7 или 8-битное слово?
  • Проверка четности ПО или программная ошибка.

Я предлагаю вам использовать 8 бит данных, без аппаратной четности, 1 стоповый бит и использовать программный контроль потока. Вы должны использовать autobaud, если ваше оборудование поддерживает это. Если нет, то автобод чертовски сложно сделать в программном обеспечении.

8 голосов
/ 21 июня 2009

Здесь есть несколько хороших ответов, вот несколько полезных указателей:

Даже если ваши пакеты не разделены по времени, байт синхронизации является важным способом уменьшения количества мест, из которых вам нужно попытаться создать пакет. Вашим устройствам часто приходится иметь дело с кучей нежелательных данных (то есть с окончанием пакета в полете, когда они включены, или в результате аппаратного столкновения). Без синхронизирующего байта вам придется пытаться составить пакет из каждого полученного вами байта. Байт синхронизации означает, что только 1/255 байтов случайного шума может быть первым байтом вашего пакета. Также FANTASTIC, когда вы хотите отследить ваш протокол.

Наличие адреса в ваших пакетах или хотя бы небольшого упоминания «ведущий / ведомый» или «ПК / устройство» полезно, когда вы смотрите на пакеты с помощью snoop tool того или иного типа. Вы можете сделать это, имея другой байт синхронизации для ПК, чем УСТРОЙСТВО. Кроме того, это будет означать, что устройство не будет реагировать на собственное эхо.

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

Номера пакетов облегчают жизнь. Отправленный пакет несет номер, ответы - тот же номер и флаг, говорящий «ответ». Это означает, что пакеты, которые никогда не поступали (скажем, синхронизация повреждена), легко обнаруживаются отправителем, и в полнодуплексном режиме с медленным каналом две команды могут быть отправлены до получения первого ответа. Это также облегчает анализ протокола (третья сторона может понять, какие пакеты были получены, не зная базового протокола)

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

5 голосов
/ 18 февраля 2015

Я прочитал этот вопрос несколько месяцев назад, у меня точно такая же проблема, и я не нашел ничего достаточно эффективного для крошечного 8-битного микро с небольшим количеством оперативной памяти. Так вдохновленный CAN и LIN, я создал что-то для этой работы. Я назвал его MIN (сеть межконтроллерного соединения) и загрузил его на GitHub здесь:

https://github.com/min-protocol/min

Там есть две реализации: одна на встроенном C, другая на Python для ПК. Плюс небольшая тестовая программа "Hello World", в которой ПК посылает команды, а прошивка загорается светодиодом. Я писал о том, как запустить это на плате Arduino:

https://kentindell.wordpress.com/2015/02/18/micrcontroller-interconnect-network-min-version-1-0/

MIN довольно прост. Я исправил представление уровня 0 (8 бит данных, 1 стоповый бит, без контроля четности), но оставил скорость передачи открытой. Каждый кадр начинается с трех байтов 0xAA, который в двоичном виде равен 1010101010, что является хорошим импульсом для автоматического определения скорости передачи, если один конец хочет динамически адаптироваться к другому. Кадры имеют полезную нагрузку 0-15 байт с 16-разрядной контрольной суммой Флетчера, а также управляющим байтом и 8-разрядным идентификатором (чтобы сообщить приложению, что содержат данные полезной нагрузки).

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

Есть место для будущих улучшений с MIN. Я оставил здесь несколько хуков для передачи блочных сообщений (4 бита управляющего байта зарезервированы) и для согласования возможностей более высокого уровня (зарезервирован идентификатор 0xFF), поэтому есть много возможностей для добавления поддержки для обычно требуемой функциональности.

5 голосов
/ 05 мая 2009

Мое предложение - Modbus. Это эффективный и простой стандартный протокол для связи с устройствами, имеющими датчики и параметры (например, ПЛК). Вы можете получить спецификации по адресу http://www.modbus.org.. Он существует с 1979 года и набирает популярность, у вас не будет проблем с поиском примеров и библиотек.

3 голосов
/ 03 мая 2009

Вот альтернативный протокол:

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, вам не нужно беспокоиться о главном / подчиненном, если это не актуально. Управление потоком доступно при необходимости.

Предлагаемое программное обеспечение для ПК: либо напишите свое, либо Docklight для простого мониторинга и управления (ознакомительная версия бесплатна).

Для большей проверки ошибок, самой простой является проверка на четность или, если вам нужно что-то более мощное, может быть сверточное кодирование .

В любом случае, что бы вы ни делали: будьте проще!

РЕДАКТИРОВАТЬ: Использование RS232 с ПК стало еще проще, чем раньше, поскольку теперь вы можете получить преобразователи USB в RS232 / TTL. Один конец входит в USB-разъем вашего ПК и выглядит как обычный последовательный порт; другой выводит сигналы 5 В или 3,3 В, которые могут быть подключены напрямую к вашему процессору, без смещения уровня.

Мы использовали TTL-232R-3V3 от FDTI Chip, который отлично подходит для такого рода приложений.

2 голосов
/ 10 февраля 2016

Вы можете взглянуть на Telemetry и связанную с ним реализацию рабочего стола в python Pytelemetry

Основные функции

Это протокол на основе PubSub , но в отличие от 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 великолепен благодаря своей гибкости. Вы можете создавать главные / подчиненные приложения, устройства к устройству и т. Д.

C библиотека GitHub version

Библиотеку 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 PyPI version

На настольном компьютере установлен модуль 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 PyPI version

Командная строка может быть запущена с

pytlm

Затем вы можете connect, ls (список) полученных тем, print данные, полученные по теме, pub (публикация) по теме или открыть plot по теме, чтобы отобразить полученные данные в режиме реального времени

enter image description here

enter image description here

2 голосов
/ 06 мая 2009

Мое единственное предложение: если вам нужна шумоустойчивость, вы можете использовать полнодуплексный RS-422/485. Вы можете использовать микросхему, аналогичную this на стороне AVR, затем преобразователь RS-232-> RS-422 на стороне ПК, например 485PTBR . Если вы можете найти или сделать экранированный кабель (две витые экранированные пары), у вас будет еще больше защиты. И все это невидимо для микро и ПК - никаких изменений программного обеспечения.

Что бы вы ни делали, убедитесь, что вы используете полнодуплексную систему, и убедитесь, что на микросхеме заданы строки разрешения чтения / записи.

1 голос
/ 14 мая 2009

Относительно проверок четности (как это происходит несколько раз здесь):

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

Используйте что-то легковесное, например CRC16, с таблицей поиска - его можно рассчитать по мере получения каждого байта, и это в основном просто XOR. Предложение Стива Мельникоффа отлично подходит для маленьких микросхем.

Я бы также предложил передавать читаемые человеком данные, а не сырые двоичные файлы (если производительность не является вашим первым приоритетом). Это сделает отладку и файлы журналов намного приятнее.

0 голосов
/ 01 декабря 2009

SLIP и UDP. Шутки в сторону.

Все ПК и подобные устройства говорят на нем.

Есть хорошая книга и примеры из TCP Lean

Джереми Бентам незаметно получил PIC, работающий по TCP / IP. AVR так же хорош, как PIC, верно?

Я бы рекомендовал UDP вместо этого, это чертовски просто.

...