1. Главная страница » Компьютеры

Modbus rtu на софтверном порту скетч

Автор: | 16.12.2019

Ранее ещё на хабре я рассказывал о реализации поддержки протокола Modbus в программе FLProg. К сожалению как показала практика его использования, реализация получилась не очень удачная. Если Slave работал ещё более менее уверенно, то мастер работал очень неустойчиво. Кроме того задание адресов регистров было возможно только в виде непрерывного массива, и не было разделения на области памяти. Мастер в той реализации мог обращаться только к Holding Registers слейвов, что очень ограничивало возможности его применения. Достаточно долго я искал нормально реализованную библиотеку Modbus RTU для Arduino, но поиски не привели к успеху. Поэтому было принято решение написать реализацию обмена по Modbus RTU самостоятельно. И вот в недавно вышедшей версии программы FLProg с номером 1.12 это сделано. Что изменилось:

  1. Реализация Modbus RTU полностью совместима с промышленным стандартом.
  2. Реализованы четыре таблицы переменных – Coils, Discrete Inputs, Input Registers, Holding Registers. Для каждой переменной, можно задавать любой адрес (не обязательно последовательно).
  3. Реализована возможность задания адреса слейва, скорости порта и отключения/включения опроса конкретного слейва мастером программным путём с запоминанием этих данных в EEProm.
  4. Реализована возможность одновременной работы мастера и слейва на одном контроллере (на разных портах).
  5. Реализована возможность применять в качестве порта SoftwareSerial
  6. Благодаря динамически генерируемому коду одновременная работа мастера и слейва возможна даже на плате Pro-Mini.
  7. Реализована прямая совместимость со старыми версиями – ранее созданные проекты будут работать на новой версии без переделки.

В данном уроке я решил сделать, что ни будь реально полезное. Пробежавшись по онлайн – магазинам, я нашёл жертву – будем дублировать датчики и исполнительные устройства на шину RS-485 продающиеся в магазине Wiren Board. Почему они? Да меня просто убили их цены. Особенно возмутила цена на датчики DS18B20. На сайте они честно говорят о китайском их происхождении, и при этом запрашивают 400 рублей. Хотя в Китае даже при розничной продаже их цена 102 рубля. А при оптовой наверняка намного дешевле. Интересно – наценка более 300% — это за поход на почту?

Читайте также:  Photoshop как добавить изображение на слой

Для начала попробуем повторить «Модуль реле Modbus-RTU Relay Module (WB-MRM2-mini)» – цена 2000 рублей.

Комплектующие для создания модуля:

Итого – 307 рублей. Как то дешевле двух тысяч рублей. Я думаю из рассыпухи по оптовым ценам на своей плате себестоимость ещё меньше будет.
Принципиальная схема:

Описание не нашёл. Будем изобретать сами.

Комплектующие для создания модуля:

Итого: 527 рублей. Чувствуете разницу? Дорогой корпус уж очень получается, зато красивый.
Принципиальная схема:

Ну и теперь напоследок соберём устройство, которое будет собирать данные и управлять этими блоками. Для отображения информации и управления будем использовать смартфон на Андроиде. Соединение будет производиться с помощью Bluetooth, а в качестве программного обеспечения будет программа HMI-KaScada. На плате Arduino будет организованна работа Modbus Master (для сбора информации с блоков) и Modbus Slave (для работы с программой HMI-KaScada) одновременно.

Комплектующие для создания модуля:

Итого:427 рублей.
Принципиальная схема:

Ну что сказать напоследок? Если у Вас есть прямые руки, то многое что продается за большие деньги, можно сделать самому и намного дешевле.

Блог технической поддержки моих разработок

В уроке представлю библиотеку для разработки программного обеспечения ведомого контроллера Ардуино в сетях с протоколом ModBus RTU. В качестве примера реализую связь контроллера с компьютером через интерфейс UART.

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

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

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

Библиотека Tiny_ModBusRTU_Slave.

Библиотеку Tiny_ModBusRTU_Slave можно загрузить по этой ссылке:

Зарегистрируйтесь и оплатите. Всего 40 руб. в месяц за доступ ко всем ресурсам сайта!

Библиотека позволяет простыми средствами реализовать программное обеспечение ведомого контроллера с протоколом ModBus RTU. Может быть использована совместно с интерфейсами UART, RS-485, RS-422, RS-232 и т.п. Поддерживает управление передатчиком в шинных интерфейсах с третьим состоянием, подобных RS-485.

Слово ”Tiny” (крошечный) в названии библиотеки подчеркивает, что реализован минимальный набор функций. Всего 3 кода функции работы с регистрами хранения. Тем не менее, большинство контроллеров поддерживает именно этот набор операций.

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

Библиотека Tiny_ModBusRTU_Slave имеет конструктор и всего одну функцию.

class Tiny_ModBusRTU_Slave <
public:
Tiny_ModBusRTU_Slave(byte adress, byte timeOut, unsigned int * holdingRegTable, unsigned int lengthTable); // конструктор
Tiny_ModBusRTU_Slave(byte adress, byte timeOut, unsigned int * holdingRegTable, unsigned int lengthTable, byte directPin); // конструктор
vo >загрузка данных
boolean flagRead; // признак данные были считаны
boolean flagWrite; // признак данные были записаны
>;

Конструктор.

Tiny_ModBusRTU_Slave(byte adress, byte timeOut, unsigned int * holdingRegTable, unsigned int lengthTable, byte directPin)

Создает объект со следующими параметрами:

  • address – адрес ведомого устройства в сети. Может иметь значение от 1 до 247.
  • timeOut – время паузы (тишины) перед передачей ответа. Значение должно быть не менее времени, необходимого на передачу 3,5 байта. Вычисляется, как timeOut * период вызова функции update().
  • holdingRegTable – указатель на массив (имя массива) – таблицы регистров хранения.
  • lengthTable – размер таблицы регистров хранения.
  • directPin – номер вывода разрешения работы передатчика ведомого устройства. Используется для шинных интерфейсов, у которых передатчик имеет три состояния. Например, RS-485. Параметр не обязательный. При его отсутствии вывод не используется.

Tiny_ModBusRTU_Slave slave(1, 12, regTable, 12); // создаем объект, адрес 1, таймаут 6 мс, массив regTable, размер 12

Метод.

update() – загрузка данных. Единственная функция класса. В ней происходит все управление обменом. Функция должна вызываться регулярно в параллельном процессе, например, в прерывании по таймеру.

// обработчик прерывания 500 мкс
void timerInterrupt() <
slave.update();
>

Метод update() полностью контролирует обмен данными по сети. Программа основного цикла работает только с массивом regTable (таблица регистров хранения). Данные массива доступны ведущему устройству сети для чтения и записи.

На всякий случай я добавил 2 признака, сообщающие об обращении ведущего устройства к регистрам хранения.

  • flagRead – признак чтения данных. Активное состояние (true) говорит о том, что ведущее устройство прочитало хотя бы один регистр хранения. Признак должен сбрасываться в основной программе при обработке.
  • flagWrite – признак записи данных. Активное состояние сообщает о том, что произошла запись хотя бы одного регистра. Т.е. данные таблицы были изменены. Признак должен сбрасываться в основной программе.

Библиотека поддерживает коды функций.

Код функции Название Описание
03 READ HOLDING REGISTERS Чтение значений одного или нескольких регистров хранения
06 FORCE SINGLE REGISTER Запись в один регистр хранения
16 FORCE MULTIPLE REGISTERS Последовательная запись нескольких регистров хранения

Обрабатываются следующие коды ошибок.

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

Библиотека поддерживает широковещательный обмен, при котором ведущее устройство формирует адрес равный 0.

Максимальное число байтов одного кадра – 64 байта.

Применение библиотеки Tiny_ModBusRTU_Slave.

Для практической реализации программы ведомого Ардуино контроллера необходимо:

  • подключить библиотеку Tiny_ModBusRTU_Slave;
  • создать массив – таблицу регистров;
  • создать объект Tiny_ModBusRTU_Slave;
  • задать параметры UART (класс Serial);
  • реализовать прерывание по таймеру и в его обработчик включить функцию update().

unsigned int regTable[10];
Tiny_ModBusRTU_Slave slave(1, 8, regTable, 10); // создаем объект, адрес 1, таймаут 4 мс, массив regTable, размер 10

void setup() <
Timer1.initialize(500); // инициализация таймера 1, период 500 мкс
Timer1.attachInterrupt(timerInterrupt, 500); // задаем обработчик прерываний
Serial.begin(9600);
>

В этом скетче цикл loop() остался пустым. Тем не менее, программа будет работать. Если подключить плату к сети ModBus, то ведущий контроллер сможет записывать и считывать данные из массива regTable. Другое дело, что больше контроллер ничего не делает. Получилось сетевое запоминающее устройство на 10 регистров.

Давайте загрузим этот простой скетч и проверим работу ведомого контроллера.

Для проверки я воспользовался эмулятором ведущего устройства ModBus. Таких программ в интернете очень много. Но то, что нужно я нашел с большим трудом.

Какие-то эмуляторы ModBus платные, другие сложные, требуют установки дополнительных программ. Некоторые допускают работу только с одним регистром. Попался мне эмулятор, который вроде меня устроил. Потом оказалось, что он при каждой посылке вырабатывает импульс на сигнале DTR конвертера USB-USRT и сбрасывает плату Ардуино. Понял я это не сразу.

В конце концов, я нашел эмулятор ведущего устройства ModBus RTU, который устроил меня полностью. Это эмулятор QModBus. Описывать его не буду. В программе все просто и интуитивно понятно.

Эмулятор QModBus опубликован по ”Универсальной общественной лицензии GNU GPL”, что допускает свободное распространение программы. Поэтому выкладываю программу на сайте: QModBus-0.2.1-win32.

С помощью QModBus я проверил все коды функции библиотеки, записывал и считывал разные данные, убедился, что правильно отрабатываются коды ошибок.

Реализация локального контроллера ModBus RTU.

Я использовал локальный контроллер из урока 48 без каких-либо изменений аппаратной части.

Повторю его схему.

Еще раз покажу, как он выглядит.

Программу, конечно, надо менять.

Прежде всего, необходимо выбрать назначение регистров хранения ModBus. Я задал адреса в подряд.

Номер регистра Формат числа Параметр
0 float Температура
1
2 float Напряжение
3
4 бит Состояние кнопки (мл. бит)
5 бит Состояние светодиода (мл. бит)

Напомню, что регистры в протоколе ModBus шестнадцатиразрядные. Получилось 6 регистров.

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

Я использовал программу из урока 48. Добавил к ней объект Tiny_ModBusRTU_Slave.

Скетч можно загрузить по этой ссылке:

Зарегистрируйтесь и оплатите. Всего 40 руб. в месяц за доступ ко всем ресурсам сайта!

Начальную проверку я выполнил с помощью того же эмулятора QModBus.

Считывал 6 регистров хранения и убедился, что передача происходит без ошибок, данные меняются. Осмысленной получилась проверка только кнопки и управление светодиодом.

Программа верхнего уровня.

Мы используем числовой протокол. Поэтому показания датчиков выглядят как бессмысленный набор чисел. Для того, чтобы увидеть температуру и напряжение в ”человеческом виде” я написал программу верхнего уровня. Вернее я изменил протокол обмена программы UART_Arduino_PC из урока 48. И с помощью нее окончательно проверил работу локального контроллера.

Все работает идеально. Ни единой ошибки.

Программу верхнего уровня можете загрузить по ссылке:

Зарегистрируйтесь и оплатите. Всего 40 руб. в месяц за доступ ко всем ресурсам сайта!

Сравнение производительности протокола ModBus и специализированного протокола из урока 48.

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

Для обмена информацией с локальным контроллером по специализированному протоколу из урока 48 нам требовалось 15 байтов.

Для передачи той же самой информации по протоколу ModBus я насчитал 39 байтов. И еще паузы между кадрами.

Производительность сети ModBus более чем в два раза ниже. Это расплата за применение универсального протокола.

Библиотеку Tiny_ModBusRTU_Slave я буду использовать в дальнейших уроках для организации проводной сети между платами Ардуино. Проверить ее работу в сети ModBus с чужими контроллерами у меня нет возможности. Но испытание совместно с эмулятором ModBus ошибок в библиотеке не выявило.

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

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

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

Что нам необходимо знать об этом стандарте?
Протокол Modbus использует последовательные линии связи (например, RS232, RS485), а протокол Modbus TCP рассчитан на передачу данных по сетям TCP/IP.
Протокол Modbus имеет два режима передачи RTU и ASCII, в режиме ASCII каждый байт передается как два ASCII символа его шестнадцатеричного представления.
В сети Modbus есть только один ведущий, который с заданным интервалом опрашивает несколько ведомых устройств, каждое из которых имеет свой уникальный адрес от 1 до 254, адрес 0 широковещательный и на него отвечают все устройства, так как ведущий в сети один у него нет своего адреса.
В спецификации Modbus определено два типа данных, один бит и 16 битное слово. Данные организованны в четыре таблицы с 16 битной адресацией ячеек, адресация в таблицах начинается с 0. Для доступа к данным из разных таблиц предназначены отдельные команды.

Discrete Inputs 1 бит только чтение
Coils 1 бит чтение и запись
Input Registers 16 бит только чтение
Holding Registers 16 бит чтение и запись

Как нам подключить Modbus устройство к OpenHAB? За это отвечает модуль Modbus Tcp Binding, этот модуль работает в режиме ведущего и обеспечивает подключение нескольких ведомых устройств через последовательный порт или TCP/IP сеть.
Для того чтобы связать с ним Arduino нам необходимо реализовать в контроллере ведомое Modbus устройство, воспользуемся для этого библиотекой Modbus-Master-Slave-for-Arduino.

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

Рассмотрим на примере нашего скетча основные шаги необходимые для работы с этой библиотекой.

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

Затем определить массив регистров Modbus

После этого, при старте программы настроить последовательный порт ведомого

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

И после этого можно обработать полученные данные и сохранить необходимые переменные в регистрах Modbus.

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

Для демонстрации работы с разными регистрами, в процессе работы программы данные из регистра с типом coil будут скопированы в регистр с типом discrete, а из регистров с типом holding в регистры с типом input. Кроме этого состояние кнопки будет сохранено в третий бит регистра au16data[0] (discrete), а значение третьего бита регистра au16data[1] (coil) выведено на светодиод.

Доработаем макет контроллера, который был собран для предыдущих экспериментов, переключим светодиод с 13 на 12 вывод. Обычно на плате самого Arduino уже есть светодиод, подключенный к 13 выводу, в нашей программе он станет индикатором статуса работы. Теперь подключим USB кабель к компьютеру, скомпилируем и загрузим программу в контроллер.

Пора приступать к испытаниям. Значительно облегчает работу на этом этапе эмулятор Modbus мастер-устройства, в сети есть несколько хороших, при этом бесплатных программ, вот некоторые из них:
www.focus-sw.com/fieldtalk/modpoll.html
qmodbus.sourceforge.net
www.mikont.com/products/EAT-Console.html

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

Для установки эмулятора нужно скачать архив и распаковать его в папку C:arduinoEATConsole, затем открыть страницу загрузки Eclipse, скачать Eclipse IDE for Java Developers и распаковать его в папку C:arduinoeclipse, после этого скопировать файлы из папки C:arduinoEATConsoleeclipseplugins в папку C:arduinoeclipseplugins.

Для создания конфигурации необходимо запустить C:arduinoeclipseeclipse.exe, создать пустой проект, скопировать в него пустой файл C:arduinoEATConsolemenu.ptmenu и добавить в редакторе пункты в соответствии со следующей таблицей. Если же вы скачали проект из репозитория, то в нём, в папке EATConsole уже есть подготовленный файл menu.ptmenu.

Type Address Bit Name Point Slave
Display Boolean 0 0 DT0 1
Display Boolean 0 1 DT1 1
Display Boolean 0 2 DT2 1
Display Boolean 0 3 BTN 1
Input Boolean 1 0 CL16 1
Input Boolean 1 1 CL17 1
Input Boolean 1 2 CL18 1
Input Boolean 1 3 LED 1
Display Integer 2 INPT3 0 1
Display Integer 3 INPT4 0 1
Display Integer 4 INPT5 0 1
Display Integer 5 HOLD6 0 1
Display Integer 6 HOLD7 0 1
Display Integer 7 HOLD8 0 1

Type — тип элемента меню EATConsole.
Address — адрес регистра данных.
Bit – номер бита в регистре.
Name – название элемента меню.
Point – количество десятичных знаков после точки.
Slave – Modbus адрес контроллера.

Теперь сохраним и скопируем файл menu.ptmenu в каталог C:arduinoEATConsole, для этого можно щёлкнуть правой кнопкой мыши на файле прямо в Eclipse, выбрать в контекстном меню пункт “Copy”, а затем вставить в проводнике в папку C:arduinoEATConsole.

После этого запустим C:arduinoEATConsoleEATConsole.exe, настроим последовательное соединение, выбрав пункт меню ФайлНастройки, в диалоговом окне укажем номер порта, скорость 9600, 8 бит данных, 1 стоповый бит.

*Программа работает с портами с 1 по 8 и если USB переходник Arduino встал на порт с большим номером, придётся открыть диспетчер устройств Windows и изменить номер порта для него.

Когда все настройки будут введены, нажмите кнопку “Установить”, сразу после этого программа начнёт опрос устройства и если что-то пошло не так появится сообщение – НЕТ СВЯЗИ. Если же всё было сделано правильно и связь есть в чём можно убедиться по миганию индикатора статуса (светодиод на выводе 13), то пора приступить к испытаниям нашего контроллера.

Попробуем поменять значение в регистрах HLD0…HLD2 и СL0…СL2, при этом должно поменяться значение в соответствующем регистре IN0..IN2 и DT0..DT2, затем нажмём на кнопку макета, при этом должно поменяться значение в поле BTN, щёлкнем по полю LED, при этом должен загореться или потухнуть светодиод.

Что мы получили в результате нашей работы:

1 познакомились с азами протокола Modbus;
2 создали скетч, который превращает Arduino в Modbus slave устройство и позволяет читать и записывать несколько Modbus регистров с разными типами данных;
3 протестировали обмен с контроллером при помощи эмулятора функций Modbus master устройства, для которого создали конфигурацию соответствующую структуре регистров контроллера.

Выводы
Библиотека Modbus-Master-Slave-for-Arduino проста в использовании, позволяет создать ведомое Modbus устройство, которое корректно работает с программным эмулятором. Скомпилированный пример занимает немногим более 5кб памяти программ, так что в контроллере остаётся достаточно места для добавления необходимого функционала.

Стандарт Modbus открыт и популярен, но в нём есть ряд недостатков — в стандарте определено только два типа данных,
протокол требует постоянного обмена между ведущим и ведомыми устройствами, конфигурировать систему приходится вручную.

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

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *