Как стать автором
Обновить

Комментарии 41

Весьма похоже на Modbus RTU, при этом последний компактнее, ошибки выявляются надёжнее за счёт использования CRC-16. И главное — Modbus RTU — промышленный стандарт, в сети есть исходники на С нескольких различных реализаций. Конечно, разобраться с Modbus может быть сложнее, чем придумать свой подобный протокол, реализация — объёмнее, и требования к времени реакции жестче. А номер сообщения можно не добавлять в пакет, если передавать абсолютные значения а не приращения.
Весьма похожи, но все же они отличаются. Насчет компактнее — тут надо подходить к вопросу с лупой, и математическим анализом спроектированного потока данных в конкретном случае. На счет CRC-16 могу сказать следующее, в самом интерфейсе RS-485 хардварное CRC на каждый байт + программное CRC-8 на все байты по моему тоже очень даже не плохо. Не собираюсь никому навязывать использование описанного интерфейса и каждый пусть сам решает что ему использовать, промышленный стандарт с его плюсами и нюансами или облегченный вариант интерфейса который можно с легкостью реализовать для своего независимого использования! По поводу абсолютного и приращения — мне не хотелось привязываться к конкретным отправляемым данным будь то команда или строка на вывод в консоль, данный механизм просто гарантирует не повторяемость информации на уровне протокола передачи данных и при грамотном подходе к реализации интерфейса пользователю передающему информацию не надо даже задумываться о существовании параметра НС т.к. он назначается циклически и не изменяется при повторных сообщениях.
Дело не в других, а в вас. Намек на промышленный стандартный протокол намекает на то, что раз уж такой стандарт существует и выглядит таким образом, то наверное его разработали не глупые люди и он работает так не просто потому, что кому-то захотелось, а потому, что это обеспечивает наиболее оптимальный и надежный вариант использования данного интерфейса. Другими словами люди уже давно позаботились о вылизывании всех проблем и глюков, реализовав данный протокол, а на что вы напоретесь еще неизвестно.
Часто также начинающие ставят слишком высокие требования к протоколу, не думая о том, нужно это в данном случае или нет. В итоге вылазят такие приколы, что мама не горюй.
Если нужен гарантированный прием и быстрая реакция, советую поменять RS485 на CAN. Нужный вам механизм там заложен в железе.
Во главных, я не описываю(не изобретаю, не улучшаю) установленный промышленный стандарт, и не берусь сказать за всех неглупых людей, и более того сам в этом работаю — и поэтому написал эту статью, потому что не нашел подходящего для себя варианта! По поводу протокола Modbus, вот в этой статье http://okbit.ru/blog/umnyij-dom/pervyij-modul.html в комментариях автором описана некоторая проблема которая была перекрыта костылем. Еще раз по поводу CAN, для работы с ним требуются контроллеры которые железно его поддерживают — мне данный вариант не подходит!
У вас уже есть контроллер? Скажите какой.
Вы просто поймите — невооруженным глазом видно, что вы не очень понимаете, где могут возникнуть проблемы, а где нет.
Например в вашем случае можно спокойно организовать периодический опрос мастером всех ведомых. Ведомый тогда может просто игнорировать все сообщения с испорченными контрольными суммами. В конце концов он примет сообщение в следующий раз при следующем цикле. Пользователь этого как правило не замечает.
Или вы пишете, что ведомому нужно время на то, чтобы переварить сообщение и ответить — это чушь. Ведомому нужно только ответить коротким Ack и делать, что ему сказали, а мастер пусть за следующим разом спрашивает о результате.
В случае же если мастер спрашивает, например, температуру — никто не начинает опрашивать датчик температуры только после прихода запроса. Нет, Датчик опрашивается постоянно и его показания записываются в память, откуда обработчик запроса просто достает последнее значение и выставляет на шину. Т.е данные должны всегда лежать под рукой и готовы к отправке по запросу. Так вы не теряете драгоценное время простоя своей шины в ожидании ответа от слейва.
Не надо придираться к описанному примеру — он написан чтобы показать как можно использовать интерфейс. В том то и проблема что устройство должно быть готово к приему данных, данные могут быть не под рукой, тогда как? Что вы тут за пургу несете на постном масле с вооруженным глазом!!! Найдите мне CAN на Arduino, Raspberry, STM32? Кто мешает использовать предложенный мною интерфейс совместно с устройствами на Modbus? Если вы считаете что предложенный мною интерфейс проблемный — НЕ ИСПОЛЬЗУЙТЕ ЕГО!!!
В том то и проблема что устройство должно быть готово к приему данных, данные могут быть не
под рукой, тогда как?
Объясните поподробнее как это может получиться? Желательно на примере.

По поводу Arduino и Rapberry — там ставится адаптер. Но мы же говорим о микроконтроллерах? В STM32 CAN есть в STM32F103, а в F105 их даже два, а также в новых линейках.

Если вы считаете что предложенный мною интерфейс проблемный — НЕ ИСПОЛЬЗУЙТЕ ЕГО!!!
Я и не собираюсь, я просто предлагаю его не использовать ВАМ.
CRC-8 слишком мало, а контроль чётности — это как деревянная щеколда на сейфе. CRC-8 даст вероятность пропустить ошибку 1 к 256. Примерно 0.5% ошибок не будут считаться ошибками с соответствующими последствиями.
И я бы осуществлял посекционную проверку на ошибки — секция с адресом и кодом функции должна быть наиболее защищённой, чтобы принимающая сторона могла хотябы дать правильный ответ «повторите, данные повреждены». А в идеале, тут нужен не только контроль, а ещё и алгоритмы коррекции ошибок. Жалко из-за одного повреждённого бита гонять сообщение ещё раз, выгодней восстановить его благодаря избыточности. Например 3 раза повторить заголовок и данные извлечь по принципу минимум 2 одинаковых из 3-х.
libmodbus уже всё давно придумано и написано.
Интересно, ссылочкой на русское описание не TCP части поделится можете?
А чем не устроили существующие промышленные шины? Они ведь как раз-таки и решают задачи гарантированной доставки сообщений.
Вот CAN, например. Те же 2 провода, дистанция до километров. Применяют все, кому не лень. Протокол CANopen снимает ряд ограничений (типа ограничения на длину сообщения в 8 байт) и дает кучу небесполезных плюшек вроде обнаружения, кто есть живой на линии (с помощью heartbeat-message).
В общем, мне кажется, что Вы изобрели велосипед.
CAN это серьезный протокол, который тянет за собой библиотеки и требования к железу (цене)- он есть не на многих контроллерах, к вашему невнимательному чтению!
К сожалению, я не нашел указание типа контроллера в статье. Да и не обязательно иметь поддержку CAN на борту — вот, например, есть MCP2515 — с одной стороны CAN, с другой SPI. На чип-дипе 100 рублей, значит, точно есть дешевле ;)
Т.е. мне надо выкинуть свой программный интерфейс и понакупать ваших МСP2515 и еще припилить SPI в свои проги попутно разработав плату с вашим этим преобразователем чтобы это все красиво заработало, или я что-то недопонимаю!!!
Зато он решает многие ваши проблемы, связанные с инициацией сообщения любым узлом и гарантированной доставки. Вы бы попробовали его сначала, прежде чем писать — в вашем случае там вообще никаких библиотек не надо — сообщение в буфер засунул и забыл.
По поводу цены — контроллер с CAN на борту стоит сейчас почти столько же, что и без, что на фоне остального железа просто незаметно.
НЛО прилетело и опубликовало эту надпись здесь
Для связи с удаленными модулями сбора данных существует простой и надежный протокол DCON. Интерфейс RS-485, master-slave. Все данные передаются в ASCII кодах, поэтому отладка может производится с помощью любой терминальной программы.
А подскажите какой-нибудь стандартный протокол на базе RS-485, только чтобы это был не master-slave, а со свободным доступом.

Чтобы любое устройство на шине могло по своей инициативе начать передачу.

В Вашем варианте одним протоколом не обойтись. Должны еще быть средства распознавания коллизий и их разрешения. Известные сети, использующие на физическом уровне RS-485 (PROFIBUS) используют архитектуру master-slave.
Не обязательно. Те же протоколы с передачей маркера отлично обходятся без распознавания коллизий. Но это создает дополнительную нагрузку и на среду передачи, и на устройства.

Свой протокол придумать не сложно, но не хочется проходить все грабли с нуля.
Но Вы же писали — «Чтобы любое устройство на шине могло по своей инициативе начать передачу». При маркерном доступе устройство не может начать передачу по своей инициативе — только при наличии у него маркера.
Наверное я не вполне четко выразился.

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

Главное, что нет выделенных ролей — master/slave. Хочется, чтобы устройства общались между собой «на равных».
Используйте Ethernet и стандартные протоколы и не будет у Вас проблем. Тем более, что многие современные МК уже содержат сетевую поддержку на чипе и есть отдельные специализированные чипы с прошитым стеком протоколов за 3$…
Можно примеры Ethernet контроллеров за 3 бакса с TCP/IP стеком внутри?
WIZNET W5500
Спасибо.

Надо будет подумать на эту тему. Хотя к цене контроллера надо добавить как минимум цену трансформатора, порта в свитче и персонального куска витой пары.

RS485 подкупает тем, что куча устройств работает на одной шине длиной в разы большей, чем допустимая длина Ethernet и кроме интерфейсной микросхемы ценой меньше доллара не требует ничего.
Коллизии могут обнаруживаться приёмом одновременно с передачей, большинство трансиверов позволяют это сделать, хотя время обнаружения коллизии здесь будет больше чем в CAN. Разрешение коллизий можно сделать подобно Ethernet — введением случайной задержки перед повторной передачей. Потребность в таком протоколе существует, например чтобы использовать его как канальный уровень для IP.
Передатчик RS-485 это просто преобразователь ТТЛ в дифференциальный сигнал, а приемник делает обратное преобразование. Стандартный UART тоже никак не контролирует результат передачи. Т.о. используя стандартные компоненты не удасться обнаружить коллизию в сети на базе RS-485.
Если после передачи каждого байта с небольшой задержкой проверять что принят в точности такой же байт — коллизию можно обнаружить. На небольших скоростях это нужно делать только после передачи первого байта.
RS-485 по определению полудуплексный интерфейс. Вы либо передаете, либо принимаете. Можно конечно использовать 2 UART, один только передает, другой только читает. Но, думаю, овчинка не стоит выделки…
RS-485 полудуплексный, но UART — обычно дуплексный, и если не запрещать приём во время передачи ни в UARTе ни в трансивере — он будет принимать то что передал сам, и это можно использовать не только для обнаружения коллизий, но и в случае когда возможны настолько мощные помехи, что они искажают сигнал прямо на выходе передатчика.
Извиняюсь, может мы о разном RS485 говорим, но как вы распознаете коллизию, если в RS485 нет доминантных и рецессивных уровней? Что 0 что 1 — делаются активно, поэтому при коллизии вы просто делаете КЗ и уровень шины становится неопределенным. При этом в разных сегментах сети может присутствовать разное напряжение, так что один приемник будет думать, что это 1, а другой 0. При этом передатчик как раз ничего не заметит, так как он будет мерять напряжение возле своего передатчика, который «продавит» нужный уровень.
Короче коллизии на RS485 — это очень неблагодарная штука. Их надо избегать вообще, а не пытаться детектировать.
>в RS485 нет доминантных и рецессивных уровней
Это не совсем так, на шине обычно либо присутствует смещение, создаваемое подтяжкой одной линии к + питания, а другой к -, либо пороговый уровень приёмников смещен на 150мВ. Но Вы правы, если передатчики, создавшие коллизию находятся далеко друг от друга, сопротивление линии между ними создаст падение напряжения превышающее это смещение. Но так ли критична необнаруженная коллизия, например, для TCP/IP? Если тишина на шине перед началом передачи надёжно детектируется (как этого требует например Modbus RTU), а время обязательной тишины перед передачей для разных узлов различно — вероятность коллизии будет невелика, и повтор пакетов может оказаться более эффективным решением чем ожидание опроса.
Это зависит от загрузки шины. Если будет много узлов и каждый будет пытаться что-то самостоятельно передавать, то коллизии будут очень частыми. Где-то я читал, не могу гарантировать точно, но при таком подходе можно утилизировать максимум около 30% пропускной способности шины. Дальше просто из-за разруливания коллизий начнутся затыки — если много узлов одновременно захотят говорить, никаких рандомных задержек не хватит. Будете их увеличивать — уменьшите пропускную способность шины и сделаете еще хуже. Будете уменьшать — получите большую вероятность повторной коллизии при повторной передаче. CAN тем и хорош, что там коллизия не разрушающая, поэтому даже при большой загрузке шины сеть не затыкается, а приоритеты идентификаторов позволяют организовать неплохой QoS.
Modbus RTU тоже из-за чего хорош — там коллизия невозможна в принципе и загрузку шины можно довести до 100% легко, но плата за это — латентность и лишний трафик.
К сожалению CAN и Modbus RTU имеют серьёзные недостатки. У CAN это малая длина кадра, что приводит к тому, что служебная информация канального уровня занимает не менее 40% пропускной способности канала, и жестко заданные приоритеты узлов. У Modbus RTU при необходимости передать пакет от слейва опрос узлов может потребовать времени, эквивалентного передаче 3500 байт, то есть если нужно передать 32 байта — служебный трафик канального уровня может занять до 99% пропускной способности канала. Думаю, возможно придумать такой протокол обмена по RS-485, в котором для передачи пакетов размером 32..128 байт между произвольными узлами служебный трафик канального уровня займёт в среднем 10..20%. Например по такой схеме: при простое шины ведущий узел периодически выдаёт на шину 1-байтовый маркер времени, остальные узлы отсчитывают от него время с дискретностью в один символ(бит) и могут занять шину, передав свой старт-бит строго в момент времени равный своему адресу. При этом даже для 256 узлов время арбитража шины не превысит времени передачи 26 байт.
Ну по поводу СAN можно поаргументировать. Длина кадра у CAN оптимальная для передачи 2-3 переменных. Ну а CRC и идентификатор сообщения — это неотъемлемая часть таких протоколов.
Также следует заметить, что в CANе приоритеты узлов не задаются, а задаются приоритеты сообщений. Ничего не мешает одному и тому же узлу генерировать как сообщения с низким приоритетом — состояния входов, например, так и какое нибудь ALARM-сообщение с высоким приоритетом.

Для передачи 2-3 переменных CAN хорошо подходит, а вот как альтернатива Ethetnet для подключение к Intranet'у двух десятков устройств c web-серверами и набором других сервисов на базе TCP и UDP расстоянии до 500 метров — не очень.
Извиняюсь, но CAN вообще не альтернатива Ethernet. RS-485, кстати тоже.
И через Ethernet передать пару переменных по простой витой паре с гарантированной латентностью, как в CAN, тоже не так просто.
RS-485 не альтернатива Ethernet как раз из-за отсутствия протокола канального уровня, подходящего для IP. А по пропускной способности в некоторых случаях вполне подошел бы.
Если не надо связи с устройствами других изготовителей — напиши сами любой протокол. 3 дня жизни на это потратите — будет свой мир конечно, но зато Ваш.
Вопрос первый: проверка передаваемого байта основана на самом интерфейсе RS-485, но она не гарантирует достоверно переданный байт

RS-485 ничего не проверяет, этот стандарт описывает только физический уровень.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории