В предыдущих статьях мы познакомились с замечательным внешним RS485/ModbusRTU блоком расширения EBYTE MA01-AACX2240 и научились управлять работой его реле. Сегодня мы разберём программирование цифровых входов MA01-AACX2240 и научимся получать с них данные в контроллере на ESP32.
Поскольку это RS485/ModbusRTU блок, то при помощи него можно не только расширить функционал вашего контроллера, но и вынести реле, цифровые и аналоговые входы на значительное расстояние от самого контроллера (десятки и сотни метров), что может быть полезно в различных проектах.
MA01-AACX2240 это довольно функциональное устройство и позволяет не только получать данные с цифровых входов, но и тонко настраивать работу самих этих входов — можно использовать счётчики, устанавливать работу по фронтам сигнала, выбирать метод обнуления счётчиков и т. д. и т. п., обо всём этом мы и поговорим далее…
❯ Регистры, ассоциированные с цифровыми входами
Снова привожу таблицу Modbus RTU регистров MA01-AACX2240, в которой я отметил цветом регистры, ассоциированные с цифровыми входами. Всего таких групп регистров пять:
- Текущее состояние цифровых входов
- Счётчики цифровых входов
- Метод срабатывания для счётчиков
- Тип обнуления (автоматическое или ручное)
- Значение для обнуления
Во второй таблице тоже присутствует один регистр, относящийся к цифровым входам. Это т. н. «фильтр», то есть количество импульсов для усреднения показаний счётчиков (по умолчанию — 6). В таблице (видимо ошибочно) этот параметр ассоциирован с аналоговыми входами (AI), а в документации — с цифровыми (что верно).
Итого, суммарно в блоке MA01-AACX2240 присутствуют 6 групп Modbus RTU регистров, относящихся к цифровым входам. Далее мы попробуем подробнее разобраться с их работой.
❯ Тестовое оборудование
В качестве управляющего, как и в предыдущих статьях, мы будем использовать контроллер Lavritech V7.1 Lite на ESP32 с внутренним модулем Lavritech RS485 V1. Перечень оборудования для проведения тестов:
- Клеммы на DIN-рейку ABB MA2,5 для подключения сетевых проводов
- Автоматический выключатель ABB S201 C16 для подачи сетевого питания
- Блок питания на DIN-рейку MEAN WELL 12В 2А для запитки MA01-AACX2240
- Контроллер Lavritech V7.1 Lite с модулем Lavritech RS485 V1
- Блок EBYTE MA01-AACX2240
Устанавливаем всё это на стенд и соединяем соответствующим образом. Контроллер Lavritech V7.1 Lite запитывается от USB разъёма компьютера, а соединение по интерфейсу RS485 между контроллером и блоком MA01-AACX2240 производится при помощи отрезка витой пары на контакты A-A и B-B клеммных колодок обоих устройств.
❯ Цифровые входы
В серии блоков EBYTE MA0x-xxCXxxx0 предусмотрено наличие до 4-х цифровых входов. В блоке MA01-AACX2240 присутствуют 2 из них. То или иное количество цифровых и аналоговых входов в различных моделях определяется распайкой соответствующих компонентов на типовой печатной плате серии MA0x-xxCXxxx0.
Производитель в официальной документации декларирует следующие параметры цифровых входов MA01-AACX2240:
Как вы видите, цифровые входы MA01-AACX2240 являются довольно функциональными и имеют множество параметров и настроек, в этой статье мы разберём программирование двух основных из них: собственно текущего состояния цифровых входов и значения их счётчиков. Ниже приведена выдержка из таблиц с этими параметрами.
Из этой таблицы видно, что данные, ассоциированные с цифровыми входами, распределены по двум диапазонам Modbus RTU регистров.
Discrete Inputs. 8-битные регистры, доступные только для чтения (код функции 0x02). Используются в MA01-AACX2240 для представления данных о состоянии DI входов.
Holding Registers. 16-битные регистры, доступные для чтения и записи (коды функций 0x03, 0x06, 0x10). Используются в MA01-AACX2240 для хранения настроек, текущих значений и т. п.
Программирование получения данных из этих регистров блока MA01-AACX2240 мы разберём далее в этой статье.
❯ Получение данных о текущем состоянии цифровых входов
Данные о текущем состоянии цифровых входов хранятся в 8-битных регистрах Discrete Inputs, доступных только для чтения. В таблице указаны 4 регистра (это для всей серии MA0x-xxCXxxx0), в нашем случае это 2 регистра 0х0000 и 0х0001.
0х0000 0х0001
Для управления блоком MA01-AACX2240, выступающего в качестве Modbus RTU слейва, мы будем использовать Arduino библиотеку ModbusMaster.
Примечание. Это статья из цикла о внешнем Modbus RTU блоке расширения MA01-AACX2240 и тут предполагается, что вы знакомы с предыдущими статьями этого цикла. Поэтому некоторые подробности и пояснения в этой статье я буду опускать.
В скетче определяем адреса регистров двух цифровых входов MA01-AACX2240.
#define ADR_DI_DI0 0 #define ADR_DI_DI1 1
И переменные для хранения текущего состояния цифровых входов.
byte stateDi0 = 0; byte stateDi1 = 0;
Полный код скетча, который реализует чтения регистров состояния цифровых входов на блоке MA01-AACX2240:
/* Lavritech V7.1 Lite (RS485 V1) EBYTE MA01-AACX2240 Modbus RTU DI example */ #include <Wire.h> #include <ModbusMaster.h> #define RS485_SerialNum 1 #define RS485_RX 16 #define RS485_TX 17 //#define RS485_DE -1 #define MODBUS_BAUD 9600 #define MODBUS_SLAVE_ID 32 #define REQ_DELAY 100 int cntOk = 0; int cntEr = 0; uint8_t result; HardwareSerial RsSerial(RS485_SerialNum); ModbusMaster RS; #define ADR_DI_DI0 0 #define ADR_DI_DI1 1 byte stateDi0 = 0; byte stateDi1 = 0; void setup() { Serial.begin(115200); Serial.println(); Serial.println(F("Start MA01-AACX2240 DI example...")); RsSerial.begin(MODBUS_BAUD, SERIAL_8N1, RS485_RX, RS485_TX); RS.begin(MODBUS_SLAVE_ID, RsSerial); RS.preTransmission(preTransmission); RS.postTransmission(postTransmission); } // setup void preTransmission() {;} void postTransmission() {;} void displayInfo() { Serial.print(F(" ok:")); Serial.print(cntOk); Serial.print(F("/")); Serial.print(cntEr); Serial.print(F(" DI:")); Serial.print(stateDi0); Serial.print(stateDi1); Serial.println(); } word readDi1(word shift) { word res = 0; result = RS.readDiscreteInputs(shift, 1); if (result == RS.ku8MBSuccess) { res = RS.getResponseBuffer(0); cntOk++; } else { cntEr++; } delay(REQ_DELAY); return res; } void loop() { stateDi0 = readDi1(ADR_DI_DI0); stateDi1 = readDi1(ADR_DI_DI1); displayInfo(); delay(1000); } // loop
Получением данных о состоянии цифровых входов занимается функция readDi1().
word readDi1(word shift) { word res = 0; result = RS.readDiscreteInputs(shift, 1); if (result == RS.ku8MBSuccess) { res = RS.getResponseBuffer(0); cntOk++; } else { cntEr++; } delay(REQ_DELAY); return res; }
Результат работы нашего скетча (рамкой выделены запросы с замкнутым нулевым (первым) цифровым входом):
Видно, что все запросы проходят успешно и нет ни одной ошибки проведения операций чтения DI регистров с блока MA01-AACX2240. Обратите внимание, что количество запросов возрастает на 2 за один цикл. Это не очень эффективно и далее мы попробуем решить эту проблему.
❯ Чтение состояния DI за 1 запрос
Функция readDiscreteInputs() позволяет читать сразу несколько последовательно расположенных регистров и при помощи неё можно получить 2 значения за один запрос.
Я не буду приводить здесь полный код скетча чтения состояния 2-х входов за 1 запрос, он практически полностью повторяет предыдущий, приведу только изменения в коде.
Вызываем функцию чтения состояния 2-х входов за 1 запрос, передавая ей в качестве параметра адрес цифрового входа #0 (#1 идёт последовательно за ним).
readDi2(ADR_DI_DI0);
Код самой функции чтения состояния 2-х входов за 1 запрос. Здесь последовательно читаются 2 байта из приёмного буфера.
void readDi2(word shift) { result = RS.readDiscreteInputs(shift, 2); if (result == RS.ku8MBSuccess) { stateDi0 = bitRead(RS.getResponseBuffer(0), 0); stateDi1 = bitRead(RS.getResponseBuffer(0), 1); cntOk++; } else { cntEr++; } delay(REQ_DELAY); }
Результат работы модернизированного скетча — как вы видите, результат тот же, только для его получения используется всего один запрос, вместо двух, что гораздо более эффективно.
❯ Получение значений счётчиков цифровых входов
Теперь попробуем получить значения счётчиков цифровых входов. Здесь нам уже придётся иметь дело с 16-битными Holding Registers (см. таблицу выше).
Определяем адреса регистров, хранящих текущие значения счётчиков цифровых входов MA01-AACX2240.
#define ADR_HR_COUNT0 2527 #define ADR_HR_COUNT1 2528
И переменные для их хранения.
word count0 = 0; word count1 = 0;
Далее создаём скетч, реализующий получение значений счётчиков цифровых входов MA01-AACX2240:
/* Lavritech V7.1 Lite (RS485 V1) EBYTE MA01-AACX2240 Modbus RTU DI count example */ #include <Wire.h> #include <ModbusMaster.h> #define RS485_SerialNum 1 #define RS485_RX 16 #define RS485_TX 17 //#define RS485_DE -1 #define MODBUS_BAUD 9600 #define MODBUS_SLAVE_ID 32 #define REQ_DELAY 100 int cntOk = 0; int cntEr = 0; uint8_t result; HardwareSerial RsSerial(RS485_SerialNum); ModbusMaster RS; #define ADR_HR_COUNT0 2527 #define ADR_HR_COUNT1 2528 word count0 = 0; word count1 = 0; void setup() { Serial.begin(115200); Serial.println(); Serial.println(F("Start MA01-AACX2240 DI count example...")); RsSerial.begin(MODBUS_BAUD, SERIAL_8N1, RS485_RX, RS485_TX); RS.begin(MODBUS_SLAVE_ID, RsSerial); RS.preTransmission(preTransmission); RS.postTransmission(postTransmission); } // setup void preTransmission() {;} void postTransmission() {;} word readHr1(word shift) { word res = 0; result = RS.readHoldingRegisters(shift, 1); if (result == RS.ku8MBSuccess) { res = RS.getResponseBuffer(0); cntOk++; } else { cntEr++; } delay(REQ_DELAY); return res; } void displayInfo() { Serial.print(F(" ok:")); Serial.print(cntOk); Serial.print(F("/")); Serial.print(cntEr); Serial.print(F(" c0:")); Serial.print(count0); Serial.print(F(" c1:")); Serial.print(count1); Serial.println(); } void loop() { count0 = readHr1(ADR_HR_COUNT0); count1 = readHr1(ADR_HR_COUNT1); displayInfo(); delay(1000); } // loop
Непосредственно получением значений счётчиков занимается функция readHr1().
word readHr1(word shift) { word res = 0; result = RS.readHoldingRegisters(shift, 1); if (result == RS.ku8MBSuccess) { res = RS.getResponseBuffer(0); cntOk++; } else { cntEr++; } delay(REQ_DELAY); return res; }
Вот результат работы нашего скетча:
Здесь хорошо виден принцип работы счётчиков цифровых входов MA01-AACX2240: при поступлении импульсов значение счётчиков возрастает через усредняющее «скользящее окно» в 6 значений, за которое отвечает регистр «All channel filter» (от 1 до 16, по умолчанию 6), который тоже можно изменять и подстраивать под ваши задачи.
❯ Улучшения и прочие DI регистры
Чтобы не загромождать статью, создание скетча, получающего 2 значения счётчиков цифровых входов за один запрос, я оставляю вам в качестве домашнего задания. Если вы внимательно прочитали эту статью, то для вас не составит труда создать скетчи для работы с остальными четырьмя регистрами (параметрами), ассоциированными DI входами блока MA01-AACX2240.
❯ Заключение
Мы уже научились управлять реле и получать данные с цифровых входов блока MA01-AACX2240, далее нас ожидает ещё более захватывающее исследование — работа с аналоговыми входами, в которой нам поможет «волшебная коробочка» — генератор тока и напряжения QH-VISG2-ED.
ссылка на оригинал статьи https://habr.com/ru/company/timeweb/blog/717316/
Добавить комментарий