Урок 57. Обмен данными между платой Ардуино и компьютером через UART по протоколу ModBus. Библиотека Tiny_ModBusRTU_Slave.

Подключение платы Ардуино к компьютеру

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

Предыдущий урок     Список уроков     Следующий урок

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

 

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

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

 

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

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

Библиотека позволяет простыми средствами реализовать программное обеспечение ведомого контроллера с протоколом 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); // конструктор
    void update();  // загрузка данных
    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().

#include <Tiny_ModBusRTU_Slave.h>
#include <TimerOne.h>

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);
}

void loop() {
}

// обработчик прерывания
void timerInterrupt() {
  slave.update();
}

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

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

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

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

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

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

Эмулятор QModBus

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

 

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

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

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

Схема локального контроллера

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

Локальный контроллер

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

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

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

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

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

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

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

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

Эмулятор QModBus

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

 

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

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

Монитор данных локального контроллера

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

Программу верхнего уровня можете загрузить по этой ссылке UART_Arduino_PC_ModBus.zip.

 

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

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

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

Кадры обмена

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

Кадры обмена

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

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

 

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

Предыдущий урок     Список уроков     Следующий урок

2 комментария на «Урок 57. Обмен данными между платой Ардуино и компьютером через UART по протоколу ModBus. Библиотека Tiny_ModBusRTU_Slave.»

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

    • Здравствуйте!
      Для мастера будет другая библиотека Tiny_ModBusRTU_Master. Через несколько дней напишу новый урок.

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

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