EBYTE MA01-AACX2240: программирование цифровых входов

—

от автора

В предыдущих статьях мы познакомились с замечательным внешним 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/


Комментарии

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

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