Работа с протоколом Modbus RTU/ASCI по шине RS485
Описание протокола Modbus:
Перед тем как приступить к описанию протокола, давайте разберёмся с терминами.
Шина – канал связи, служащий для передачи данных, используя предписанные электрические (физические) и логические (управляющие) уровни.
Шина это нечно физическое (дорожки на плате, провода, шлейфы и т.д.). Шина определяет граничные значения скорости, максимальную дальность, напряжения логических уровней, допустимые емкости между линиями, форму сигналов на линиях и т.д.
Протокол – набор правил и действий (очерёдности действий), позволяющий осуществлять соединение и обмен данными.
Протокол это правила по которым осуществляется передача данных. Данные между двумя устройствами передаются по шине в соответствии с протоколом.
Интерфейс – совокупность средств и правил, обеспечивающих логическое и физическое взаимодействие устройств и (или) программ системы.
Интерфейс это шина + протокол + устройство или программа отвечающая за передачу данных.
Протокол Modbus – коммуникационный протокол, основанный на архитектуре ведущий-ведомый.
Протокол Modbus разработан для шин: RS-485, RS-422, RS-232, и интерфейса Ethernet сети TCP/IP, но при желании его можно использовать для связи и по другим шинам или даже радиоканалам.
Протокол Modbus предусматривает наличие одного ведущего и до 247 ведомых устройств. Количество ведомых устройств может быть ограничено физическими возможностями шины.
Для ведущего устройства (master) в протоколе Modbus используется термин — client. Для ведомого устройства (slave) в протоколе Modbus используется термин — server. Да, это не опечатка, ведущий – клиент, ведомый – сервер. Думаю не будет ошибкой, если далее в статье мы будем пользоваться более привычными терминами: ведущий (master), ведомый (slave).
В соответствии с протоколом Modbus связь всегда начинает мастер, а ведомые устройства могут только отвечать на запросы мастера. Связь осуществляется посылкой пакета запроса (от мастера к ведомому) и посылкой ответного пакета (от ведомого к мастеру).
Типы протоколов Modbus:
- Modbus RTU:
Данные передаются в двоичном формате, разделителем пакетов служит отсутствие данных в течении времени при котором можно передать более 3,5 байт.
Протокол предназначен для шин: RS-485, RS-422, RS-232. - Modbus ASCII:
Данные передаются символами из таблицы ASCII в шестнадцатеричном формате, разделителями пакетов служат символы начала и конца пакета.
Каждый пакет начинается символом двоеточия, в кодировке ASCII и заканчивается символами возврата каретки ‘\r’, и переноса строки ‘\n’.
Например, для передачи адреса 10 в протоколе Modbus RTU будет передан байт 0x0A, а в протоколе Modbus ASCII будет передан байт символа ‘0’ и байт символа ‘A’, в кодировке ASCII.
Протокол предназначен для шин: RS-485, RS-422, RS-232. - Modbus TCP:
Данные передаются в двоичном формате и упаковываются в обычный TCP-пакет, для передачи по IP-сетям. Отличием данного протокола является отсутствие проверки целостности (CRC-16), так как TCP уже имеет собственный механизм контроля целостности.
Протокол предназначен для сетей TCP/IP.
Состав пакета Modbus RTU:
Состав пакета запроса от мастера к ведомому, аналогичен составу ответного пакета ведомого.
ADU (до 256 байт) | |||
АДРЕС (1 байт) | PDU (до 253 байт) | CRC-16 (2 байта) | |
КОМАНДА (1 байт) | ДАННЫЕ (до 252 байт) количество байт зависит от команды | ||
0. 247 | 1. 127 | 0. 65535 |
- ADU (Application Data Unit) – пакет Modbus целиком.
- PDU (Protocol Data Unit) – основная часть пакета, состоит из команды и данных.
- АДРЕС – адрес ведомого устройства которому адресован пакет запроса, или от которого отправлен пакет ответа. Ведомые устройства могут иметь адреса от 1 до 247. Пакет запроса отправленный с адресом 0 является широковещательным, он адресован всем ведомым на шине, они обязаны выполнить запрос, но не должны на него отвечать.
- КОМАНДА – указывает какие действия должен выполнить ведомый. Команда в запросе может иметь значение от 1 до 127. Этот диапазон соответствует байту у которого сброшен старший бит. Если ведомый выполнил запрос мастера, то в ответном пакете он указывает тот же номер команды, без изменений. Если ведомый обнаружил ошибку в запросе, или не может его выполнить, то в ответном пакете он указывает номер команды с установленным старшим битом. То есть номер команды будет лежать в диапазоне от 129 до 255.
- ДАННЫЕ – состав и количество данных в запросе и ответе зависят от номера команды. Если ведомый обнаружил ошибку в запросе, или не может его выполнить, то в ответном пакете, в поле данных, он указывает код ошибки.
- CRC-16 – проверка целостности пакета, два байта передаются младшим байтом вперёд.
Для протокола Modbus значение CRC-16 рассчитывается используя реверсивный сдвиг, начальное значение равно 0xFFFF, порождающий полином равен 0xA001.
Регистры ведомых устройств:
Данные ведомых устройств хранятся в регистрах. Существует 4 типа регистров:
Адрес: | Название: | Назначение: | |||
---|---|---|---|---|---|
0. 0x270E | (DI) | Discrete Input | 1 бит | Цифровые входы | R |
0. 0x270E | (DO) | Discrete Output Coils | 1 бит | Цифровые выходы (регистры флагов) | RW |
0. 0x270E | (AI) | Analog Input Registers | 16 бит | Аналоговые входы | R |
0. 0x270E | (AO) | Analog Output Holding Registers | 16 бит | Аналоговые выходы (регистры хранения) | RW |
Данные в регистрах не обязательно связаны со значениями на входах и выходах ведомых устройств. Каждый регистр DI/DO хранит 1 бит. Каждый регистр AI/AO хранит 16 бит (2 байта).
Например, регистры AI и AO могут хранить входные данные и результаты вычислений, а регистры DI и DO флаги настроек, и биты состояний.
Команды протокола Modbus:
Номер: | Название: | Назначение: | |
---|---|---|---|
hex | dec | ||
0x01 | 1 | Read Coil Status | Чтение значений из нескольких регистров «DO» |
0x02 | 2 | Read Discrete Inputs. | Чтение значений из нескольких регистров «DI». |
0x03 | 3 | Read Holding Registers. | Чтение значений из нескольких регистров «AO». |
0x04 | 4 | Read Input Registers. | Чтение значений из нескольких регистров «AI». |
0x05 | 5 | Force Single Coil. | Запись значения в один регистр «DO». |
0x06 | 6 | Preset Single Register. | Запись значения в один регистр «AO». |
0x07 | 7 | Read Exception Status. | Чтение сигналов состояния статусных выходов. |
0x08 | 8 | Diagnostic. | Диагностика. |
0x09 | 9 | — — | Команда не стандартизирована, но уже используется в различных устройствах. |
0x0A | 10 | ||
0x0B | 11 | Get Com Event Counter. | Чтение счетчика событий. |
0x0C | 12 | Get Com Event Log. | Чтение журнала событий. |
0x0D | 13 | — — | Команда не стандартизирована, но уже используется в различных устройствах. |
0x0E | 14 | ||
0x0F | 15 | Force Multiple Coils. | Запись значений в несколько регистров «DO». |
0x10 | 16 | Preset Multiple Registers. | Запись значений в несколько регистров «AO». |
0x11 | 17 | Report Slave ID. | Чтение информации об устройстве. |
0x12 | 18 | — — | — — |
0x13 | 19 | ||
0x14 | 20 | Read File Record. | Чтение из файла. |
0x15 | 21 | Write File Record. | Запись в файл. |
0x16 | 22 | Mask Write Register. | Запись значения в регистр «AO» с масками И и ИЛИ. |
0x17 | 23 | Read/Write Multiple Registers. | Чтение и запись нескольких регистров «AO». |
0x18 | 24 | Read FIFO Queue. | Чтение данных из буфера FIFO. |
Все перечисленные команды (кроме работы с файлами и буфером FIFO) реализованы в библиотеке iarduino_Modbus.
Библиотека iarduino_Modbus:
Библиотека iarduino_Modbus позволяет работать с устройствами по шине RS485 используя протокол Modbus RTU или Modbus ASCII. Так как у большинства плат Arduino и ESP нет шины RS485, библиотека использует аппаратную или программную шину UART. Сигналы шины UART необходимо преобразовать в сигналы шины RS485 при помощи конвертирующего модуля UART-RS485, например, на базе микросхемы на MAX485.
Конвертер подключается к выводам TX и RX шины UART, а так же назначается вывод разрешающий работу передатчика DE.
Подключение к шине RS485:
- Для подключения конвертера к микроконтроллеру используется вывод DE и выводы UART.
- TX — вывод шины UART микроконтроллера для передачи данных к конвертеру.
- RX — вывод шины UART микроконтроллера для получения данных от конвертера.
- DI — вывод шины UART конвертера для получения данных от микроконтроллера.
- RO — вывод шины UART конвертера для передачи данных к микроконтроллеру.
- DE — вывод конвертера разрешающий работу его передатчика на шине RS485.
RE — вывод конвертера разрешающий работу его приёмника на шине RS485.
- A, B — витая пара для передачи/приёма данных.
- GND — линия шины RS485 для выравнивания потенциалов.
Подключение к программной шине Piranha UNO:
Вместо выводов 2, 8 и 9 платы Piranha UNO можно использовать любые выводы, указав их номера в скетче.
Подключение к аппаратной шине Piranha ULTRA:
В примере используется аппаратная шина UART1 использующая выводы 8 и 9. Вместо вывода 2 можно использовать любой вывод платы Piranha ULTRA, указав его номер в скетче.
Подключение к аппаратной шине Piranha ESP32:
В примере используется аппаратная шина UART2 работающая на выводах 16 и 17. Вместо вывода 22 можно использовать любой вывод платы Piranha ESP32, указав его номер в скетче.
Описание функций библиотеки:
В данном разделе описаны функции библиотеки iarduino_Modbus для работы с шиной RS485 по протоколу Modbus.
Синтаксис функций библиотеки iarduino_Modbus совместим с библиотекой ArduinoModbus.
Подключение библиотеки:
В примерах вход DE конвертера подключён к выводу D2 Arduino. Вместо вывода D2 можно использовать любой выход Arduino.
- Если используется аппаратная шина UART:
Если используется аппаратная шина UART-1, то вместо класса Serial указываем Serial1, для шины UART2 указываем Serial2 и т.д.
- Если используется программная реализация шины UART:
Для программной реализации шины UART необходимо указать выводы которые будут использоваться как RX и TX, в примере указаны выводы 8, и 9 соответственно. При создании объекта modbus указывается не класс Serial, а объект для работы с программной шиной UART.
- Если используются две и более шины:
В примере созданы два объекта для работы по двум аппаратным шинам UART. Количество создаваемых объектов ограничено количеством шин и памятью микроконтроллера. Можно добавить еще и программную шину, подключив библиотеку SoftwareSerial как в примере выше.
Скорость передачи данных по шине Modbus равна скорости шины UART.
Функция begin();
- Назначение: Инициализация работы по протоколу Modbus.
- Синтаксис: begin();
- Параметры: Нет.
- Возвращаемое значение: Нет.
- Примечание:
- Протокол будет инициирован на той шине UART, которая указана при создании объекта.
- Функцию достаточно вызвать 1 раз в коде Setup(), до обращения к остальным функциям библиотеки.
- Пример:
Функция setTypeMB();
- Назначение: Указание типа протокола Modbus.
- Синтаксис: setTypeMB( ТИП );
- Параметр: ТИП — может принимать значение MODBUS_RTU или MODBUS_ASCII.
- Возвращаемое значение: Нет.
- Примечание: Тип протокола по умолчанию MODBUS_RTU.
- Пример:
Функция setTimeout();
- Назначение: Указание максимального времени ожидания ответа от ведомых устройств.
- Синтаксис: setTimeout( ВРЕМЯ );
- Параметр: ВРЕМЯ uint32_t — количество миллисекунд.
- Возвращаемое значение: Нет.
- Примечание:
- Максимальное время ожидания устанавливается, как для типа RTU, так и для ASCII.
- Максимальное время ожидания по умолчанию 10 мс.
- Библиотека не ждёт завершение времени ожидания, если модуль ответил раньше.
- Пример:
Функция setDelay();
- Назначение: Указание паузы до отправки сообщения.
- Синтаксис: setDelay( ВРЕМЯ );
- Параметр: ВРЕМЯ uint32_t — количество миллисекунд.
- Возвращаемое значение: Нет.
- Примечание:
- Пауза до отправки сообщения устанавливается только для протокола Modbus RTU.
- Пауза до отправки сообщения по умолчанию 3 мс.
- Пауза устанавливается между пакетами. Если после получения/отправки последнего пакета прошло больше времени, то новый пакет будет отправлен без паузы.
- Пример:
Функция coilRead();
- Назначение: Чтение одного регистра «Coil» (он же «Discrete Output»).
- Синтаксис: coilRead( [ АДРЕС_МОДУЛЯ ] , АДРЕС_РЕГИСТРА );
- Параметры:
- АДРЕС_МОДУЛЯ: uint8_t — значение от 1 до 247.
- АДРЕС_РЕГИСТРА: uint16_t — значение от 0 до 9999.
- Возвращаемое значение: int8_t — прочитанное значение (0/1), или -1 при неудаче.
- Примечание: Если адрес модуля не указан, команда будет отправлена всем устройствам.
- Пример без проверки чтения:
- Пример с проверкой:
Функция discreteInputRead();
- Назначение: Чтение одного регистра «Discrete Input».
- Синтаксис: discreteInputRead( [ АДРЕС_МОДУЛЯ ] , АДРЕС_РЕГИСТРА );
- Параметры:
- АДРЕС_МОДУЛЯ: uint8_t — значение от 1 до 247.
- АДРЕС_РЕГИСТРА: uint16_t — значение от 0 до 9999.
- Возвращаемое значение: int8_t — прочитанное значение (0/1), или -1 при неудаче.
- Примечание: Если адрес модуля не указан, команда будет отправлена всем устройствам.
- Пример без проверки чтения:
- Пример с проверкой:
Функция holdingRegisterRead();
- Назначение: Чтение одного регистра «Holding Register» (он же «Analog Output»).
- Синтаксис: holdingRegisterRead( [ АДРЕС_МОДУЛЯ ] , АДРЕС_РЕГИСТРА );
- Параметры:
- АДРЕС_МОДУЛЯ: uint8_t — значение от 1 до 247.
- АДРЕС_РЕГИСТРА: uint16_t — значение от 0 до 9999.
- Возвращаемое значение: int32_t — прочитанное значение (0. 65535), или -1 при неудаче.
- Примечание: Если адрес модуля не указан, команда будет отправлена всем устройствам.
- Пример без проверки чтения:
- Пример с проверкой:
Функция inputRegisterRead();
- Назначение: Чтение одного регистра «Input Register» (он же «Analog Input»).
- Синтаксис: inputRegisterRead( [ АДРЕС_МОДУЛЯ ] , АДРЕС_РЕГИСТРА );
- Параметры:
- АДРЕС_МОДУЛЯ: uint8_t — значение от 1 до 247.
- АДРЕС_РЕГИСТРА: uint16_t — значение от 0 до 9999.
- Возвращаемое значение: int32_t — прочитанное значение (0. 65535), или -1 при неудаче.
- Примечание: Если адрес модуля не указан, команда будет отправлена всем устройствам.
- Пример без проверки чтения:
- Пример с проверкой:
Функция coilWrite();
- Назначение: Запись в один регистр «Coil» (он же «Discrete Output»).
- Синтаксис: coilWrite( [ АДРЕС_МОДУЛЯ ] , АДРЕС_РЕГИСТРА , ДАННЫЕ );
- Параметры:
- АДРЕС_МОДУЛЯ: uint8_t — значение от 1 до 247.
- АДРЕС_РЕГИСТРА: uint16_t — значение от 0 до 9999.
- ДАННЫЕ: bool — значение для записи 0 или 1.
- Возвращаемое значение: bool — результат записи значения в регистр (true или false).
- Примечание: Если адрес модуля не указан, команда будет отправлена всем устройствам.
- Пример без проверки записи:
- Пример с проверкой:
Функция holdingRegisterWrite();
- Назначение: Запись в один регистр «Holding Register» (он же «Analog Output»).
- Синтаксис: holdingRegisterWrite( [ АДРЕС_МОДУЛЯ ] , АДРЕС_РЕГИСТРА , ДАННЫЕ );
- Параметры:
- АДРЕС_МОДУЛЯ: uint8_t — значение от 1 до 247.
- АДРЕС_РЕГИСТРА: uint16_t — значение от 0 до 9999.
- ДАННЫЕ: uint16_t — значение для записи от 0 до 65535.
- Возвращаемое значение: bool — результат записи значения в регистр (true или false).
- Примечание: Если адрес модуля не указан, команда будет отправлена всем устройствам.
- Пример без проверки записи:
- Пример с проверкой:
Функция registerMaskWrite();
- Назначение: Запись масок в один регистр «Holding Register» (он же «Analog Output»).
- Синтаксис: registerMaskWrite( [ АДРЕС_МОДУЛЯ ] , АДРЕС_РЕГИСТРА , AND , OR );
- Параметры:
- АДРЕС_МОДУЛЯ: uint8_t — значение от 1 до 247.
- АДРЕС_РЕГИСТРА: uint16_t — значение от 0 до 9999.
- AND: uint16_t — значение маски AND от 0 до 65535.
- OR: uint16_t — значение маски OR от 0 до 65535.
- Возвращаемое значение: bool — результат записи масок в регистр (true или false).
- Примечание:
- Если адрес модуля не указан, команда будет отправлена всем устройствам.
- Результат записи вычисляется по формуле: REG = ( REG & AND ) | ( OR &
AND ).
- Каждый бит маски AND запрещает менять значение того же бита в регистре.
- Маска OR содержит биты для записи в регистр, если это не запрещено маской AND.
- Пример:
- Допустим сейчас значение регистра = ( 0101 0101 0101 0101 )2.
- Если маска AND = ( 0000 0000 1111 1111 )2, то она запрещает менять 8 младших битов.
- Для маски OR возьмем значение = ( 0111 0111 0111 0111 )2.
- После записи, значение регистра будет = ( 0111 0111 0101 0101 )2.
- 8 старших битов взяли значение из OR, а 8 младших остались без изменений.
- Так можно менять отдельные биты, без предварительного чтения регистра.
- Пример без проверки записи:
- Пример с проверкой:
Функция beginTransmission();
- Назначение: Инициализация записи в несколько регистров «Coils» или «Holding Registers».
- Синтаксис: beginTransmission( [ АДРЕС_МОДУЛЯ ], ТИП, АДРЕС_РЕГИСТРА, КОЛИЧЕСТВО);
- Параметры:
- АДРЕС_МОДУЛЯ: uint8_t — значение от 1 до 247.
- ТИП — может принимать значение COILS или HOLDING_REGISTERS.
- АДРЕС_РЕГИСТРА: uint16_t — адрес первого регистра для записи от 0 до 9999.
- КОЛИЧЕСТВО: uint16_t — количество записываемых регистров.
- Возвращаемое значение: bool — результат инициализации записи (true или false).
- Примечание:
- Если адрес модуля не указан, команда будет отправлена всем устройствам.
- Если задан некорректный диапазон адресов регистров, не будет записан ни один регистр.
- Данные для записи необходимо ставить в очередь функцией write().
- Запись данных поставленных в очередь осуществляется функцией endTransmission().
- Пример для функций beginTransmission(), write() и endTransmission(), указан ниже.
Функция write();
- Назначение: Постановка значения в очередь на запись, после beginTransmission().
- Синтаксис: write( ДАННЫЕ );
- Параметр: ДАННЫЕ uint16_t — значение 0/1 для «Coils», или 0. 65535 для «Holding Registers».
- Возвращаемое значение: bool — результат постановки значения в очередь (true или false).
- Пример для функций beginTransmission(), write() и endTransmission(), указан ниже.
Функция endTransmission();
- Назначение: Выполнение инициированной ранее записи.
- Синтаксис: endTransmission();
- Параметр: Нет.
- Возвращаемое значение: bool — результат записи (true или false).
- Пример без проверки записи:
- Пример с проверкой:
Функция requestFrom();
- Назначение: Чтение из нескольких регистров указанного типа.
- Синтаксис: requestFrom( [ АДРЕС_МОДУЛЯ ], ТИП, АДРЕС_РЕГИСТРА, КОЛИЧЕСТВО);
- Параметры:
- АДРЕС_МОДУЛЯ: uint8_t — значение от 1 до 247.
- ТИП: COILS, или DISCRETE_INPUTS, или HOLDING_REGISTERS, или INPUT_REGISTERS.
- АДРЕС_РЕГИСТРА: uint16_t — адрес первого читаемого регистра от 0 до 9999.
- КОЛИЧЕСТВО: uint16_t — количество читаемых регистров.
- Возвращаемое значение: uint16_t — количество прочитанных регистров, или 0 при неудаче.
- Примечание:
- Если адрес модуля не указан, команда будет отправлена всем устройствам.
- Если задан некорректный диапазон адресов регистров, не будет прочитан ни один регистр.
- Для получения прочитанных данных нужно обращаться к функции read().
- Количество оставшихся доступных данных можно узнать функцией available().
- Пример для функций requestFrom(), available() и read(), указан ниже.
Функция available();
- Назначение: Получение количества значений, доступных для чтения функцией read().
- Синтаксис: available();
- Параметры: Нет.
- Возвращаемое значение: uint16_t — количество значений доступных для чтения read().
- Примечание: При обращении к любой функции библиотеки кроме available() и read(), буфер доступных значений будет очищен или перезаписан.
- Пример для функций requestFrom(), available() и read(), указан ниже.
Функция read();
- Назначение: Получение очередного прочитанного значения.
- Синтаксис: read();
- Параметры: Нет.
- Возвращаемое значение: int32_t — очередное прочитанное значение, или -1 при неудаче.
- Примечание: При обращении к любой функции библиотеки кроме available() и read(), буфер доступных значений будет очищен или перезаписан.
- Пример без проверки чтения:
- Пример с проверкой:
Функция end();
- Назначение: Функция для совместимости с библиотекой ArduinoModbus.
- Синтаксис: end();
- Параметры: Нет
- Возвращаемое значение: Нет.
- Примечание: Функция позволяет перенести код написанный для библиотеки ArduinoModbus в скетч с библиотекой iarduino_Modbus, без сообщений об ошибках, но сама ничего не делает.
- Пример:
Функция exceptionStatusRead();
- Назначение: Чтение состояния 8 статусных выходов.
- Синтаксис: exceptionStatusRead( [ АДРЕС_МОДУЛЯ ] );
- Параметр: АДРЕС_МОДУЛЯ uint8_t — значение от 1 до 247.
- Возвращаемое значение: int16_t — байт битов, или -1 при неудаче.
- Примечание: Если адрес модуля не указан, команда будет отправлена всем устройствам.
- Пример без проверки чтения:
- Пример с проверкой:
Функция getSate();
- Назначение: Чтение состояния устройства.
- Синтаксис: getSate( [ АДРЕС_МОДУЛЯ ] );
- Параметр: АДРЕС_МОДУЛЯ uint8_t — значение от 1 до 247.
- Возвращаемое значение: int8_t — состояние ( 0-свободно, 1-занято ), или -1 при неудаче.
- Примечание: Если адрес модуля не указан, команда будет отправлена всем устройствам.
- Пример без проверки чтения:
- Пример с проверкой:
Функция diagnostic();
- Назначение: Выполнение команды диагностики.
- Синтаксис: diagnostic( АДРЕС_МОДУЛЯ , НОМЕР_ФУНКЦИИ_ДИАГНОСТИКИ [ , ДАННЫЕ ] );
- Параметры:
- АДРЕС_МОДУЛЯ: uint8_t — значение от 1 до 247.
- НОМЕР_ФУНКЦИИ_ДИАГНОСТИКИ: uint16_t — значение от 0 до 65535.
- 0 — Проверка связи. Результатом диагностики будет значение аргумента ДАННЫЕ.
- 1 — Перезагрузка коммуникаций и диагностика внутренних систем устройства.
- 2 — Получить значение регистра диагностики. Каждый бит информирует о ошибке.
- 3 — Сменить символ конца пакета ASCII на значение аргумента ДАННЫЕ.
- 4 — Включить режим «Только прослушивание» (Listen Only Mode).
- 10 — Сбросить все счетчики и регистр диагностики.
- 11 — Получить значение счётчика всех запросов на шине.
- 12 — Получить значение счётчика запросов с ошибками CRC.
- 13 — Получить значение счётчика ответов об ошибках.
- 14 — Получить значение счётчика запросов адресованных устройству.
- 15 — Получить значение счётчика запросов которые остались без ответа.
- 16 — Получить значение счётчика ответов об ошибках CODE_ERR_NAK.
- 17 — Получить значение счётчика ответов о «занятости» CODE_ERR_BUSY.
- 18 — Получить значение счётчика ошибок переполнения приема символов.
- Остальные номера функций доступны в документации протокола Modbus.
- ДАННЫЕ: uint16_t — необязательное значение от 0 до 65535.
- Возвращаемое значение: int32_t — результат диагностики (0. 65535), или -1 при неудаче.
- Примечание:
- Счётчик событий, это счётчик успешно выполненных запросов.
- Счётчик не реагирует на успешное выполнение команды чтения его значения.
- Пример:
- Пример:
Функция getEventCounter();
- Назначение: Чтение счетчика событий.
- Синтаксис: getEventCounter( [ АДРЕС_МОДУЛЯ ] );
- Параметр: АДРЕС_МОДУЛЯ uint8_t — значение от 1 до 247.
- Возвращаемое значение: int32_t — значение счётчика событий (0. 65535), или -1 при неудаче.
- Примечание:
- Если адрес модуля не указан, команда будет отправлена всем устройствам.
- Счётчик событий, это счётчик успешно выполненных запросов.
- Счётчик не реагирует на успешное выполнение команды чтения его значения.
- Пример без проверки чтения:
- Пример с проверкой:
Функция getEventLog();
- Назначение: Чтение журнала событий.
- Синтаксис: getEventLog( [ АДРЕС_МОДУЛЯ ] );
- Параметр: АДРЕС_МОДУЛЯ uint8_t — значение от 1 до 247.
- Возвращаемое значение: uint8_t — количество данных, доступных для чтения функцией read().
- Примечание:
- Если адрес модуля не указан, команда будет отправлена всем устройствам.
- Для получения прочитанных данных нужно обращаться к функции read().
- Количество оставшихся доступных данных можно узнать функцией available().
- Данные будут получены в следующем порядке:
- uint16_t — слово состояния (0x0000 — устройство свободно, 0xFFFF — устройство занято).
- uint16_t — значение счётчика событий (0. 65535).
- uint16_t — значение счётчика всех сообщений на шине (0. 65535).
- uint8_t — массив байтов журнала событий (не более 64 байт).
- Пример без проверки чтения:
- Пример с проверкой:
Функция getInfo();
- Назначение: Чтение информации об устройстве.
- Синтаксис: getInfo( [ АДРЕС_МОДУЛЯ ] );
- Параметр: АДРЕС_МОДУЛЯ uint8_t — значение от 1 до 247.
- Возвращаемое значение: uint8_t — количество данных, доступных для чтения функцией read().
- Примечание:
- Если адрес модуля не указан, команда будет отправлена всем устройствам.
- Для получения прочитанных данных нужно обращаться к функции read().
- Количество оставшихся доступных данных можно узнать функцией available().
- Данные будут получены в следующем порядке:
- uint8_t — идентификатор линейки устройств.
- uint8_t — индикатор пуска: (0x00 — off, 0xFF — on).
- uint8_t — массив данных об устройстве (количество байт зависит от устройства).
- Пример без проверки чтения:
- Пример с проверкой:
- Пример для модулей iarduino:
Функция lastError();
- Назначение: Получение кода причины последней ошибки.
- Синтаксис: lastError();
- Параметры: Нет.
- Возвращаемое значение: uint8_t — код причины последней ошибки.
- ERROR_ILLEGAL_FUNCTION — Команда запроса не поддерживается модулем.
- ERROR_ILLEGAL_ADDRESS — У модуля отсутствует регистр с указанным адресом.
- ERROR_ILLEGAL_VALUE — Недопустимое значение в поле данных запроса.
- ERROR_DEVICE_FAILURE — Любая невосстановимая ошибка кроме первых трёх.
- ERROR_ACKNOWLEDGE — Модуль принял запрос, но на обработку требуется время.
- ERROR_DEVICE_BUSY — Ведомый занят, запрос проигнорирован.
- ERROR_MEMORY_PARITY — Ошибка чтения/записи файла.
- ERROR_GATEWAY_UNAVAILABLE — Шина перегружена данными или не настроена.
- ERROR_GATEWAY_NO_DEVICE — Ведомого устройства нет или от него нет ответа.
- ERROR_SYNTAX — Ошибка синтаксиса.
- ERROR_ADR_IARDUINO — Ошибка назначения или сортировки адресов устройств iarduino.
- ERROR_ADR_RESPONSE — Несовпадение адреса регистра в ответе.
- ERROR_VAL_RESPONSE — Несовпадение данных в ответе.
- ERROR_CRC_RESPONSE — Несовпадение CRC в принятом ответе.
- ERROR_LEN_REQUEST — Размер отправляемого запроса превышает размер буфера.
- ERROR_LEN_RESPONSE — Размер полученного ответа превышает размер буфера.
- Пример:
Функции для работы с адресами:
Функции перечисленные в данном разделе предназначены для устройств iarduino.