Arduino holding register

Работа с протоколом 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.

  • Для подключения устройств к шине RS485 используются выводы A, B и GND.
    • 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.

    Источник

    Adblock
    detector