Контроллер поддерживает Modbus RTU по RS-485 и Modbus TCP по Ethernet. В режиме ведомого устройства (Slave) внешняя программа может читать состояние контроллера и значения ресурсов, изменять выходы и пользовательские регистры, запускать и останавливать сохранённые сценарии.

В режиме ведущего устройства (Master) опрос оборудования по Modbus RTU выполняется из сценариев MicroPython или C. API мастера описан в документации модуля dev для MicroPython и C-сценариев. Далее описан режим Slave.

Настройка Slave

В разделе «Modbus» настроек контроллера задайте параметры:

ПараметрНазначение
Использовать TCPПринимать Modbus TCP на порту 502.
Использовать RTUПринимать Modbus RTU по RS-485.
АдресОбщий адрес для RTU и TCP, 1–248. В TCP-клиенте укажите его как Unit ID / Slave ID.
RTU битрейт300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 56000, 57600 или 115200 бит/с.
RTU чётностьnone — 8 бит данных, без чётности, 2 стоп-бита (8N2); even — 8E1; odd — 8O1.
RTU задержка, мсЗадержка перед ответом: 0–100 мс. Учитывайте её при выборе таймаута клиента.

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

Modbus TCP обслуживает одно соединение одновременно. Перед запуском другого клиента закройте соединение в предыдущей программе. Если TCP-соединение устанавливается, но ответы не приходят, проверьте, не подключена ли другая утилита опроса.

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

Доступ к ресурсам

Для Do, Di, Ao, Ai и Reg используется настройка внешнего доступа, общая для Modbus и SNMP. Она независима от доступа через веб-интерфейс. В сценариях ей соответствует второй символ параметра access.

Внешний доступРезультат
0 — нет доступаЧтение и запись запрещены.
1 — чтениеМожно читать значение.
2 — чтение и изменениеМожно читать и записывать Do, Ao и Reg. Di и Ai остаются только для чтения.

Неиспользуемые адреса карты не являются дополнительными каналами. Запрос к несуществующему, скрытому или недоступному для выбранной операции ресурсу возвращает ошибку Modbus. Для Reg также учитываются настроенное количество, тип и ограничения значения.

Поддерживаемые функции

Все значения расположены в области Holding Registers. Один Modbus-регистр содержит 16 бит.

Код функцииНазначениеКоличество 16-битных слов
03 / 0x03 — Read Holding RegistersЧтение карты адресов ниже.1–125
06 / 0x06 — Write Single RegisterЗапись одного Do, Ao или регистра управления сценарием. Для пользовательских Reg запрещена.1
16 / 0x10 — Write Multiple RegistersЗапись нескольких слов, в том числе полных 32-битных Reg.1–123

Здесь 16 — десятичный код функции, которому соответствует 0x10. FC06 записывает одно 16-битное слово; FC16 может передать несколько слов в одном запросе.

Чтение Input Registers (FC04), Coils и Discrete Inputs не поддерживается. Для Di также используйте FC03 по адресам из общей карты.

Весь запрошенный диапазон должен быть доступен. Например, чтение от адреса 0 количеством 32 слова завершится ошибкой: адрес 15 и адреса 24–31 зарезервированы. Системные данные можно читать отдельными блоками 0–14 и 16–23.

Карта адресов

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

R — чтение; RW — чтение и запись с учётом прав ресурса. Адреса обозначают десятичные числа.

Состояние и управление сценарием

АдресДоступЗначение
0RЧисловой код модели контроллера.
1RВерсия прошивки, младшие 16 бит.
2RВремя с запуска контроллера в секундах, младшее слово uint32.
3RТо же, старшее слово.
4RПодключение к серверу: 0 — неизвестно; 1 — отключено; 2 — подключение; 3 — подключено; 4 — ошибка.
5RБитовая маска системных аварий, см. ниже.
6RБитовая маска пользовательских аварий, биты 0–15.
7RБитовая маска пользовательских аварий, биты 16–31.
8RWПри чтении — код текущего/последнего сценария. При записи — выбор кода сохранённого сценария для следующей команды запуска. Допустимо 0–65534; код 65535 запрещён.
9RWПри чтении: 0 — сценарий ещё не запускался; 1 — работает; 2 — остановлен. При записи: 0 — остановить, 1 — запустить сценарий, выбранный записью в адрес 8. Запись 2 и других значений запрещена.
10RТип сценария: 0 — нет; 1 — MicroPython; 2 — C; 3 — двоичный C-сценарий.
11RПричина запуска, см. таблицу ниже.
12RПричина остановки, см. таблицу ниже.
13RВремя работы сценария в секундах, младшее слово uint32.
14RТо же, старшее слово.
15—Резерв, чтение и запись запрещены.
16RТекущий IPv4-адрес локального Ethernet-интерфейса: первые два октета, (a << 8) | b.
17RТот же IPv4-адрес: последние два октета, (c << 8) | d.
18–23RUID процессора: 12 байт, по два байта в регистр, первый байт пары — старший.
24–31—Резерв, чтение и запись запрещены.

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

Для запуска сценария с кодом 301 выполните FC06: адрес 8, значение 301; затем FC06: адрес 9, значение 1. Можно передать оба слова одним FC16: начало 8, количество 2, слова [301, 1]. Для остановки запишите FC06: адрес 9, значение 0. Подтверждение команды запуска не означает завершение сценария; отслеживайте состояние по адресу 9. Если сценарий не найден или команду выполнить не удалось, возвращается exception 04.

Биты системных аварий по адресу 5:

БитАвария
0HardFault в прошивке контроллера.
1HardFault в пользовательском сценарии.
2Срабатывание watchdog.
3Переполнение стека.
4Ошибка выполнения пользовательского сценария.
5Автозапуск сценария отключён из-за нестабильной работы контроллера.

В случае критических ошибок контроллер перезапускается посредством watchdog с последующей активацией системной аварии. Чтение аварий по Modbus не сбрасывает их.

Адреса 11 и 12 используют одинаковые коды причин:

КодПричина
0Не задана.
1Ошибка.
2Автоматическое действие.
3Действие пользователя.
4Штатное завершение сценария.
5Алгоритм.
6Расписание.
7Веб-интерфейс.
8Внешний доступ, в том числе Modbus.
9Пульт управления.

Текущий IP-адрес и UID

Регистры 16–23 доступны в актуальной прошивке X0 и X1 через RTU и TCP. Они предназначены только для чтения: попытка записи FC06 или FC16 возвращает exception 02 — Illegal Data Address. В старой прошивке эти адреса также могут возвращать exception 02 при чтении.

Чтобы узнать IP-адрес, отправьте FC03, начало 16, количество 2. Возвращается фактический адрес локального Ethernet-интерфейса, в том числе полученный по DHCP. До назначения адреса возвращается 0.0.0.0; в этом случае повторите чтение после ожидания DHCP.

Слова передаются по порядку октетов IPv4, внутри слова первым идёт старший байт. Например:

  Адрес 16: слово 0xC0A8, байты C0 A8 → октеты 192.168
Адрес 17: слово 0x326C, байты 32 6C → октеты 50.108
IP-адрес: 192.168.50.108
  

При чтении обоих слов одним запросом используется один снимок IP-адреса, поэтому изменение адреса DHCP не смешивает две его половины. В клиенте с обозначениями Holding Registers от 40001 это регистры 40017 и 40018. Узнав IP через RTU, можно обратиться к HTTP API контроллера; проверка GET /ping подтверждает доступность HTTP.

Для чтения UID отправьте FC03, начало 18, количество 6. Для строкового представления объедините шесть слов по порядку, записывая каждое четырьмя шестнадцатеричными цифрами с ведущими нулями:

  Слова: 0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xAABB
UID:   00112233445566778899aabb
  

Порядок байтов совпадает с полем idCpu в ответе GET /json?static. Это позволяет проверить, что Modbus и HTTP отвечают от одного контроллера. IP и UID можно прочитать вместе: FC03, начало 16, количество 8.

Входы, выходы и пользовательские Reg

АдресДоступРесурс и формат
32–63RWDo(n), адрес 32 + n: 0 — выключен, 1 — включён.
64–95RDi(n), адрес 64 + n: 0 или 1.
96–127RWAo(n), адрес 96 + n: целое 0–1000, сотые доли вольта; 1000 = 10,00 В.
128–159RAi(n), адрес 128 + n: 16-битное значение, формат зависит от режима и канала, см. ниже.
160–223RWReg(n): младшее слово по адресу 160 + 2*n, старшее — 161 + 2*n. Максимум 32 пользовательских Reg.

Диапазоны зарезервированы под карту, но фактическое число физических каналов меньше: Do — 3 у X0 и 5 у X1; Di — 5, Ao — 3, Ai — 3 у обеих моделей. Например, у X0 адреса Do 35–63 недоступны. Нумерация каналов начинается с нуля. Количество пользовательских Reg задаётся в настройках: при десяти Reg доступны адреса 160–179.

Ai: интерпретируйте слово как знаковое 16-битное целое. В обработанном режиме температурные каналы возвращают десятые доли °C: -125 означает −12,5 °C, на линии это слово 0xFF83. Значение 32767 / 0x7FFF означает ошибку измерения температуры. На X0 все три входа температурные. На X1 входы 0 и 1 температурные, вход 2 в обработанном режиме возвращает напряжение в сотых долях вольта. В режиме raw передаётся исходный отсчёт АЦП без пересчёта в температуру или напряжение.

Формат и запись 32-битных Reg

Reg передаётся как исходное 32-битное значение настроенного типа:

  • bool — 0 или 1;
  • int — знаковое 32-битное целое в дополнительном коде;
  • uint — беззнаковое целое 0–4294967295;
  • float — двоичный формат IEEE 754 binary32;
  • enum — целый индекс варианта, начиная с нуля.

Число десятичных знаков отображения Reg не меняет его передаваемое значение. Для float требуется интерпретация битов как float32, а не числовое преобразование uint32 в float.

Внутри каждого 16-битного слова сначала передаётся старший байт. Для 32-битного значения сначала передаётся младшее слово, затем старшее. Например:

  Reg(0) = 0x12345678
адрес 160: слово 0x5678, байты 56 78
адрес 161: слово 0x1234, байты 12 34
  

Для чтения Reg(0) отправьте FC03, начало 160, количество 2. Значение собирается как low | (high << 16). Для float 1.0 исходные биты равны 0x3F800000, слова на линии — [0x0000, 0x3F80]. В программах опроса выбирайте порядок младшего слова первым; названия опций могут отличаться.

При чтении двух половин в одном запросе они соответствуют одному снимку Reg, даже если сценарий меняет значение. Чтение одной половины разрешено, но два отдельных запроса не гарантируют согласованную пару. Снимок всех Reg одновременно не гарантируется. Для системных 32-битных счётчиков и масок по адресам 2–3, 6–7 и 13–14 отдельный согласованный снимок также не гарантируется.

Правила записи

Пользовательский Reg записывается только целиком одним FC16, с младшим и старшим словом в одном запросе:

  Функция:    16 (0x10)
Начало:     160
Количество: 2 слова
Данные:     [0x5678, 0x1234]
Результат:  Reg(0) = 0x12345678
  

Данные PDU этого запроса, без адреса устройства, MBAP и CRC:

  10 00 A0 00 02 04 56 78 12 34
  

Нельзя записывать Reg двумя FC06 или двумя отдельными запросами с одной половиной. Такие запросы отклоняются с exception 03 и не сохраняют отложенную половину. Для блока Reg начальный адрес должен приходиться на младшее слово, а количество слов — быть чётным. Например, десять Reg записываются одним FC16: начало 160, количество 20 слов.

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

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

Широковещательные запросы RTU

Адрес 0 используется для RTU broadcast. Допустимые записи FC06/FC16 выполняются без ответа, чтение игнорируется. Для пользовательских Reg по-прежнему нужны полные пары FC16. Отсутствие ответа на broadcast ожидаемо и не подтверждает успешную запись; результат можно проверить обычным чтением по адресу устройства.

Для обычных запросов RTU контроллер проверяет адрес и CRC. Запросы с чужим адресом или неверной CRC игнорируются без ответа. В TCP указывайте настроенный адрес контроллера; широковещательный режим RTU на TCP не переносится.

Ошибки и диагностика

ExceptionЗначение для клиента
01 — Illegal FunctionНеподдерживаемая функция.
02 — Illegal Data AddressНеверный/несуществующий адрес, скрытый ресурс, запрет доступа или попытка записи в ресурс только для чтения. Весь диапазон должен быть доступен.
03 — Illegal Data ValueНеверная длина, количество слов, byteCount, значение, команда управления сценарием или неполная/смещённая пара Reg.
04 — Slave Device FailureОшибка выполнения, например сценарий не найден или его не удалось запустить/остановить.
06 — Slave Device BusyРесурс занят; запрос можно повторить позднее.

Некорректный заголовок Modbus TCP (Protocol ID или длина MBAP) приводит к закрытию соединения. Подключитесь заново после исправления запроса. TCP допускает передачу запроса частями и нескольких запросов в одном пакете; сопоставляйте ответы по Transaction ID.

Если нет ответа, проверьте включение нужного интерфейса, адрес устройства, доступность TCP-порта 502 или параметры RS-485, затем права и адреса ресурсов. Для TCP также закройте другие клиенты. Журнал доступен в веб-интерфейсе и по HTTP /txt?log; сведения о hardFault и переполнении стека — /txt?sys.