Modbus rtu своими руками

Modbus RTU для Чайников

Modbus — протокол, работающий по принципу «клиент-сервер».
Широко применяется в промышленности.
Modbus может использоваться для передачи данных через последовательные линии связи RS-485, RS-422, RS-232, а также сети TCP/IP.
В этой статье рассмотрим на примере линии RS-485.

И так, в основе интерфейса RS-485 лежит принцип дифференциальной (балансной) передачи данных. Суть его заключается в передаче одного сигнала по двум проводам. Причем по одному проводу (условно A) идет оригинальный сигнал, а по другому (условно B) — его инверсная копия. Другими словами, если на одном проводе «1», то на другом «0» и наоборот. Таким образом, между двумя проводами витой пары всегда есть разность потенциалов: при «1» она положительна, при «0» — отрицательна.

Именно этой разностью потенциалов и передается сигнал. Такой способ передачи обеспечивает высокую устойчивость к синфазной помехе. Синфазной называют помеху, действующую на оба провода линии одинаково. К примеру, электромагнитная волна, проходя через участок линии связи, наводит в обоих проводах потенциал. Если сигнал передается потенциалом в одном проводе относительно общего, как в RS-232, то наводка на этот провод может исказить сигнал относительно хорошо поглощающего наводки общего («земли»). Кроме того, на сопротивлении длинного общего провода будет падать разность потенциалов земель — дополнительный источник искажений. А при дифференциальной передаче искажения не происходит. В самом деле, если два провода пролегают близко друг к другу, да еще перевиты, то наводка на оба провода одинакова. Потенциал в обоих одинаково нагруженных проводах изменяется одинаково, при этом информативная разность потенциалов остается без изменений.

Воплощение
Есть несколько вариантов.
Подешевле на известной MAX-ADM485.
Без изоляции, развязки, изолированного источника питания. Зато стоит не более 25 рублей.
Подороже, сюда можно отнести монстра ADM2587, ADM2483 и пр.
Разводить пп желательно очень вдумчиво.
Узел RS-485 хорошо вынести подальше от точных и измерительных цепей, узлов и т.п.
На обычную сигнальную линию проложенную вдоль силовых установок и мощных потребителей, воздействует огромное количество наводок и помех.
В некоторых случаях, их потенциал может достигнуть нескольких тысяч вольт!

Так выглядит типичная посылка, от Ведущего — Ведомому.

Так выглядит ответ Ведомого — Ведущему

ID — Адрес ведомого устройства. Он может иметь значения от 1 до 247. Адрес 0 используется для широковещательной передачи, его распознаёт каждое устройство, адреса в диапазоне 248…255 — зарезервированы.
Команда(код функции):
в данном примере одна, на чтение 0x03.
Но в действительности их намного больше.
Все коды функций делятся на:
Публичные коды, описанные в стандарте MODBUS-IDA. Их список включает уже назначенные и используемые коды, а также коды для будущего использования;
User-Defined Function Codes (65-72, 100-110) — коды, которые могут использоваться компаниями для собственных функций, и не описаны в спецификации;
Reserved Function Codes (9, 10, 13, 14, 41, 42, 43, 90, 91, 125, 126 и 127) — зарезервированы коды, которые не доступны для общего использования.
(0x02) — чтение значений из нескольких дискретных входов (Read Discrete Inputs).
(0x03) — чтение значений из нескольких регистров хранения (Read Holding Registers).
(0x04) — чтение значений из нескольких регистров ввода (Read Input Registers).
(0x05) — запись значения одного флага (Force Single Coil).
(0x06) — запись значения в один регистр хранения (Preset Single Register).
(0x07) — Чтение сигналов состояния (Read Exception Status)
(0x0F) — запись значений в несколько регистров флагов (Force Multiple Coils)
(0x10) — запись значений в несколько регистров хранения (Preset Multiple Registers)
(0x16) — запись в один регистр хранения с использованием маски «И» и маски «ИЛИ» (Mask Write Register).
(0x18) — Чтение данных из очереди (Read FIFO Queue)
(0x14) — Чтение из файла (Read File Record)
(0x15) — Запись в файл (Write File Record)
(0x08) — Диагностика (Diagnostic)
(0x0B) — Чтение счетчика событий (Get Com Event Counter)
(0x0C) — Чтение журнала событий (Get Com Event Log)
(0x11) — Чтение информации об устройстве (Report Slave ID)
(0x2B) — Encapsulated Interface Transport
Обработка ошибок
Ведущий отправляет запрос к Ведомому, в котором в поле «код функции» указывает ему на необходимое действие.
Байты данных содержат информацию, необходимую для выполнения данной функции.
Ведомый, в случае удачного выполнения этой функции, повторяет код функции в ответе.
При возникновении ошибки, код функции в ответе модифицируется — старший бит выставляется в 1.
В байтах данных передается причина ошибки. Например при исполнении Ведомым функции 0x0F возникла ошибка, тогда он ответит Ведущему полем функции равным 0x8F.
В дополнении к изменению кода функции, Ведомый размещает в поле данных уникальный код, который указывает на тип и причину ошибки.

Читайте также:  Как сделать автомат игрушками своими руками

CRC-16, циклически избыточный код.
Полином:

Для расчета есть два метода:
Простой

и Табличный

Использование табличной функции
unsigned char mess[3] = <1,108,8>;
volatile unsigned short res1 = CRC16(&mess,3);
res1 будет равен 0x0СС6 при подстановке в конце команды менять местами
старший и младший байты не надо. Эта функция при занесении значения в
res1 автоматически меняет местами старший и младший байты.


Как указано в даташите на ADM485, для работы на прием выводы RE-DE-DI должны быть в 0,
тогда на выводе RO появляются принятые данные.
Для работы на передачу — все противоположно, но данные следует слать на DI.
Простая функция приема

Ответ выглядит примерно так

Все интервалы организованы на прерываниях.
Сообщение должно начинаться и заканчиваться интервалом тишины, длительностью не менее 3,5 символов.
Во время передачи сообщения не должно быть пауз длительностью более 1,5 символов.
Для скоростей более 19200 бод допускается использовать интервалы 1,75 и 0,75 мс, соответственно.

Для отладки удобно использовать что-то вроде Modbus_Poll.

К сожалению он не бесплатный, триальная версия работает 25 дней, ограничивает работу 10 минутами и всячески достает сообщениями…

Файл логанализатора, с общением по Modbus Яндекс диск

Рекомендуется к прочтению:
Спецификация Modbus Link
RS-485 для чайников — Link
Modbus в Википедии Link
Modbus протокол Link

Отдельное спасибо товарищу Papandopala, за функцию табличного расчета CRC.

Источник

Простая реализация Модбас-стека на MSP430. Часть первая: Modbus (RTU)

Простая реализация Модбас-стека на MSP430. Часть первая: Modbus (RTU). Часть вторая здесь
А потом пришла третья часть — с подчищеной библиотекой.

Что бы там ни говорили о «старости» Модбаса, он является очень хорошим и заслуженно популярным протоколом в системах промышленной автоматизации. Поэтому полезно иметь возможность использовать Модбас в МК-девайсах, согласных на скромную роль Слейва. Для такого Слейва я и написал Модбас стек. И хотя мой МК — это достаточно новый и еще не очень популярный ФРАМ-камешек из семейства MSP430FR57xx, программу можно портировать и на другие МК.
Хорошо известна библиотека от Кристиана Вольтера, которую я раньше использовал для проекта на Атмеге168. Тем, кто действительно понимает Си, она может оказаться оптимальной. Я программирую примитивно и все время работы с этой библиотекой ощущал себя туземцем, которому дали мобилку, а он только и умеет, что нажать в ней одну кнопку и ответить на вызов. А потом пришло время для MSP430 — а в библиотеке Вольтера как раз для этих МК варианта нет. Ну, и слава Богу. Ленивым толчок в зад, чтобы сами чьой-то делали.
Еще поделюсь вот этой ссылкой. Она, оказывается, лежала у меня давно, но нашел ее только сейчас, когда начал писать эту заметку. Там есть весьма неплохие реализации (в том числе и Мастера!), спокойное обсуждение… Почитайте. Меня подкупило использование структуры для хранения всех переменных стека — это открывает возможность легко плодить несколько слейвов, если в МК есть более одного УАРТа. Такой же подход я видел в примере от уважаемого коллеги reptile, который как-то прислал мне свою реализацию.
Но я сделал по-своему. Просто подошел с чистого листа, озабоченный именно простотой и понятностью (хотя бы для меня!) реализации.

1. Протокол Модбас

Несколько слов о том, что собой представляет этот Модбас. Кто знаком с протоколом — читайте с п.2. Я изложу все очень нестрого, уделяя внимание простоте и краткости.
Замечу. что я опираюсь на «Руководство по имплементации Модбаса в последовательных каналах передачи данных», а также «Спецификацию приложений, работающих по Модбасу». Я только что был поражен также обилием инфо на русском, дав Гуглю запрос «Введение в Модбас протокол» 🙂 Что там кому понравится — смотрите сами.

Читайте также:  Активный темброблок для электрогитары своими руками

Протокол достаточно прост. Он описывает обмен между устройствами, причем реализована система «Мастер-Слейв» (Ведущий-Ведомый, Главный-Подчиненный, Начальник-Дурак). Обмен всегда начинает Мастер: он делает запрос, Слейв отвечает. Нет запроса — нет ответа. Это раз.
Второе: обычно на запрос должен быть ответ. Исключение — широковещательный запрос, но это пока забудем. То есть, если Мастер даже не запросил данные, а наоборот — пихнул их Слейву, то все равно Слейв по получению должен отписаться, мол, все гут, командир, запрос от тебя получен, данные принял, столько-то байт. Не будет такого ответа — Мастер выждет таймаут и посчитает, что Слейв недопонял. Может начать повторами долбить, может вычеркнуть Слейва из числа живущих, может еще чего — стандарт не оговаривает.
Третье: я рассматриваю только один режим работы Модбаса — Modbus RTU. Есть еще и другие режимы, но при работе по RS-232 или RS-485 именно Modbus RTU должен быть в каждом устройстве, как обязательный. Он и является самым популярным.

Итак, запрос-ответ. В ходе такого акта общения данные либо тудЫ, либо сюдЫ. Что за данные? Да простые, цифровые коды. Либо это отдельные биты информации (в далекие времена им отвечали обмотки реле, катушки, потому по-аглицки до сих пор их называют Coils), либо 16-разрядные слова, несущие информацию из т.н. регистров. Как катушки, так и регистры имеют свои адреса, номера. В стандарте много сделано, чтобы запутать православных, но скажу просто: адрес — двухбайтное число. От 0 до сами знаете…
Какова структура запроса и ответа? Общая структура передаваемого от Мастера запроса такова (каждая строка — это один символ):

Адрес
Код функции
Данные
Данные

Данные
Контролька CRC, младший байт
Контролька CRC, старший байт

В Modbus RTU разделителем сообщений (фреймов, содержащих запросы и ответы) является тишина на линии в течение не менее 3,5 символов. С учетом того, что стандартный символ передается УАРТом 11-ю битами, получаем длительность этого периода ( называют его t3.5), равную 38,5 периодов бодрейта. Например, для 9600 бод — 4,01 мс (38,5/9600). Для скоростей от 38400 и выше рекомендовано использовать фиксированную длительность 1,75 мс.
Красивая картинка по этому поводу — на странице 13/44 вышеупомянутого Руководства (пункт 2.5.1.1):

Весь фрейм должен передаваться как непрерывный поток символов. Если обнаружен разрыв между символами длительностью более 1,5 времени передачи одного символа (считаем: 1,5*11=16,5 периодов бодрейта, выше 38400 бод — фиксировано 0,75 мс), то приемник должен поставить «черную метку» и похерить принимаемый фрейм. Обращаю внимание, не надо при этом лихорадочно искать во входном потоке начало следующего фрейма. Можно просто принимать символы дальше, ожидая стандартного признака окончания — паузы t3.5. И лишь потом, начиная парсинг, следует проверить наличие флага «Плохой фрейм» — и похерить принятое сообщение.
Вот иллюстрация

Замечу, что я постучался рогами, пока не понял, что измерять нужно время от окончания предыдущего символа, до начала следующего. Это вовсе не одно и то же, что измерять время между прерываниями по принятому в УАРТ символу! Можно легко вляпаться в ситуацию, когда забракуем вполне годный фрейм.
Далее. Ответ на запрос дается в тех, и только в тех случаях, если команда принята, фрейм не битый (контролька CRC в порядке) и адрес в запросе именно наш. В ответе повторяется первый байт (адрес), а поле кода функции — либо тот же код, либо в него добавлен бит 128 (0х80). Последнее — если обнаружена та или иная ошибка (Exception). Примерами таких ошибок являются: ошибочный код функции, ошибочный номер регистра, недопустимые значения в поле данных… Пока не будем о плохом.
Функции. Они кодируются 7 битами, поэтому придумано их много. Но для нас, простолюдинов, достаточно знать 2 основные:
03 — читать регистры (блок регистров, идущих подряд в адресном поле)
16 — записать регистры (тоже блок регистров)
Есть еще чтение и запись битов, но тут уж почитайте сами. Я пакую биты в регистры, потому вполне хорошо себя чувствую даже с двумя функциями. Вот их и рассмотрим.
Чтение регистров — чтение непрерывного блока регистров с начального номера (адреса), указанное количество. Запрос:
Адрес
03 (код функции)
Начальный номер регистра (старший байт)
Начальный номер регистра (младший байт)
Количество регистров в блоке (старший байт)
Количество регистров в блоке (младший байт)
Контролька CRC, младший байт
Контролька CRC, старший байт

Ответ от Слейва:
Адрес
03 (код функции)
Количество байт — значений регистров (2N)
Значение регистра с начальным номером (старший байт)
Значение регистра с начальным номером (младший байт)

Значение последнего регистра (старший байт)
Значение последнего регистра (младший байт)
Контролька CRC, младший байт
Контролька CRC, старший байт

Несмотря на то, что количество регистров передается двумя байтами, допустимое значение этого параметра — от 1 до 125. Поэтому в ответе число байт 2N (которое вдвое больше числа регистров), передается одним байтом. Что-то они там недопили, когда придумывали эту команду…
Иллюстрация (здесь не показаны ни байт адреса. ни 2 байта контрольной суммы):

Читайте также:  Как сделать мостик для кота своими руками

Запись в регистры — симметрично команде 03. Тоже блок регистров.
Адрес
16 или 0х10 (код функции)
Начальный номер регистра (старший байт)
Начальный номер регистра (младший байт)
Количество регистров в блоке (старший байт)
Количество регистров в блоке (младший байт)
Количество байт — значений регистров (2N)
Значение регистра с начальным номером (старший байт)
Значение регистра с начальным номером (младший байт)

Значение последнего регистра (старший байт)
Значение последнего регистра (младший байт)
Контролька CRC, младший байт
Контролька CRC, старший байт

Ответ от Слейва:
Адрес
16 (код функции)
Начальный номер регистра (старший байт)
Начальный номер регистра (младший байт)
Количество регистров в блоке (старший байт)
Количество регистров в блоке (младший байт)
Контролька CRC, младший байт
Контролька CRC, старший байт

не знаю, с какого бодуна, но здесь максимальное число регистров — 123. Почему не одинаково с командой 03 — х.з.
Иллюстрация:

Вот и все. Вы знаете теперь достаточно об этом протоколе, чтобы рассмотреть программную реализацию работы Слейва.

Подытожу, рассматривая теперь процесс обмена с точки зрения работы Слейва:

— имеем на борту: буфер для размещения принятых и отправляемых фреймов. Его размер — максимум 256 байт. Если хотите работать с числом регистров, существенно меньшим 252, то можете и буфер ограничить. Все равно при приеме проверяем, не переполнился ли буфер;
— ждем первого символа (от Мастера) и по нему начинаем принимать фрейм. Как вариант — сразу фильтруем, наш ли адрес и можем не принимать все что дальше. Но ждать завершающий период тишины t3.5 все равно придется;
— каждый раз, когда символ принят, запускаем таймер для того, чтобы отловить событие: прошло уже t1.5 или t3.5;
— если возникло событие «прошло уже t1.5», а потом пришло начало следующего импульса — фиксируем печальный приговор: «Данный фрейм фтопку», но продолжаем принимать до конца, ибо что ж делать, конец-то должен быть, чтобы было новое начало 🙂
— если возникло событие «прошло уже t3.5», то заканчиваем принимать фрейм, разбираем его и наполняем (тот же) буфер ответом.
— забрасываем первый байт в буфер передатчика УАРТ, не забыв развернуть драйвер шины RS-485 на передачу;
— когда весь ответ выползет, развернем драйвер шины на прием. В принципе, теперь мы должны отстучать часиками тот же t3.5, но я ставлю программу на прием новых запросов сразу же. Все равно Мастер дождется паузы, потом рассмотрит ответ Слейва, а уж потом что-то может спрашивать.

Как все это реализовано у меня — расскажу во второй части. Сначала посмотрим, как вы покритикуете вступление, подправим все это дело, а к тому времени и программу опишу.

Источник

Оцените статью