Имеется 2 или более устройств на достаточно большом (1-100 метров) расстоянии, между которыми надо передавать данные. Рассмотрев некоторые интерфейсы (rs232/422/485, I2C, Ethernet) пришел к выводу — что они либо не гарантируют однозначную передачу данных, много проводов тоже мне не понравилось, не дают ответ что информация принята. За основу решил взять интерфейс RS485 — из его плюсов он может «далеко идти», 2 провода, можно одновременно подключить кучу приборов, прост, (UART) есть почти на любом контроллере.
В моем случае для меня подходит классическая схема 1 ведущий остальные ведомые. Алгоритм обмена сообщениями такой: передача данных происходит циклами обмена, один цикл обмена состоит из сообщения которое передается от ведущего к ведомому, в ответ ведущий принимает сообщение от ведомого, все остальные молчат. На этой же основе реализовать запрос на получение данных от ведомого устройства.
Один цикл обмена.
Для удовлетворения моих потребностей по передаче данных требуется решить всего два вопроса. Вопрос первый: проверка передаваемого байта основана на самом интерфейсе RS-485, но она не гарантирует достоверно переданный байт — при обнаружении запорченного байта в самом интерфейсе он выкидывается из принимаемых данных, но при этом все равно остается возможность передать неправильный байт — если поменялось(испортилось) четное количество бит в байте. т.е. требуется проверка на количество передаваемых байт и достоверность байтов в передаваемых данных.
Вопрос второй: получение ответного сообщения, на переданное.
По первому вопросу: предлагается такая схема: начальный байт, байт количества
передаваемых символов во всем сообщении, что-то еще, байт контрольной суммы (БКС), конечный байт.
Примечание: байт контрольной суммы считать по модулю 2
На основе предложенной схемы можно судить что если ответ не вернулся, то ведомый — не доступен. При этом возможны варианты когда до ведомого доходит испорченное сообщение и он не отвечает на него, или сообщение до него доходит и он направляет ответ, но ответ портится и ведущий его игнорирует.
Для исправления этого было принято: если ответ не приходит(или приходит но недостоверный), то повторно (кол-во раз без маразма) повторять текущий цикл обмена. Здесь может возникнуть следующая ошибка. Допустим мы направляем команду говорящую устройству, что нужно прибавить громкость на +1 единицу. Когда сообщение доходит до ведомого, он выполняет команду прибавить громкость и отправляет ответ «ок, я сделал как ты хотел», при этом может получится так что ответ портится и ведущий не понимает что команда уже исполнена, и отправляет сообщение повторно. В итоге по приеме команды на стороне ведомого громкость будет уже прибавлена на +2 единицы. Для избегания такого явления, принято ввести идентификатор (НС — номер сообщения) отличия сообщений. Если номер сообщения повторяется, то это повторное сообщение и указанную команду выполнять не надо, а просто отправить предыдущее ответное сообщение.
Так же здесь ввожу еще 2 параметра — это номер (код) устройства которому передаются данные и номер (субкод) обозначающий какую команду надо выполнять(либо какие данные лежат внутри сообщения).
В итоге сложу все вместе и пройду по алгоритму, на примере увеличения значения порога срабатывания реле по температуре на 5 градусов Цельсия и забора текущего показания температуры из ведомого устройства за 1 цикл обмена:
Формирую передаваемые данные от ведущего:
При приеме сообщения ведомым смотрит 2 байт, где лежит кол-во отправленных байт, если кол-во отправленных байт равно кол-ву принятых — значит сообщение не потеряло байтов далее смотрим начальный байт(символ) если он = '$', а также конечный байт(символ) если он = '#' — то это сообщение от ведущего к ведомому.
Тут же рассмотрю возможные варианты сообщения от ведущего к ведомому с ошибками в начальном и конечном байтах, а также вариант с ошибкой кол-ва байт в сообщении. Оговорюсь сразу из 3 значений параметров буду считать правильными 2 и 3, т.е. при совпадении 2-х параметров из 3-х возможных считаю сообщение состоявшимся.
1. начальный байт = '$', кол-во принятых байт = 7(кол-во отправленных байт = 7), конечный байт не равен '#';
2. начальный байт не равен '$', кол-во принятых байт = 7(кол-во отправленных байт = 7), конечный байт = '#';
3. начальный байт = '$', кол-во принятых байт = 7(кол-во отправленных байт = 7, кол-во байт не равно 7), конечный байт = '#'.
Далее обсчитываем контрольную сумму оставшихся 3 байт(байты 3, 4, 5), если она совпадает с БКС продолжаем парсинг данных, смотрим для этого ли устройства эти данные и что надо по ней выполнить, в нашем случае код ведомого устройства 55 и субкод 2 говорит о том что надо прибавить еще 5 градусов к порогу срабатывания реле и в ответном сообщении отправить текущие данные по температуре. Проверяю НС если не равен предыдущему номеру сообщения то выполняю команду и к текущему значению порога срабатывания реле прибавляю 5 градусов. Если они равны (НС), то не выполняю указанные действия, далее перехожу к формированию ответного сообщения.
применение схемы ['$'][кол-во отправленных/принятых байт][...]['#'] — с большой вероятностью гарантирует что такая комбинация не сможет встретится в передаваемых данных, и спровоцировать лжесообщение.
Формирую передаваемые данные от ведомого на основе принятого сообщения:
Принцип обработки следующий: смотрим 2 байт где лежит кол-во отправленных байт, если кол-во отправленных байт равно количеству принятых байт а также начальный байт = '@' и конечный байт = '&' — то это сообщение от ведомого к ведущему. Если требуется использую механизм 2 из 3-х, аналогично описанному выше только уже для ответного сообщения (для символов '@' и '&'). Ведущий при приеме этого сообщения анализирует контрольную сумму 9 (с 3-го по 11-ый) байт, при совпадении контрольной суммы данные в сообщении считаются достоверными и продолжается дальнейший анализ данных. При совпадении кода, субкода и НС отправленного и принятого сообщения продолжаем анализ ответа на сообщение отправленное ведущим. Далее идет анализ принимаемых данных, в моем случае в 6-ом байте значение 1 — говорит о том что команда по прибавке 5 градусов к порогу срабатывания реле произведена успешно, остальные 5 байт говорят о текущих показаниях температуры 7-ой байт — флаг говорящий о достоверности передаваемой температуры (т.е. рассматриваю вариант ведомое устройство включено и отвечает, а датчик может не работать) и 4 байта типа float значения температуры.
Применение 2-х проверочных символов в начале и конце сообщения с большой вероятностью гарантирует при ошибке не спутать сообщения от ведомого и ведущего. Также случайные(не случайные) данные в канале не испортят обмена.
Немного о передаче данных ведомый ведомому, и централизованное сообщение всем ведомым от ведущего.
Сначала о последнем — передача от ведущего ведомым осуществляется назначением кода устройства 255, говорящего ведомым что это централизованное сообщение, далее остается только решить вопрос об общих субкодах, также можно группировать по кодам устройств т.е. назначить код устройства 254 и по этому коду 3 или 4 устройства будут принимать сообщение остальные ее игнорируют, естественно здесь не должна срабатывать часть по отправке ответов от ведомых устройств — т.е. не гарантированно что ведомые однозначно приняли эти сообщения!
О передаче данных ведомый ведомому, реализовать методом ведущий отправляет сообщение ведомому (ведомый1) от которого должна поступить информация другому ведомому (ведомый2), ведомый1 отправляет ответ ведущему при этом ведомый2 подслушивает этот ответ забирая данные себе. Опять же гарантии об однозначной доставки сообщения от ведомого1 к ведомому2 нет, этот надо учитывать!
Возможности интерфейса кол-во теоретически подключаемых устройств около 250, команд/типов данных до 248 для каждого устройства, длинна полезной информации в сообщении до 250 байт.
Поговорим о подводных каменьях:
Вся передача данных рассчитана на работу по времени т.е. следует соблюдать определенные задержки между сообщениями. Так-же рекомендую делать фиксированную задержку между отправленным сообщением ведущего и ответом ведомого для того чтобы ведомый успел сгенерировать данные и полностью передать отправить в канал.
Также важен момент организации ответов от ведомого, может так произойти что ведомый был занят и у него в канале оказались данные нескольких сообщений сразу, следует избегать ответов на устаревшие сообщения (т.к ведущий их уже не ждет) игнорируя их, выполняя команды только последнего актуального сообщения и давать ответ на него.
Отдельно хотелось бы выделить вопрос об синхронизации устройств по времени — следует учитывать что синхронизация по времени ведомого при получении сообщения требует учитывать задержки времени на отправку данных в канал (при скорости 9600 сообщение 10 байт будет передаваться примерно 11 мсек) и важен момент срабатывания прерывания по окончанию приема данных на стороне ведомого, если прерывания нет то стоит учитывать время проверки прихода данных в буфер устройства, и т.п.
Так-же стоит отметить что повторная отправка цикла сообщения также добавляет нюансов, рекомендую на синхронизацию по времени использовать отправку сообщения без повторов, а формировать сообщения с новым НС.
P.S. У меня есть сомнения что я открыл здесь что-то новое, все это в той или иной мере где-то используется в разных интерфейсах! С легкой руки автора этой писанины и применения сего протокола в своих разработках, хочу дать название этому протоколу передачи данных «SRDB2».
Комментарии (41)
Potok
04.11.2016 10:32+1А чем не устроили существующие промышленные шины? Они ведь как раз-таки и решают задачи гарантированной доставки сообщений.
Вот CAN, например. Те же 2 провода, дистанция до километров. Применяют все, кому не лень. Протокол CANopen снимает ряд ограничений (типа ограничения на длину сообщения в 8 байт) и дает кучу небесполезных плюшек вроде обнаружения, кто есть живой на линии (с помощью heartbeat-message).
В общем, мне кажется, что Вы изобрели велосипед.Vasilii_B2
04.11.2016 13:18-1CAN это серьезный протокол, который тянет за собой библиотеки и требования к железу (цене)- он есть не на многих контроллерах, к вашему невнимательному чтению!
Potok
04.11.2016 17:14+1К сожалению, я не нашел указание типа контроллера в статье. Да и не обязательно иметь поддержку CAN на борту — вот, например, есть MCP2515 — с одной стороны CAN, с другой SPI. На чип-дипе 100 рублей, значит, точно есть дешевле ;)
Vasilii_B2
07.11.2016 11:36Т.е. мне надо выкинуть свой программный интерфейс и понакупать ваших МСP2515 и еще припилить SPI в свои проги попутно разработав плату с вашим этим преобразователем чтобы это все красиво заработало, или я что-то недопонимаю!!!
lingvo
04.11.2016 20:08+1Зато он решает многие ваши проблемы, связанные с инициацией сообщения любым узлом и гарантированной доставки. Вы бы попробовали его сначала, прежде чем писать — в вашем случае там вообще никаких библиотек не надо — сообщение в буфер засунул и забыл.
По поводу цены — контроллер с CAN на борту стоит сейчас почти столько же, что и без, что на фоне остального железа просто незаметно.
lzb_j77
04.11.2016 14:06В небольших проектах вполне можно изобретать велосипеды — т.е. пройти весь цикл разработки и выпуска продукта. Это интересно и полезно для самого изобретателя.
SNPopov
04.11.2016 10:32+1Для связи с удаленными модулями сбора данных существует простой и надежный протокол DCON. Интерфейс RS-485, master-slave. Все данные передаются в ASCII кодах, поэтому отладка может производится с помощью любой терминальной программы.
ProstoUser
04.11.2016 12:17-1А подскажите какой-нибудь стандартный протокол на базе RS-485, только чтобы это был не master-slave, а со свободным доступом.
Чтобы любое устройство на шине могло по своей инициативе начать передачу.
SNPopov
04.11.2016 12:49+2В Вашем варианте одним протоколом не обойтись. Должны еще быть средства распознавания коллизий и их разрешения. Известные сети, использующие на физическом уровне RS-485 (PROFIBUS) используют архитектуру master-slave.
ProstoUser
04.11.2016 14:13+1Не обязательно. Те же протоколы с передачей маркера отлично обходятся без распознавания коллизий. Но это создает дополнительную нагрузку и на среду передачи, и на устройства.
Свой протокол придумать не сложно, но не хочется проходить все грабли с нуля.SNPopov
04.11.2016 14:45Но Вы же писали — «Чтобы любое устройство на шине могло по своей инициативе начать передачу». При маркерном доступе устройство не может начать передачу по своей инициативе — только при наличии у него маркера.
ProstoUser
04.11.2016 15:13+1Наверное я не вполне четко выразился.
Конечно же, ни в одной сети устройство не может начать передачу прямо в тот момент, когда ему захотелось. В сетях с маркерным доступе оно должно подождать, когда к нему придет маркер и тогда только передавать.
Главное, что нет выделенных ролей — master/slave. Хочется, чтобы устройства общались между собой «на равных».SNPopov
04.11.2016 15:45+1Используйте Ethernet и стандартные протоколы и не будет у Вас проблем. Тем более, что многие современные МК уже содержат сетевую поддержку на чипе и есть отдельные специализированные чипы с прошитым стеком протоколов за 3$…
ProstoUser
04.11.2016 16:18+1Можно примеры Ethernet контроллеров за 3 бакса с TCP/IP стеком внутри?
SNPopov
04.11.2016 17:57+2WIZNET W5500
ProstoUser
05.11.2016 16:51Спасибо.
Надо будет подумать на эту тему. Хотя к цене контроллера надо добавить как минимум цену трансформатора, порта в свитче и персонального куска витой пары.
RS485 подкупает тем, что куча устройств работает на одной шине длиной в разы большей, чем допустимая длина Ethernet и кроме интерфейсной микросхемы ценой меньше доллара не требует ничего.
Sun-ami
04.11.2016 14:41-1Коллизии могут обнаруживаться приёмом одновременно с передачей, большинство трансиверов позволяют это сделать, хотя время обнаружения коллизии здесь будет больше чем в CAN. Разрешение коллизий можно сделать подобно Ethernet — введением случайной задержки перед повторной передачей. Потребность в таком протоколе существует, например чтобы использовать его как канальный уровень для IP.
SNPopov
04.11.2016 14:56+1Передатчик RS-485 это просто преобразователь ТТЛ в дифференциальный сигнал, а приемник делает обратное преобразование. Стандартный UART тоже никак не контролирует результат передачи. Т.о. используя стандартные компоненты не удасться обнаружить коллизию в сети на базе RS-485.
Sun-ami
04.11.2016 15:03-1Если после передачи каждого байта с небольшой задержкой проверять что принят в точности такой же байт — коллизию можно обнаружить. На небольших скоростях это нужно делать только после передачи первого байта.
SNPopov
04.11.2016 15:41+1RS-485 по определению полудуплексный интерфейс. Вы либо передаете, либо принимаете. Можно конечно использовать 2 UART, один только передает, другой только читает. Но, думаю, овчинка не стоит выделки…
Sun-ami
04.11.2016 16:03-1RS-485 полудуплексный, но UART — обычно дуплексный, и если не запрещать приём во время передачи ни в UARTе ни в трансивере — он будет принимать то что передал сам, и это можно использовать не только для обнаружения коллизий, но и в случае когда возможны настолько мощные помехи, что они искажают сигнал прямо на выходе передатчика.
lingvo
04.11.2016 20:50+1Извиняюсь, может мы о разном RS485 говорим, но как вы распознаете коллизию, если в RS485 нет доминантных и рецессивных уровней? Что 0 что 1 — делаются активно, поэтому при коллизии вы просто делаете КЗ и уровень шины становится неопределенным. При этом в разных сегментах сети может присутствовать разное напряжение, так что один приемник будет думать, что это 1, а другой 0. При этом передатчик как раз ничего не заметит, так как он будет мерять напряжение возле своего передатчика, который «продавит» нужный уровень.
Короче коллизии на RS485 — это очень неблагодарная штука. Их надо избегать вообще, а не пытаться детектировать.Sun-ami
04.11.2016 22:15-1>в RS485 нет доминантных и рецессивных уровней
Это не совсем так, на шине обычно либо присутствует смещение, создаваемое подтяжкой одной линии к + питания, а другой к -, либо пороговый уровень приёмников смещен на 150мВ. Но Вы правы, если передатчики, создавшие коллизию находятся далеко друг от друга, сопротивление линии между ними создаст падение напряжения превышающее это смещение. Но так ли критична необнаруженная коллизия, например, для TCP/IP? Если тишина на шине перед началом передачи надёжно детектируется (как этого требует например Modbus RTU), а время обязательной тишины перед передачей для разных узлов различно — вероятность коллизии будет невелика, и повтор пакетов может оказаться более эффективным решением чем ожидание опроса.lingvo
05.11.2016 02:07+1Это зависит от загрузки шины. Если будет много узлов и каждый будет пытаться что-то самостоятельно передавать, то коллизии будут очень частыми. Где-то я читал, не могу гарантировать точно, но при таком подходе можно утилизировать максимум около 30% пропускной способности шины. Дальше просто из-за разруливания коллизий начнутся затыки — если много узлов одновременно захотят говорить, никаких рандомных задержек не хватит. Будете их увеличивать — уменьшите пропускную способность шины и сделаете еще хуже. Будете уменьшать — получите большую вероятность повторной коллизии при повторной передаче. CAN тем и хорош, что там коллизия не разрушающая, поэтому даже при большой загрузке шины сеть не затыкается, а приоритеты идентификаторов позволяют организовать неплохой QoS.
Modbus RTU тоже из-за чего хорош — там коллизия невозможна в принципе и загрузку шины можно довести до 100% легко, но плата за это — латентность и лишний трафик.Sun-ami
05.11.2016 14:35К сожалению CAN и Modbus RTU имеют серьёзные недостатки. У CAN это малая длина кадра, что приводит к тому, что служебная информация канального уровня занимает не менее 40% пропускной способности канала, и жестко заданные приоритеты узлов. У Modbus RTU при необходимости передать пакет от слейва опрос узлов может потребовать времени, эквивалентного передаче 3500 байт, то есть если нужно передать 32 байта — служебный трафик канального уровня может занять до 99% пропускной способности канала. Думаю, возможно придумать такой протокол обмена по RS-485, в котором для передачи пакетов размером 32..128 байт между произвольными узлами служебный трафик канального уровня займёт в среднем 10..20%. Например по такой схеме: при простое шины ведущий узел периодически выдаёт на шину 1-байтовый маркер времени, остальные узлы отсчитывают от него время с дискретностью в один символ(бит) и могут занять шину, передав свой старт-бит строго в момент времени равный своему адресу. При этом даже для 256 узлов время арбитража шины не превысит времени передачи 26 байт.
lingvo
05.11.2016 19:00Ну по поводу СAN можно поаргументировать. Длина кадра у CAN оптимальная для передачи 2-3 переменных. Ну а CRC и идентификатор сообщения — это неотъемлемая часть таких протоколов.
Также следует заметить, что в CANе приоритеты узлов не задаются, а задаются приоритеты сообщений. Ничего не мешает одному и тому же узлу генерировать как сообщения с низким приоритетом — состояния входов, например, так и какое нибудь ALARM-сообщение с высоким приоритетом.
Sun-ami
05.11.2016 20:14Для передачи 2-3 переменных CAN хорошо подходит, а вот как альтернатива Ethetnet для подключение к Intranet'у двух десятков устройств c web-серверами и набором других сервисов на базе TCP и UDP расстоянии до 500 метров — не очень.
lingvo
05.11.2016 23:38Извиняюсь, но CAN вообще не альтернатива Ethernet. RS-485, кстати тоже.
И через Ethernet передать пару переменных по простой витой паре с гарантированной латентностью, как в CAN, тоже не так просто.Sun-ami
06.11.2016 01:00RS-485 не альтернатива Ethernet как раз из-за отсутствия протокола канального уровня, подходящего для IP. А по пропускной способности в некоторых случаях вполне подошел бы.
x893
04.11.2016 12:54+1Если не надо связи с устройствами других изготовителей — напиши сами любой протокол. 3 дня жизни на это потратите — будет свой мир конечно, но зато Ваш.
hardegor
06.11.2016 09:12Вопрос первый: проверка передаваемого байта основана на самом интерфейсе RS-485, но она не гарантирует достоверно переданный байт
RS-485 ничего не проверяет, этот стандарт описывает только физический уровень.
Sun-ami
Весьма похоже на Modbus RTU, при этом последний компактнее, ошибки выявляются надёжнее за счёт использования CRC-16. И главное — Modbus RTU — промышленный стандарт, в сети есть исходники на С нескольких различных реализаций. Конечно, разобраться с Modbus может быть сложнее, чем придумать свой подобный протокол, реализация — объёмнее, и требования к времени реакции жестче. А номер сообщения можно не добавлять в пакет, если передавать абсолютные значения а не приращения.
Vasilii_B2
Весьма похожи, но все же они отличаются. Насчет компактнее — тут надо подходить к вопросу с лупой, и математическим анализом спроектированного потока данных в конкретном случае. На счет CRC-16 могу сказать следующее, в самом интерфейсе RS-485 хардварное CRC на каждый байт + программное CRC-8 на все байты по моему тоже очень даже не плохо. Не собираюсь никому навязывать использование описанного интерфейса и каждый пусть сам решает что ему использовать, промышленный стандарт с его плюсами и нюансами или облегченный вариант интерфейса который можно с легкостью реализовать для своего независимого использования! По поводу абсолютного и приращения — мне не хотелось привязываться к конкретным отправляемым данным будь то команда или строка на вывод в консоль, данный механизм просто гарантирует не повторяемость информации на уровне протокола передачи данных и при грамотном подходе к реализации интерфейса пользователю передающему информацию не надо даже задумываться о существовании параметра НС т.к. он назначается циклически и не изменяется при повторных сообщениях.
lingvo
Дело не в других, а в вас. Намек на промышленный стандартный протокол намекает на то, что раз уж такой стандарт существует и выглядит таким образом, то наверное его разработали не глупые люди и он работает так не просто потому, что кому-то захотелось, а потому, что это обеспечивает наиболее оптимальный и надежный вариант использования данного интерфейса. Другими словами люди уже давно позаботились о вылизывании всех проблем и глюков, реализовав данный протокол, а на что вы напоретесь еще неизвестно.
Часто также начинающие ставят слишком высокие требования к протоколу, не думая о том, нужно это в данном случае или нет. В итоге вылазят такие приколы, что мама не горюй.
Если нужен гарантированный прием и быстрая реакция, советую поменять RS485 на CAN. Нужный вам механизм там заложен в железе.
Vasilii_B2
Во главных, я не описываю(не изобретаю, не улучшаю) установленный промышленный стандарт, и не берусь сказать за всех неглупых людей, и более того сам в этом работаю — и поэтому написал эту статью, потому что не нашел подходящего для себя варианта! По поводу протокола Modbus, вот в этой статье http://okbit.ru/blog/umnyij-dom/pervyij-modul.html в комментариях автором описана некоторая проблема которая была перекрыта костылем. Еще раз по поводу CAN, для работы с ним требуются контроллеры которые железно его поддерживают — мне данный вариант не подходит!
lingvo
У вас уже есть контроллер? Скажите какой.
Вы просто поймите — невооруженным глазом видно, что вы не очень понимаете, где могут возникнуть проблемы, а где нет.
Например в вашем случае можно спокойно организовать периодический опрос мастером всех ведомых. Ведомый тогда может просто игнорировать все сообщения с испорченными контрольными суммами. В конце концов он примет сообщение в следующий раз при следующем цикле. Пользователь этого как правило не замечает.
Или вы пишете, что ведомому нужно время на то, чтобы переварить сообщение и ответить — это чушь. Ведомому нужно только ответить коротким Ack и делать, что ему сказали, а мастер пусть за следующим разом спрашивает о результате.
В случае же если мастер спрашивает, например, температуру — никто не начинает опрашивать датчик температуры только после прихода запроса. Нет, Датчик опрашивается постоянно и его показания записываются в память, откуда обработчик запроса просто достает последнее значение и выставляет на шину. Т.е данные должны всегда лежать под рукой и готовы к отправке по запросу. Так вы не теряете драгоценное время простоя своей шины в ожидании ответа от слейва.
Vasilii_B2
Не надо придираться к описанному примеру — он написан чтобы показать как можно использовать интерфейс. В том то и проблема что устройство должно быть готово к приему данных, данные могут быть не под рукой, тогда как? Что вы тут за пургу несете на постном масле с вооруженным глазом!!! Найдите мне CAN на Arduino, Raspberry, STM32? Кто мешает использовать предложенный мною интерфейс совместно с устройствами на Modbus? Если вы считаете что предложенный мною интерфейс проблемный — НЕ ИСПОЛЬЗУЙТЕ ЕГО!!!
lingvo
В том то и проблема что устройство должно быть готово к приему данных, данные могут быть не
под рукой, тогда как?
Объясните поподробнее как это может получиться? Желательно на примере.
По поводу Arduino и Rapberry — там ставится адаптер. Но мы же говорим о микроконтроллерах? В STM32 CAN есть в STM32F103, а в F105 их даже два, а также в новых линейках.
Если вы считаете что предложенный мною интерфейс проблемный — НЕ ИСПОЛЬЗУЙТЕ ЕГО!!!
Я и не собираюсь, я просто предлагаю его не использовать ВАМ.
Alexeyslav
CRC-8 слишком мало, а контроль чётности — это как деревянная щеколда на сейфе. CRC-8 даст вероятность пропустить ошибку 1 к 256. Примерно 0.5% ошибок не будут считаться ошибками с соответствующими последствиями.
И я бы осуществлял посекционную проверку на ошибки — секция с адресом и кодом функции должна быть наиболее защищённой, чтобы принимающая сторона могла хотябы дать правильный ответ «повторите, данные повреждены». А в идеале, тут нужен не только контроль, а ещё и алгоритмы коррекции ошибок. Жалко из-за одного повреждённого бита гонять сообщение ещё раз, выгодней восстановить его благодаря избыточности. Например 3 раза повторить заголовок и данные извлечь по принципу минимум 2 одинаковых из 3-х.