Коды ошибок modbus. Просто о Modbus RTU с подробным описанием и примерами

16.03.2019

Статья посвящена промышленному протоколу ModBus — наиболее простому, а потому широко распространённому цифровому протоколу передачи данных.

Стандарт ModBus был изобретён ещё в 1979 году компанией Modicon (ныне Schneider Electric) и с того времени не утратил своей актуальности, а даже наоборот получил широкое распространение и большую популярность среди разработчиков АСУ ТП.

Преимущества и недостатки протокола ModBus

Преимущества:

  • прост в реализации
  • отсутствует необходимость установки специальных микросхем для реализации протокола при разработке контроллеров и устройств
  • простота диагностики и отладки
  • поддерживается большинством устройств, применяемых при построении АСУ ТП
  • высокая надёжность и достоверность при передаче данных

Недостатки:

  • ModBus сеть построена по принципу «ведущий-ведомый», где ведущее устройство может быть только одно. Поэтому обмен данными происходит только по инициативе ведущего устройства (оно по очереди опрашивает все ведомые). Если ведомому устройству нужно срочно передать данные, оно не может этого сделать, пока его не опросит «ведущий».

Общие сведения о ModBus сети

ModBus сеть объединяет одно ведущее (мастер) и несколько ведомых (слейвов). Обмен данными в сети происходит по инициативе мастера. Он может отправить запрос одному из подчинённых устройств или широковещательное сообщение сразу всем ведомым устройствам сети.

После отправки запроса мастер ожидает ответ в течение заданного времени («время таймаута»). Если в течение этого времени ответ не получен, мастер считает, что связь с ведомым отсутствует. На широковещательное сообщение ответ не предусмотрен.

Слейвы (ведомые устройства) не могут самостоятельно инициировать передачу данных. Они могут передать данные только после запроса мастера (и только те данные, которые мастер запросит).

Существует три разновидности протокола:

  • ModBus ASCII — разновидность протокола, в которой сообщения кодируются с помощью ASCII-символов. Сообщения разделяются символами «:» и CR/LF. Не очень удобен, в России используется крайне редко.
  • ModBus RTU — разновидность протокола, в которой сообщения кодируются «как есть» (числами). Между собой сообщения разделяются временной паузой в 3,5 символа при заданной скорости передачи.
  • ModBus TCP — разновидность протокола для работы поверх TCP/IP стека, требуется при соединении устройств по Ethernet.

Физический уровень протокола ModBus

Для передачи ModBus сообщений используется последовательные асинхронные интерфейсы (RS232, RS485, RS422) в случае использования протоколов ASCII и RTU и Ethernet интерфейс для протокола ModBus TCP.

Использование стандартных интерфейсов делает ModBus удобным для пользователей и разработчиков.

Типы данных ModBus

Любой узел сети ModBus — это интеллектуальное устройство (контроллер, регулятор, датчик и др.). Согласно спецификации узел сети может иметь следующие структуры данных:

  • Discrete Inputs — состояния дискретных входов устройства, их можно только прочитать. Однобитовый тип данных.
  • Coils — состояния дискретных выходов устройства, их можно прочитать и изменить (записать новое состояние). Однобитовый тип.
  • Input Registers — 16-битные регистры, доступные только для чтения.
  • Holding Registers — 16-битные регистры свободного назначения, доступны для чтения и записи.

Указанные типы данных необязательны для всех устройств, поддерживающих ModBus. Например, Discrete Inputs и Coils характерны больше для .

Производитель устройства сам решает, какой тип данных сделать доступным для чтения и записи по ModBus, и об этом написано в руководстве устройства. В большинстве случае пользуются типом Holding Registers, поскольку он самый универсальный.

Структура обмена данными по ModBus

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

Рис. Структура ModBus-пакета

Типовой запрос или ответ состоит из следующих блоков:

  • адрес подчинённого устройства
  • номер функции — определяет тип запрашиваемых данных и что с ними нужно сделать (прочитать/записать)
  • данные — содержит параметры функции («куда», «сколько» и «какие» данные записывать или читать)
  • блок контроля подлинности — содержит контрольную сумму для проверки целостности полученных данных.

Состав данных блоков отличается для RTU и TCP реализаций ModBus. Далее мы подробно рассотрим каждый из них.

ModBus ASCII мы не будем подробно рассматривать, поскольку он используется крайне редко. Состав пакета в ModBus ASCII такой же как и ModBus RTU, и отличается только типом кодирования и способом разделения пакетов.

Номер функции определяет тип запрашиваемых данных и что с ними нужно сделать (прочитать/записать).

Функций ModBus достаточно много и они разделены на три категории:

  • стандартные — функции, описанные в стандарте протокола. Среди них много устаревших и неиспользуемых.
  • пользовательские — диапазон номеров функций (с 65 по 72 и с 100 по 110), которые может использовать любой производитель устройств для реализации своих специфичных функций. При этом вполне возможно, что у устройств различных производителей под одинаковыми номерами будут разные по смыслу функции.
  • зарезервированные — функции, не описанные в базовом стандарте, но реализованные в устройствах различных производителей. При этом гарантируется, что данные производители зарезервировали эти номера для себя и другие производители не могут ими воспользоваться.

Однако, это всё лирика… На практике в большинстве случаев используются всего несколько функций, мы подробно поговорим о них в , а в этой будем рассматривать всё на примере функции Read Holding Registers (чтение регистров общего назначения).

Функция Read Holding Registers (0x03)

Функция под номером 3 — одна из самых употребимых функций, предназначена для чтения регистров общего назначения устройства.

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

Ответ содержит количество байт (количество регистров умноженное на 2) и значения запрошенных регистров.


Рис. Запрос от мастера

Рис. Ответ слейва

Количество байт в ответе помогает ведущему устройству по мере получения данных понять, когда все данные уже получены. То есть если мастер получил третий байт с числом 200 — это означает, что ему осталось получить еще 100 байт + 2 байта контроля целостности. Это позволит ему посчитать количество пришедших байт и закончить приём, не дожидаясь, когда закончится время таймаута, отведённое слейву на ответ.

Вместо нормального ответа, содержащего запрошенные данные, подчинённое устройство может ответить ошибкой. При этом к номеру функции в ответе добавляется код 0х80 в шестнадцатеричной системе исчисления.

Обратимся к предыдущему примеру. Там подчинённое устройство ответило без ошибки и второй байт в ответе был 0х03. Если бы ответ содержал код ошибки, то к номеру функции подчинённое устройство добавило бы 0х80 и получилось бы 0х83. Вот так:

Рис. Ответ слейва с признаком ошибки

В этом примере код ошибки 02 — это один из стандартных кодов. Вот какие они бывают:

01 — функция не поддерживается. Это значит, что, возможно, функция не стандартная или просто не реализована конкретно в этом устройстве.

02 — запрошенная область памяти не доступна. Каждое устройство содержит определённое количество данных определённого типа. Например, в устройстве доступно 100 регистров общего назначения. Если при этом запросить чтение 101 регистров — возникнет ошибка 02.

03 — функция не поддержит запрошенное количество данных. Например, функция №3 «Read Holding Registers» позволяет читать от 1 до 2000 регистров общего назначения. Поэтому, даже если в подчинённом устройстве доступно для чтения 10 000 регистров, при запросе более 2000 с помощью функции №3 — возникнет эта ошибка.

04 — функция выполнена с ошибкой. Такой код ошибки будет возвращён, если есть какое-то иное препятствие для нормального выполнения команды, не охваченное тремя предыдущими кодами ошибки. Проще говоря, это такая заглушка «на всякий случай», если что-то пошло не так, но в протоколе специального кода для такой ошибки не предусмотрено.

Нужно помнить, что существуют не только стандартные функции, но ещё и пользовательские и зарезервированные. Поэтому, производители устройств, которые дополнили протокол своими функциями, возможно заложили туда другие коды ошибок. Но это всё очень большая экзотика…

ModBus RTU

Как уже говорилось, в протоколе ModBus RTU данные передаются в виде сообщений, разделённых между собой временными паузами длиной в 3,5 символа при заданной скорости передачи.

В сообщении обязательно указывается адрес получателя (или 0, если сообщение широковещательное) и номер функции.Номер функции определяет какие данные содержит сообщение и как их интерпретировать.

За номером функции идут данные. Регистры данных в ModBus 32-битные, а передаются ввиде двух 16-битных сло. Сначала идёт старший байт, затем младший.

Пример. Допустим, мы хотим прочитать из удалённого модуля сбора данных 2 регистра, начиная с первого. Адрес удалённого модуля в сети ModBus «4». Для этого воспользуемся функцией №3 Read Holding Registers.


Рис. Запрос на чтение 2-х регистров, начиная с 1-го

Рис. Ответ от слейва на запрос

В ответе подчинённое устройство повторяет свой адрес и номер функции, далее следует количество полезных байт в ответе. Каждый регистр состоит из двух байт (сначала идёт старший, затем младший). Значение запрошенных регистров оказались равны 11 и 22 в десятичной системе исчисления (0B и 16 в шестнадцатеричной соответственно).

О том, как использовать другие ModBus функции мы выпустим отдельную статью.

Контроль целостности пакета в ModBus RTU (CRC-16)

В предыдущем примере за байтами данных идут два байта проверки целостности пакета. Они являются результатом вычисления кода CRC-16 для всего сообщения.

Мастер, передавая запрос, вычисляет CRC-код и добавляет его в конец сообщения. Слейв, получив сообщение, проверяет сообщение на целостность согласно алгоритму CRC-16. Затем подчинённое устройство составляет ответ, точно так же вычисляет для него CRC и добавляет в конец пакета.

Подробно рассматривать алгоритм CRC-16 мы не будем, т.к. мы стараемся быть ближе к практике… А на практике программисту практически никогда не приходится писать блок вычисления CRC — в любой среде программирования можно найти соответствующую функцию или функциональный блок.

Заключение

В данной статье мы рассмотрели общую структуру протокола ModBus и его классическую разновидность ModBus RTU. Вообще говоря, ModBus RTU — это и есть «истинный Modbus» (если отбросить ModBus ASCII, который уже устарел).

В мы поговорим о разновидности протокола ModBus TCP, который является «притягиванием за уши» классического ModBus с целью использования его в Ethernet-сетях, что, конечно же, накладывает определённые ограничения. Но об этом в следующей статье. Следите за обновлениями на LAZY SMART .

) для использования в её контроллерах с программируемой логикой . Впервые спецификация протокола была опубликована в 1979 году. Это был открытый стандарт, описывающий формат сообщений и способы их передачи в сети состоящей из различных электронных устройств.

Первоначально контроллеры MODICON использовали последовательный интерфейс RS-232. Позднее стал применяться интерфейс RS-485, так как он обеспечивает более высокую надёжность, позволяет использовать более длинные линии связи и подключать к одной линии несколько устройств.

Многие производители электронного оборудования поддержали стандарт, на рынке появились сотни использующих его изделий. В настоящее время развитием Modbus занимается некоммерческая организация Modbus-IDA , созданная производителями и пользователями электронных приборов .

Введение

Modbus относится к протоколам прикладного уровня сетевой модели OSI . Контроллеры на шине Modbus взаимодействуют, используя клиент-серверную модель, основанную на транзакциях , состоящих из запроса и ответа.

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

Спецификация Modbus описывает структуру запросов и ответов. Их основа - элементарный пакет протокола, так называемый PDU (Protocol Data Unit). Структура PDU не зависит от типа линии связи и включает в себя код функции и поле данных. Код функции кодируется однобайтовым полем и может принимать значения в диапазоне 1...127. Диапазон значений 128...255 зарезервирован для кодов ошибок. Поле данных может быть переменной длины. Размер пакета PDU ограничен 253 байтами.

Modbus PDU
номер функции данные
1 байт N < 253 (байт)

Для передачи пакета по физическим линиям связи PDU помещается в другой пакет, содержащий дополнительные поля. Этот пакет носит название ADU (Application Data Unit). Формат ADU зависит от типа линии связи.

Существуют три основных реализации протокола Modbus, две для передачи данных по последовательным линиям связи, как медным EIA/TIA-232-E (RS-232), EIA-422, EIA/TIA-485-A (RS-485), так и оптическим и радио:

  • Modbus ASCII,

и для передачи данных по сетям Ethernet поверх TCP/IP :

  • Modbus TCP.

Общая структура ADU следующая (в зависимости от реализации, некоторые из полей могут отсутствовать):

  • адрес ведомого устройства - адрес подчинённого устройства, к которому адресован запрос. Ведомые устройства отвечают только на запросы, поступившие в их адрес. Ответ также начинается с адреса отвечающего ведомого устройства, который может изменяться от 1 до 247. Адрес 0 используется для широковещательной передачи, его распознаёт каждое устройство, адреса в диапазоне 248...255 - зарезервированы;
  • номер функции - это следующее однобайтное поле кадра. Оно говорит ведомому устройству, какие данные или выполнение какого действия требует от него ведущее устройство;
  • данные - поле содержит информацию, необходимую ведомому устройству для выполнения заданной мастером функции или содержит данные, передаваемые ведомым устройством в ответ на запрос ведущего. Длина и формат поля зависит от номера функции;
  • блок обнаружения ошибок - контрольная сумма для проверки отсутствия ошибок в кадре.

Максимальный размер ADU для последовательных сетей RS232/RS485 - 256 байт, для сетей TCP - 260 байт.

Для Modbus TCP ADU выглядит следующим образом:

  • ид транзакции - два байта, обычно нули
  • ид протокола - два байта, нули
  • длина пакета - два байта, старший затем младший, длина следующей за этим полем части пакета
  • адрес ведомого устройства - адрес подчинённого устройства, к которому адресован запрос. Обычно игнорируется, если соединение установлено с конкретным устройством. Может использоваться, если соединение установлено с бриджом, который выводит нас, например, в сеть RS485.

Поле контрольной суммы в Modbus TCP отсутствует.

Категории кодов функций

В действующей в настоящее время спецификации протокола определяются три категории кодов функций:

Стандартные команды Их описание должно быть опубликовано и утверждено Modbus-IDA. Эта категория включает в себя как уже определенные, так и свободные в настоящее время коды. Пользовательские команды Два диапазона кодов (от 65 до 72 и от 100 до 110), для которых пользователь может реализовать произвольную функцию. При этом не гарантируется, что какое-то другое устройство не будет использовать тот же самый код для выполнения другой функции. Зарезервированные В эту категорию входят коды функций, не являющиеся стандартными, но уже используемые в устройствах, производимых различными компаниями. Это коды 9, 10, 13, 14, 41, 42, 90, 91, 125, 126 и 127.

Модель данных

Одно из типичных применений протокола - чтение и запись данных в регистры контроллеров. Спецификация протокола определяет четыре таблицы данных:

Доступ к элементам в каждой таблице осуществляется с помощью 16-битного адреса, первой ячейке соответствует адрес 0. Таким образом, каждая таблица может содержать до 65536 элементов. Спецификация не определяет, что физически должны представлять собой элементы таблиц и по каким внутренним адресам устройства они должны быть доступны. Например, допустимо организовать перекрывающиеся таблицы, В этом случае команды работающие с дискретными данными и с 16-битными регистрами будут фактически обращаться к одним и тем же данным.

Следует отметить, что со способом адресации данных связана определённая путаница. Modbus был первоначально разработан для контроллеров Modicon. В этих контроллерах для каждой из таблиц использовалась специальная нумерация. Например, первому регистру ввода соответствовал номер ячейки 30001, а первому регистру хранения - 40001. Таким образом, регистру хранения с адресом 107 в команде Modbus соответствовал регистр № 40108 контроллера. Хотя такое соответствие адресов больше не является частью стандарта, некоторые программные пакеты могут автоматически «корректировать» вводимые пользователем адреса, например, вычитая 40001 из адреса регистра хранения.

Стандартные функции протокола Modbus

PDU запроса и ответа для стандартных функций
номер
функции
запрос/ответ
1 (0x01) A 1 A 0 Q 1 Q 0
N D (N байт)
2 (0x02) A 1 A 0 Q 1 Q 0
N D (N байт)
3 (0x03) A 1 A 0 Q 1 Q 0
N D (N байт)
4 (0x04) A 1 A 0 Q 1 Q 0
N D (N байт)
5 (0x05) A 1 A 0 D 1 D 0
A 1 A 0 D 1 D 0
6 (0x06) A 1 A 0 D 1 D 0
A 1 A 0 D 1 D 0
15 (0x0F) A 1 A 0 Q 1 Q 0 N D (N байт)
A 1 A 0 Q 1 Q 0
16 (0x10) A 1 A 0 Q 1 Q 0 N D (N байт)
A 1 A 0 Q 1 Q 0
  • A 1 и A 0 - адрес элемента,
  • Q 1 и Q 0 - количество элементов,
  • N - количество байт данных
  • D - данные

Чтение данных

Для чтения значений из перечисленных выше таблиц данных используются функции с кодами 1-4 (шестнадцатеричные значения 0x01-0x04):

  • 1 (0x01) - чтение значений из нескольких регистров флагов (Read Coil Status)
  • 2 (0x02) - чтение значений из нескольких дискретных регистров (Read Discrete Inputs)
  • 3 (0x03) - чтение значений из нескольких регистров хранения (Read Holding Registers)
  • 4 (0x04) - чтение значений из нескольких регистров ввода (Read Input Registers)

Запрос состоит из адреса первого элемента таблицы, значение которого требуется прочитать, и количества считываемых элементов. Адрес и количество данных задаются 16-битными числами, старший байт каждого из них передается первым.

В ответе передаются запрошенные данные. Количество байт данных зависит от количества запрошенных элементов. Перед данными передается один байт, значение которого равно количеству байт данных.

Значения регистров хранения и регистров ввода передаются начиная с указанного адреса, по два байта на регистр, старший байт каждого регистра передаётся первым:

байт 1 байт 2 байт 3 байт 4 ... байт N-1 байт N
R A,1 R A,0 R A+1,1 R A+1,0 ... R A+Q-1,1 R A+Q-1,0

Значения флагов и дискретных входов передаются в упакованном виде: по одному биту на флаг. Единица означает включённое состояние, ноль - выключенное. Значения запрошенных флагов заполняют сначала первый байт, начиная с младшего бита, затем следующие байты, также от младшего бита к старшим. Младший бит первого байта данных содержит значение флага, указанного в поле «адрес». Если запрошено количество флагов, не кратное восьми, то значения лишних битов заполняются нулями:

байт 1 ... байт N
F A+7 F A+6 F A+5 F A+4 F A+3 F A+2 F A+1 F A ... 0 ... 0 F A+Q-1 F A+Q-2 ...

Запись одного значения

  • 5 (0x05) - запись значения одного флага (Force Single Coil)
  • 6 (0x06) - запись значения в один регистр хранения (Preset Single Register)

Команда состоит из адреса элемента (2 байта) и устанавливаемого значения (2 байта).

Для регистра хранения значение является просто 16-битным словом.

Для флагов значение 0xFF00 означает включённое состояние, 0x0000 - выключенное, другие значения недопустимы.

Если команда выполнена успешно, ведомое устройство возвращает копию запроса.

Запись нескольких значений

  • 15 (0x0F) - запись значений в несколько регистров флагов (Force Multiple Coils)
  • 16 (0x10) - запись значений в несколько регистров хранения (Preset Multiple Registers)

Команда состоит из адреса элемента, количества изменяемых элементов, количества передаваемых байт устанавливаемых значений и самих устанавливаемых значений. Данные упаковываются так же, как в командах чтения данных.

Ответ состоит из начального адреса и количества изменённых элементов.

Ниже приведён пример команды ведущего устройства и ответа ведомого (для Modbus RTU).

Контроль ошибок в протоколе Modbus RTU

Во время обмена данными могут возникать ошибки двух типов:

Ошибки первого типа обнаруживаются при помощи фреймов символов, контроля чётности и циклической контрольной суммы CRC -16-IBM (используется число-полином = 0xA001).

RTU фрейм

В RTU режиме сообщение должно начинаться и заканчиваться интервалом тишины - временем передачи не менее 3.5 символов при данной скорости в сети. Первым полем затем передаётся адрес устройства.

Вслед за последним передаваемым символом также следует интервал тишины продолжительностью не менее 3.5 символов. Новое сообщение может начинаться после этого интервала.

Фрейм сообщения передаётся непрерывно. Если интервал тишины продолжительностью 1.5 возник во время передачи фрейма, принимающее устройство должно игнорировать этот фрейм как неполный.

Таким образом, новое сообщение должно начинаться не раньше 3.5 интервала, т.к. в этом случае устанавливается ошибка.

Немного об интервалах (речь идёт о Serial Modbus RTU): при скорости 9600 и 11 битах в кадре (стартовый бит + 8 бит данных + бит контроля чётности + стоп-бит): 3.5 * 11 / 9600 = 0,00401041(6), т.е. более 4 мс; 1.5 * 11 / 9600 = 0,00171875, т.е. более 1 мс. Для скоростей более 19200 бод допускается использовать интервалы 1,75 и 0,75 мс соответственно.

Логические ошибки

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

1. Если Slave принимает корректный запрос и может его нормально обработать, то возвращает нормальный ответ.

2. Если Slave не принимает какого-либо значения, никакого ответа не отправляется. Master диагностирует ошибку по таймауту.

3. Если Slave принимает запрос, но обнаруживает ошибку (parity, LRC, or CRC), никакого ответа не отправляется. Master диагностирует ошибку по таймауту.

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

Таблица 2-1. Кадр ответа (Slave→Master) при возникновении ошибки modbus RTU
Направление передачи адрес подчинённого устройства номер функции данные (или код ошибки) CRC

В уроке 48 я показал пример нестандартного протокола обмена данными через интерфейс UART. Как всегда все нестандартное позволяет оптимизировать выполнение задачи, а все универсальное упрощает разработку задачи.

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

Общее описание протокола.

ModBus – открытый протокол обмена данными в малых локальных сетях. Как правило, используется для передачи данных через интерфейсы RS-232, RS-485, RS-422, в сетях TCP/IP, UDP. Благодаря своей простоте и универсальности ModBus получил широкое распространение и стал де факто стандартом в малых распределенных вычислительных системах. Практически все современные контроллеры поддерживают работу в сетях ModBus.

В сети ModBus контроллеры, как правило, соединены по топологии ”Общая шина”. Взаимодействие контроллеров происходит в соответствии с моделью master-slave (ведущий-ведомый).

В сети есть главное устройство - ведущее. А также несколько подчиненных устройств – ведомые. Обмен может быть инициирован только ведущим устройством.

Транзакция (последовательность операций при обмене данными) состоит из запроса и ответа.

Ведущее устройство может адресовать запрос любому ведомому контроллеру или инициировать широковещательное сообщение, для всех ведомых устройств одновременно.

Ведомое устройство, определив свой адрес в запросе, формирует ответ.

В запросе от ведущего устройства обязательно содержится код функции, т.е. что надо делать. Также в зависимости от функции в запросе могут содержаться данные.

Существуют 3 варианта протокола ModBus.

  • ModBus ASCII – текстовый протокол. В нем используются только ASCII символы. Каждый байт передается как два шестнадцатеричных символа.
  • ModBus RTU – числовой протокол. Данные передаются в двоичном виде. Байт, передаваемый по сети это число протокола.
  • ModBus TCP – протокол для передачи данных в TCP/IP сетях.

Числовые и текстовые протоколы я сравнивал еще в . По производительности и скорости обмена, безусловно, преимущество имеют числовые протоколы. Ближайшие уроки будем использовать ModBus RTU. Именно этому варианту посвящена последующая информация урока.

Протокол ModBus RTU.

В сети по топологии ”Общая шина” подключены устройства (контроллеры). Стандарт ModBus допускает совместную работу до 247 контроллеров.

В каждом контроллере есть данные, собственно говоря, которыми и обмениваются устройства.

Стандарт ModBus определяет 4 типа данных.

Тип данных Размер Допустимые операции
Регистр флагов (Coils) 1 бит Запись и чтение
Дискретные входы (Discrete Inputs) 1 бит Чтение
Регистры хранения (Holding Registers) 16 бит Запись и чтение
Регистры ввода (Input Registers) 16 бит Чтение

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

На практике используются только данные Регистры хранения (Holding Registers). Доступ к данным осуществляется через 16 битный адрес. В итоге:

  • данные в каждом контроллере представляют собой таблицу 16 битных регистров;
  • в таблице данных может быть до 65536 элементов;
  • нумерация элементов начинается с 0.

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

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

В общем случае кадр запроса имеет следующий формат.


Адрес (8 бит).

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

Адрес 0 используется в широковещательном режиме. Все ведомые устройства выполняют заданную в запросе функцию, но подтверждение не посылают.

Функция (8 бит).

Поле функции сообщает адресуемому ведомому устройству, какую операцию выполнить.

Старший бит байта функция устанавливается в 1 в ответе ведомого устройства, чтобы сообщить ведущему, что операция была выполнена с ошибкой. При успешной операции старший бит равен 0.

  • Стандартные команды. Коды, определенные стандартом на протокол ModBus.
  • Пользовательские команды. Для кодов 65…72 и 100…110 пользователь может сам назначить произвольную функцию.
  • Зарезервированные команды. Это коды, которые не были изначально определены стандартом, но уже используются в устройствах разных производителей.

Подавляющее большинство ModBus контроллеров используют только 3 функции.

Формат ответа зависит от функции. Во многих случаях нормальный ответ полностью или частично повторяет запрос.

Данные (N * 8 бит).

В поле данных содержится информация, необходимую ведомому контроллеру для выполнения заданной функции или поле содержит данные передаваемые ведомым устройством по запросу ведущего. Длина и формат поля данных зависит от кода функции. В некоторых сообщениях данные могут отсутствовать.

Каждое данное имеет 16 разрядов (2 байта). Данные передаются старшим байтом вперед. Например, последовательная передача регистров с адресами 0 и 1 должна происходить следующим образом:

  • старший байт регистра 0 ->
  • младший байт регистра 0 ->
  • старший байт регистра 1 ->
  • младший байт регистра 1 ->.

При передаче 4х байтового числа, например, с плавающей запятой последовательность та же. Число разбивается на два 16 разрядных регистра и в каждом из них первым передается старший байт (1-> 0-> 3-> 2->).

Контрольная сумма (16 бит).

Поле контроля целостности данных сообщений. Позволяет проверять кадры на наличие ошибок. Речь идет об ошибках, появляющихся при передаче данных.

Я постараюсь в общих чертах рассказать о контрольном коде. Лучше пропустить этот параграф. Может голова треснуть. У меня, когда я затрагиваю эту тему – всегда трещит. В следующем уроке я представлю практическую реализацию вычисления контрольного кода ModBus.

В качестве контрольной суммы используется циклический избыточный код (CRC). Все биты кадра передачи собираются в огромное двоичное число. Оно делится на код порождающего полинома. Остаток от деления и есть контрольный код.

Используется полиноминальная арифметика по модулю 2. Это означает, что все действия при вычислении CRC это арифметические операции без переноса. Вычитание и сложение происходят побитно, без учета переноса из-за чего эти операции дают одинаковый результат и могут быть заменены операцией ”исключающее или”. При делении вместо вычитания делителя из делимого также используется операция ”исключающее или”. Это общий принцип вычисления CRC. Практически вычисления производятся с помощью более эффективных алгоритмов.

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

Стандарт ModBus RTU использует стандартный циклический код CRC-16 с порождающим полиномом X 16 +X 15 +X 2 +1. Это 16ти разрядный код, двоичные коэффициенты 1 1000 0000 0000 0101 (8005h в шестнадцатеричном представлении).

Сообщение рассматривается как одно последовательное двоичное число, в котором старший бит передается первым. Это число умножается на X 16 (сдвиг влево на 16 разрядов), и делится на X 16 +X 15 +X 2 +1 (1 1000 0000 0000 0101). 16ти битный остаток (предварительно инициализированный всеми единицами) и есть контрольный код сообщения.

Обработка логических ошибок.

Кроме ошибок, связанных с искажением данных при передаче могут быть логические ошибки, когда запрос принят без ошибок, но не может быть выполнен. Как правило, такие ошибки связаны с недопустимым адресом, данными, кодами и т.п. Большинство ModBus контроллеров поддерживают следующие типы ошибок.

Код ошибки Название Описание
01 ILLEGAL FUNCTION Код функции не поддерживается в контроллере
02 ILLEGAL DATA ADRESS Недопустимый адрес данных
03 ILLEGAL DATA VALUE Недопустимые значения данных
04 SLAVE DEVICE FAILURE Произошла ошибка при выполнении операции

При возникновении ошибки в ответе в поле код функции взводится старший бит и следом вместо обычных данных передается код ошибки.

Детальное рассмотрение функций.

Функция 03 – чтение регистров хранения.

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

Запрошенные данные содержатся в ответе. Перед блоком данных передается байт, который содержит число прочитанных данных в байтах.

Формат запроса функции чтения регистров хранения.

Номер байта Номер байта в параметре Параметр
0 0 Адрес контроллера 01 01
1 0 Функция 03 03
2 1 Начальный адрес регистров 0008 00
3 0 08
4 1 Количество регистров 0002 00
5 0 02
6 1 Контрольная сумма 45C9 45
7 0 C9

Ответ (адрес ведомого, код функции, количество прочитанных байтов, значения регистров).

Номер байта Номер байта в параметре Параметр Пример чтения регистров с адресами 8 и 9
0 0 Адрес контроллера 01 01
1 0 Функция 03 03
2 0 Количество прочитанных байтов 04 04
3 1 Значение регистра 8 12A5 12
4 0 A5
5 1 Значение регистра 9 E020 E0
6 0 20
7 1 Контрольная сумма A770 A7
8 0 70

Функция 06 – запись в один регистр хранения.

Используется для записи в единичный регистр. В запросе передается адрес регистра и значение для него. При успешном выполнении ведомый контроллер в ответе передает копию запроса.

Формат запроса функции записи одного регистра хранения.

Номер байта Номер байта в параметре Параметр
0 0 Адрес контроллера 01 01
1 0 Функция 06 06
2 1 Адрес регистра 0009 00
3 0 09
4 1 Значение регистра 12A5 12
5 0 A5
6 1 Контрольная сумма 9513 95
7 0 13

Ответ (повторяет запрос).

Номер байта Номер байта в параметре Параметр Пример записи в регистр 9 значения 12A5
0 0 Адрес контроллера 01 01
1 0 Функция 06 06
2 1 Адрес регистра 0009 00
3 0 09
4 1 Значение регистра 12A5 12
5 0 A5
6 1 Контрольная сумма 9513 95
7 0 13

Функция 16 – запись значений в регистры хранения.

Используется для записи в несколько, последовательно расположенных в таблице, регистров.

В запросе передается адрес первого регистра, количество регистров и значения для них.

В ответе возвращается начальный адрес и количество измененных регистров.

Формат запроса функции записи регистров хранения.

Номер байта Номер байта в параметре Параметр
0 0 Адрес контроллера 01 01
1 0 Функция 10 10
2 1 Начальный адрес регистров 0008 00
3 0 08
4 1 Количество регистров 0002 00
5 0 02
6 0 Счетчик байтов 04 04
7 1 Значение регистра 8 12A5 12
8 0 A5
9 1 Значение регистра 9 E020 E0
10 0 20
11 1 Контрольная сумма AF4A AF
12 0 4A

Ответ (адрес ведомого, код функции, начальный адрес и количество регистров).

Номер байта Номер байта в параметре Параметр Пример записи регистров с адресами 8 и 9
0 0 Адрес контроллера 01 01
1 0 Функция 10 10
2 1 Начальный адрес регистров 0008 00
3 0 08
4 1 Количество регистров 0002 00
5 0 02
6 1 Контрольная сумма С00A C0
7 0 0A

ModBus и специализированные протоколы.

Теперь можете сравнить протокол ModBus со специализированном протоколом из .

Номер байта Формат числа Назначение
0 … 3 float Температура
4 … 7 float Напряжение
8 byte Состояние кнопки
9 byte Резерв
10, 11 int Контрольная сумма (сумма байтов 0 … 9 ^ 0xa1e3)

По сравнению со специализированным протоколом:

  • ModBus медленнее, его производительность ниже. Для получения такого же количества информации по сети передается намного больше данных.
  • Реализация его сложнее. Требуется больше ресурсов микроконтроллера и сети.

Но достоинства во многих случаях весомее.

  • За счет более сложной контрольной суммы и избыточности информации ошибки сети определяются в нем надежнее, выше достоверность данных.
  • Сеть легко расширяется. Очень просто добавлять новые устройства.
  • ModBus – стандартный протокол. Множество контроллеров различных производителей поддерживают его.

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

Правда, бывает еще один повод использовать нестандартный протокол. В том числе, благодаря которому наша фирма выиграла крупный тендер. Никто кроме разработчиков не сможет подключиться к устройствам со специализированным протоколом и управлять ими. Т.е. совершенно противоположное стандартным протоколам качество. Философский закон единства противоположностей действует.

В следующем уроке будем реализовывать связь платы Ардуино и компьютера по протоколу ModBus.

Рубрика: . Вы можете добавить в закладки.

Мы разобрали общую структуру протокола ModBus. Сегодня мы рассмотрим разновидность этого протокола — ModBus TCP, которая используется для реализации ModBus в сетях Ethernet.

ModBus TCP всегда работает поверх TCP/IP стека, поэтому не может считаться полноценным ModBus протоколом в его классическом виде.

Основное отличие, которое накладывает TCP/IP на ModBus при их совместном использовании — непосредственное подключение к определённому адресу. Протокол TCP/IP устроен по принципу «клиент-сервер». Для обмена данными клиент открывает сеанс связи с сервером, указывая его адрес.

Переходя на терминологию протокола ModBus ведущее устройство (мастер) в TCP-сети становится клиентом (т.к. именно клиент является инициатором обмена данными), а подчинённое устройство (слейв) — сервером.

Таким образом, для того чтобы передать запрос подчинённому устройству в TCP-сети мастер должен сначала открыть сеанс связи с ним. Причём открытие сеанса реализуется не на уровне протокола ModBus, а на уровне TCP/IP. Поэтому ведущее устройство не может средствами ModBus передавать запросы разным устройствам, так же, как это происходит в ModBus RTU или ASCII.

По этой же причине в ModBus TCP отсутствуют широковещательные сообщения (сразу всем подчинённым устройствам).

Однако, Master-устройство может подключаться к необходимому узлу (слейву) средствами протокола TCP/IP, а затем уже общаться с ним на языке ModBus.

На рисунке рабочее место диспетчера под управлением SCADA-системы является сервером сбора данных и одновременно мастером в сети ModBus TCP. Оно последовательно подключается к каждому удалённому контроллеру, открывая сеанс связи в сети TCP/IP и обменивается с ним ModBus-пакетами.

Безусловно, такой обмен происходит дольше, чем в случае ModBus RTU, т.к. дополнительное время уходит на открытие и закрытие сеанса TCP/IP. Однако, это даёт возможность объединить устройства находящиеся на значительном удалении витой парой или даже по WiFi.

Кроме того, протокол ModBus TCP может использоваться в сетях со шлюзом, где шлюз является интеллектуальным устройством и маршрутизирует сообщения остальным устройствам сети ModBus.

При такой конфигурации клиент сети TCP (он же мастер сети ModBus) подключается к шлюзу (серверу) и ведёт общение только с ним. Шлюз же переадресует сообщение внутри шины ModBus (RTU или ASCII) тому устройству, адрес которого указан в ModBus-пакете.

Структура пакета ModBus TCP

Сначала вспомним структуру классического ModBus-пакета (RTU или ASCII):

Он состоит из четырёх блоков: адрес слейва, номер функции, блок данных и блок контроля чётности.

А вот так выглядит структура пакета ModBus TCP:

Как вы можете видеть, в пакете ModBus TCP по сравнению с ModBus RTU добавлены блоки идентификаторов обмена и протокола, а так же от отсутствует блок контроля подлинности пакета. Последнее объясняется тем, что контроль целостности пакета обеспечивается средствами протокола TCP/IP, поэтому отпадает необходимость в его ModBus-реализации.

Рассмотрим что означает каждый из блоков пакета ModBus TCP:

  • id обмена — чаще всего два нуля. Применяется только в том случае, если мастер отсылает подчинённому устройству несколько запросов подряд без ожидания ответа. При этом id позволяет затем понять какому из запросов какой ответ соответствует.
  • id протокола — всегда нули, не применяется. Поле оставлено в качестве резерва для будующих применений.
  • длина пакета — совокупная длина блоков «адрес», «номер функции» и «данные». Длина пакета передаётся двумя байтами, первым из которых идет старший.
  • адрес ведомого устройства — аналог такого же блока в структуре пакета ModBus RTU, но обычно не используется, т.к. ,как уже говорилось, в ModBus TCP мастер и так открывает сеанс обмена только с одним слейвом (у которого, конечно, есть и IP адрес в сети TCP/IP). Данное поле используется только в варианте ModBus TCP-сети со шлюзом. Тогда шлюз сам перенаправляет пакет по указанному адресу.
  • поля код функции и данные аналогичны соответствующим полям в классическом ModBus-пакете.

Пришло время рассмотреть еще одну вариацию протокола Modbus Modbus ASCII . Эта версия протокола использует для передачи данных только символы ASCII, которыми кодирует шестнадцатеричное представление бинарных данных. Немного не понятно и запутано? Это ничего, welcome под кат и давайте рассмотрим, с чем же мы имеем дело.

Разделитель пакетов

Первое отличие протокола Modbus ASCII от Modbus RTU – у него есть разделитель между пакетами. Если в Modbus RTU все пакеты шли один за одним (практически, там должна быть небольшая задержка на линии между пакетами, порядка 2-5мс), то в Modbus ASCII каждый новый пакет должен начинаться со специального символа разделителя.

По стандарту Modbus RTU между пакетами нужна задержка в 3.5 символа (это время, которое нужно для передачи 3.5 символов по линии связи, зависит от скорости передачи). Эта задержка используется, что бы детектировать новый запрос от мастера. Т.е. эта задержка указывает начало нового запроса. Но когда стали использовать модемы, это перестало работать. На модеме невозможно выдержать нужное время. Поэтому решили использовать новый вариант протокола — Modbus ASCII . Этот вариант устраняет многие неудобства при работе с модемом: есть специальный символ разделитель пакетов и используются только видимые символы ASCII.

Так вот, таким символом начала пакета служит символ двоеточие с шестнадцатеричным кодом 0x3A . А конец каждого пакета помечается символами новой строки и перевода каретки – 0x0D 0x0A . Таким образом, из протокола полностью убирается зависимость от задержек между байтами. Т.е. если модем задержит байт, это не вызовет недопонимания на стороне клиента. И он будет ждать окончания пакета байтами 0x0D 0x0A . А если встретит символ разделителя 0х3А – сбросит буфер и начнем формировать пакет заново. Кроме того нет необходимости в экранировании спец символов модема, так как данные не используют символы из начальной секции ASCII таблицы.

Представление байтов данных

В Modbus ASCII протоколе каждый байт данных представлен в виде 2 байтов. Каждый байт представляет собой ASCII символ в шестнадцатеричном представлении. Что бы легче было понять, приведем пример:

Немного объяснений для таблицы.

Например, нам нужно передать байт данных, который хранит символ # . Этот символ имеет в таблице ASCII шестнадцатеричный код 0x23 . В протоколе Modbus RTU мы просто передаем байт со значением 0x23 .

Если мы хоти передать тот же символ через протокол Modbus ASCII , нам нужно уже передавать 2 байта. На первом этапе мы получаем шестнадцатеричный код символа, 0x23 . На втором этапе мы кодируем это значение при помощи двух символов ASCII – 2 и 3 . И на третьем этапе мы передаем два байта данных, первый — это шестнадцатеричное значение символа 2 , второй байт — это шестнадцатеричное значение символа 3 .

Таким образом, диапазон значений для байта данных в протоколе Modbus RTU 0 .. 0xFF

Диапазон значений для байта данных в протоколе Modbus ASCII – только символы, необходимые для отображения шестнадцатеричных цифр, т.е. 0 – 9, A, B, C, D, E, F (все заглавные).

Контрольная сумма для Modbus ASCII

В протоколе Modbus RTU используется 2 байтная контрольная сумма, которая помогает детектировать поврежденные запросы. В протоколе Modbus ASCII так же есть контрольная сумма – LRC (Longitudinal Redundancy Check) .

Вычисление LRC намного проще, чем вычисление CRC . Что бы высчитать LRC вам нужно сделать следующие:

  • Сложить вместе все байты в сообщении Modbus ASCII , до того, как они сконвертированы в в символы ASCII. Не включаются в вычисления стартовый символ двоеточия и завершающие символы CR/LF .
  • Обнулить все биты больше 8 (т.е. оставить младший байт)
  • Сделать результирующий байт отрицательным чтобы получить LRC байт

Таким образом, если затем сложить все байты пакета данных и байт LRC мы получим в результате 0. Это и есть самая быстрая проверка корректности пакета данных.

Ниже приведен пример вычисления LRC для конкретного запроса Modbus ASCII .

Для примера возьмем запрос на чтение регистров #40108 — #40110 с устройства с адресом 17

Запрос: 11 03 00 6B 00 03
Данные (Десятичные) Данные (HEX) Данные (Двоичные)
17 11 0001 0001
3 03 0000 0011
0 00 0000 0000
107 6B 0110 1011
0 00 0000 0000
3 03 0000 0011

Теперь посчитаем сумму всех байт

Вот это отрицательное число (-130 или 0x7E ) и есть LRC запроса.

Эта контрольная сумма добавляется к запросу в виде 2 ASCII символов7 и E .

Т.е. в конце запроса нужно добавить 2 байта со значением 37 и 45 .

Примеры Modbus RTU и Modbus ASCII запросов

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

Возьмем наш запрос на чтение регистров #40108 — #40110 с устройства с адресом 17

Запрос: 11 03 00 6B 00 03

Это Modbus RTU запрос без последних двух байтов CRC . Теперь преобразуем этот запрос из Modbus RTU в Modbus ASCII . Для этого добавляем в начало запроса символ двоеточия, в конец запроса символ перевода строки и возврата каретки, а каждый байт представим в виде ASCII символов, соответствующих шестнадцатеричному представлению каждого байта запроса. В итоге у нас получиться такой запрос (в виде ASCII символов, или попросту в виде текстовой строки). Так же в конец запроса добавляем LRC .

: 1 1 0 3 0 0 6 B 0 0 0 3 7 E CR LF

Теперь просто нужно передать данный запрос в порт, используя коды ASCII символов. В бинарном виде запрос будет выглядеть так:

3A 3131 3033 3030 3642 3030 3033 3745 0D 0A
Индекс байта Значение HEX ASCII Описание
0 3A : Символ начала
1-2 31 31 11 Адрес устройства
3-4 30 33 03 Код команды
5-8 30 30 36 42 00 6B Адрес HOLDING регистра, с которого нужно начинать чтение. В данном случае 0х006B = 107. Но это не адрес, а смещение от адреса 40001. Т.е. реальный адрес = 107+ 40001 = 40108.
9-12 30 30 30 33 00 03 Количество регистров, которые нужно прочитать. 0х0003 = 3. Т.е. читать нужно регистры 40108– 40110.
13 – 14 37 45 7E LRC запроса
15 CR 0D Символ перевода каретки
16 LF 0A Символ новой строки