Урок 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.

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

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

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

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

  2. Как интересно! Почему раньше не находил ваш ресурс. Одно время тоже на ардуине, модбас устройства пилил ))) Скажите, на чем пишите приложения верхнего уровня? Ткните, если есть пост об этом.

    • Здравствуйте! На Borland C++ Builder. Подумываю сделать инфопродукт на эту тему, но не в ближайшее время.

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

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