Перейти к содержимому

Доброго здравия, уважаемые друзья и читатели!

Сегодня на мини-обзоре небольшая платка, которая называется R4IOI16 – это расширитель GPIO на 16 входов или выходов, предназначенная для работы с шиной RS485 и протоколом Modbus RTU.  Плата имеет 16 цифровых GPIO, которые можно использовать либо как входы, либо как выходы. Производится она китайской компанией Eletechsup, которая, к слову сказать, в последнее время выбросила на рынок довольно большой ассортимент подобных RS485 – адаптеров, на всякий вкус и цвет.

Обычно я пишу обзоры на то, что мне самому интересно или необходимо для каких-либо целей. Для чего мне понадобилась эта плата? Лично я хочу засунуть её вместе с твердотельными реле в коммутационную коробку освещения, дабы можно управлять освещением с центрального контроллера, и при этом не тянуть к нему силовые провода. На мой взгляд она идеально подходит для этого.

 


Общие сведения

Обозреваемое устройство представляет собой небольшую печатную плату размером 50 х 25 мм с маской зеленого цвета:

Нажмите для увеличения

На плате расположены: микроконтроллер неизвестного роду-племени с маркировкой 2G8T71B, RS485-трансивер BL3085, линейный стабилизатор напряжения +5В 1А 78M05, и некоторые другие элементы обвязки. Плата имеет два ряда контактов с шагом 2,54 мм, при этом стандартной “гребенки”, так любимой китайскими производителями, в комплекте не было.

На стороне входов / выходов через каждые четыре сигнальных вывода GPIO расположена контактная площадка GND. Все входы-выходы подключены к микроконтроллеру через резисторы 470 Ом, что позволяет подключать к плате светодиоды или оптроны напрямую, без использования дополнительных внешних резисторов.

Допустимый ток через выводы не указан, но в описании другой подобной платы я встречал значение максимального тока до 50 мА на вывод – стоит ли этому доверять в данном случае – не знаю. С использованием резисторов 470 Ом при напряжении 5В максимум, что удастся от нее получить – это примерно 10 мА. Разумеется, для управления мощной нагрузкой потребуется дополнительное реле или электронный ключ.

Вход питания VIN (6 ~ 25 В) защищен от ошибочного подключения диодом Шоттки, при этом можно “снять” выходные 5В со встроенного стабилизатора. Либо можно подать 5В с внешнего источника, если таковой имеется, но защиты от переполюсовки уже нет. Допускается только один вариант источника питания одновременно (то есть не нужно подавать питание одновременно и на VIN и на контакт 5V).

RS485-трансивер BL3085 частично защищен супрессорами, но положенных в этом случае полупроводниковых самовосстанавливающихся предохранителей нет. Поэтому в случае случайной длительной подачи повышенного напряжения на линии А или В, супрессоры, скорее всего, выгорят.

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

Для сброса на заводские настройки включите плату и замкните контакты RES на время около 5 секунд. Или отправьте команду в соответствующий регистр, о чем ниже.

 


Технические характеристики

  • Напряжение питания (допускается только один вариант из перечисленных ниже):
    • DC 6-25 В (с защитой от переполюсовки на диоде D1)
    • DC 4-5 В (без защиты)
  • Потребляемый ток: 6 мА (я так понимаю без учета тока выходов)
  • Режим входа: поддерживаются уровни TTL 3,3 В/5 В, два активных уровня: низкий уровень (по умолчанию) или высокий уровень
  • Режим выхода: уровни TTL 5 В, два активных уровня: низкий уровень (по умолчанию) или высокий уровень
  • Скорость передачи: 1200, 2400, 4800, 9600(default), 19200, 38400, 57600, 115200 baud; None/Odd/Even Parity

 


Режимы работы GPIO

Режим работы выводов микроконтроллера (на вход или выход) конфигурируется не программно, а с помощью перемычек – М1 ~ M4.

А вот активные уровни – уже программно, с помощью регистров Modbus, о чем будет рассказано ниже.

  • 16 DI – все 16 выводов используются как входы
  • 16 DO – все 16 выводов используются как выходы
  • 8 DI + 8 DO – первая половина (1 ~ 8 контакты) используются как входы, вторая половина (9~16 контакты) – как выходы
  • 4 DI + 12 DO – четыре входа и двенадцать выходов
  • 12 DI + 4 DO – двенадцать входов и четыре выхода

Изображение ниже иллюстрирует эти варианты:

Можно самому переключать эти режимы, а можно купить готовую платку с перемычкой в нужном месте. На обратной стороне можно найти мини-инструкцию, как переключать режимы входов-выходов данной платы и пояснительные надписи к контактам:

 

Все входы-выходы подключены к микроконтроллеру через резисторы 470 Ом, что позволяет подключать к плате светодиоды или оптроны напрямую, без использования дополнительных внешних резисторов.

По умолчанию на всех входах и выходах настроен активный низкий уровень, то есть подключенный светодиод будет светиться при 0 на выходе, а для считывания 1 на входе необходимо замкнуть выбранный вывод платы на землю (G).

 


Взаимосвязь входов и выходов

Плата имеет довольно интересную особенность, если настроена на режим 8DI-8DO (может быть и на 4DI-12DO и 12DI-4DO – я не проверял) – входы можно заставить управлять выходами непосредственно “на месте действия”, причем сделать это можно разными способами. Все входы и выходы объединяются в пары: DI 1 управляет выходом DO 9, DI 2 -> DO 10, …, DI 8 -> DO 16.

  • По умолчанию взаимосвязь входов и выходов отключена – все работает независимо, то есть командами modbus вы переключаете выходы и читаете их состояние и состояние входов.
  • Самоблокировка – первый активный сигнал на входе, например DI 1, включает соответствующий ему выход DO 9. Повторный сигнал – выключает. То есть действует как кнопка с самоблокировкой. Очень удобно использовать для управления освещением как с кнопки, так и по команде “умного дома”.
  • Защелка – любой активный сигнал на входе, например DI 1, включает соответствующий ему выход DO 9. Триггер. Отключить выход можно только по команде modbus. Можно использовать для обнаружения каких-либо событий. Но можно настроить регистр 244 так, чтобы выходы автоматически отключались через заданное время.
  • Кратковременный – при появлении на входе, например DI 1, активного уровня, на соответствующем ему выходе, например DO 9, на примерно полсекунды появится соответствующий активный уровень, а потом выход будет вновь отключен.
  • Переключатель – здесь входы и выходы связаны уже парами. Например DI 1 включает DO 9, но выключает DO 10; а DI 2 включает DO 10, но при этом выключает DO 9.
  • Повторитель (выход = вход) – как вы, наверное, уже догадались, активный уровень на входе повторяет то же самое на соответствующем выходе. Просто как кнопка без фиксации.

Разумеется, вся эта автоматика не отменяет управление через команды modbus. 

 


Регистры modbus

Плата имеет на редкость хорошую документацию (на английском). Поэтому получить необходимую информацию о регистрах не составило особого труда. Итак…

Параметры связи по умолчанию: 9600 Baud, 8 Data bits, None Parity, 1 Stop Bit

Модуль поддерживает несколько разных команд (в зависимости от варианта использования M1 ~ M4 этот список может отличаться):

  • 01 (hex 0x01) :: Read coils – чтение состояний выходов DO
  • 02 (hex 0x02) :: Read discrete inputs – чтение состояний входов DI
  • 03 (hex 0x03) :: Read holding registers – чтение функциональных регистров (параметров устройства) и регистров состояний DI и DO в виде битовой маски
  • 05 (hex 0x05) :: Write single coil – одиночное изменение состояний выходов DO
  • 06 (hex 0x06) :: Write single registers – изменение функциональных регистров (параметров устройства) по одному
  • 15 (hex 0x0F) :: Write multiple coils – множественное изменение состояний выходов DO 
  • 16 (hex 0x10) :: Write multiple registers – изменение сразу нескольких функциональных регистров (параметров устройства)

Сводная таблица регистров приведена ниже. Обратите внимание, что в зависимости от выбранного режима (перемычками M1 ~ M4), диапазоны адресов могут быть изменены или вовсе отсутствовать.

Команда Адрес или диапазон Допустимые значения Описание
Цифровые выходы DO (если есть)
01 (0x01) 1-16
(0x0001 – 0x000F)
0 или 1 Чтение состояния одного цифрового выхода DO
05 (0x05) Изменение состояния одного цифрового выхода DO
15 (0x0F) Изменение состояния нескольких цифровых выходов DO
03 (0x03) 128 (0x0080) 0 ~ 65535 Чтение состояния всех выходов DO в виде битовой маски 0-15 бит
06 (0x06) Изменение состояния всех выходов DO в виде битовой маски 0-15 бит
Цифровые входы DI (если есть)
02 (0x02) 1-16
(0x0001 – 0x000F)
0 или 1 Чтение состояния цифрового входа DI
03 (0x03) 144 (0x0090) 0 ~ 65535 Чтение состояния всех входов DI в виде битовой маски 0-15 бит
Настройки устройства (03 – чтение регистра, 06 / 16 – запись регистра)
03 (0x03)
06 (0x06)
16 (0x10)
243
(0x00F3)
0 ~ 65535 Плата будет включена автоматически после подачи питания, если в течение заданного времени не будет получена какая-либо команда.
0: Не включать автоматически (по умолчанию)
1: Включить через 1 секунду без какой-либо команды
2: Включить через 2 секунды без какой-либо команды
100: Включить через 100 секунд без какой-либо команды
Максимальная задержка включения – 65535 секунд
03 (0x03)
06 (0x06)
16 (0x10)
244
(0x00F4)
0 ~ 65535 Автоматическое отключение всех выходных портов (установка состояния в OFF), если в течение заданного периода времени не будет получена какая-либо команда.
0: Не закрывать автоматически выходные порты (по умолчанию)
1: Закрывает выходы, если в течение 1 секунды не поступает команда
2: Закрывает выходы, если в течение 2 секунд не поступает команда
100: Закрывает выходы, если в течение 100 секунд не поступает команда
Максимальная задержка выключения – 65535 секунд
03 (0x03)
06 (0x06)
16 (0x10)
245
(0x00F5)
0x0000
0x0001
Активный уровень входных портов
0x0000 (NPN) Активный уровень низкий (по умолчанию)
0x0001 (PNP) Активный уровень высокий
03 (0x03)
06 (0x06)
16 (0x10)
246
(0x00F6)
0x0000
0x0001
Активный уровень выходных портов
0x0000 (NPN) Активный уровень (ON) низкий (по умолчанию)
0x0001 (PNP) Активный уровень (ON) высокий
03 (0x03)
06 (0x06)
16 (0x10)
248
(0x00F8)
0x0000-0x0255 Автоматическое отправка данных о состоянии цифровых входов (DI)
0: Только по запросу хоста (по умолчанию)
1-255: Автоматическая отправка по таймеру, единица измерения — секунда
1: Отчет каждую секунду
2: Отчет каждые 2 секунды
10: Отчет каждые 10 секунд
Максимальный интервал 255 секунд
03 (0x03)
06 (0x06)
16 (0x10)
250
(0x00FA)
0x0000-0x0005 Связь входов и выходов
0x0000 Входы и выходы изолированы друг от друга (по умолчанию)
0x0001 Самоблокировка
0x0002 Защелка
0x0003 Кратковременный
0x0004 Переключатель (используется 2 входа)
0x0005 Повторитель (выход = вход)
Другие значения интерпретируются так же, как 0
06 (0x06) 251
(0x00FB)
0x0000 Сброс на заводские настройки
Например, если вы не знаете адрес устройства, можно отправить команду с широковещательным адресом 0xFF: FF 06 00 FB 00 00 ED E5
03 (0x03)
06 (0x06)
252
(0x00FC)
0x0000-0x1000 Время ответа на команды
Временной интервал для ответа на команды управления (единица: миллисекунды)
Значение настройки: 0-1000
03 (0x03)
06 (0x06)
253
(0x00FD)
0x0001-0x0254 Адрес RS485 (идентификатор подчиненного устройства)
Если адрес не известен (утерян), можно отправить команду на широковещательный адрес 0xFF
03 (0x03)
06 (0x06)
254
(0x00FE)
0x0000-0x0255 Скорость передачи данных
0 = 1200, 1 = 2400,  2 = 4800, 3 = 9600 (default), 4 = 19200, 5 = 38400, 6 =57600, 7 = 115200
Любое другое значение: сброс на заводские настройки
03 (0x03)
06 (0x06)
255
(0x00FF)
0x0000-0x0002 Контроль четности
0 = None Parity, 1 = Odd Parity, 2 = Even Parity

 

Эту таблицу можно проиллюстрировать “картами” из программы Modbus Poll:

Здесь стоит поподробнее остановится на некоторых регистрах – опциях.

243 (0x00F3)

Автовключение. Вот честно говоря, не очень понял, для чего эта опция предназначена. Если в данном регистре 0, то при подаче питания ничего не происходит. Если больше 0 – через заданное время начинает мигать светодиод – плата как бы пытается сама достучаться до хоста? Состояние входов и выходов никак не меняется. И что это дает?

244 (0x00F4)

Автоматическое отключение всех выходных портов. Более интересная опция. Если во время работы неожиданно была разорвана связь с хостом (мыши провод сгрызли), то спустя заданное время все выходы будут переведены в режим OFF. Если попытаться включить выходы с помощью входов – то они почти немедленно будут выключены. Можно использовать для того, чтобы при потере связи с контроллером управления вся нагрузка отключалась автоматически.

245 (0x00F5)

Активный уровень входных портов. Если в регистре записан 0, то при низком уровне на входе (замыкании его на “землю”) программа будет считать, что на входе логическая единица. Если в регистре записана 1, то для активации входа необходимо подать 5В на соответствующий контакт платы.

246 (0x00F6)

Активный уровень выходных портов. Если в регистре записан 0, то при отправке в соответствующий выход команды на включение, на нем будет установлен низкий уровень и наоборот. Если в регистре записана 1, то запись в соответствующий выход логической единицы приведет к появлению на контакте напряжения 5В.

 

Про взаимосвязь входов и выходов я уже написал выше.

 


Работа с платой на ESP32

В качестве примера я написал небольшую программку, для которой использовал ESP-IDF API, которое так и называется – ESP_MODBUS. Про нее я уже писал тут: Работа с шиной RS485 и протоколом Modbus RTU на ESP32. Поэтому подробно весь процесс я описывать не буду, а приведу лишь код демонстрирующий чтение состояния входов из регистра 144 (0x0090):

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "mbcontroller.h"
#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_err.h"

// Хэендл мастер-контроллера
static void *master_handle = NULL;

void app_main(void)
{
  // Настраиваем modbus контроллер
  mb_communication_info_t modbus_config = {0};
  modbus_config.ser_opts.port = UART_NUM_1;
  modbus_config.ser_opts.mode = MB_RTU;
  modbus_config.ser_opts.baudrate = 9600;
  modbus_config.ser_opts.parity = MB_PARITY_NONE;
  modbus_config.ser_opts.response_tout_ms = 1000;
  modbus_config.ser_opts.data_bits = UART_DATA_8_BITS;
  modbus_config.ser_opts.stop_bits = UART_STOP_BITS_1;

  // Создаем master-контроллер на COM-порту
  esp_err_t err = mbc_master_create_serial(
    &modbus_config,   // Указантель на config
    &master_handle    // Указатель на переменную, в которую будет записан хендл контроллера
  );
  if ((err != ESP_OK) || (master_handle == NULL)) {
    ESP_LOGE("MODBUS", "MB controller initialization failure: %d %s", (int)err, esp_err_to_name(err));
    return;
  };

  // Настраиваем выводы COM-порта
  err = uart_set_pin(
    UART_NUM_1,       // Номер COM-порта
    17,               // Номер вывода TXD
    16,               // Номер вывода RXD
    -1,               // Номер вывода RTS
    -1                // Номер вывода CTS
  );
  if (err != ESP_OK) {
    ESP_LOGE("MODBUS", "UART1 set pins failure: %d %s", (int)err, esp_err_to_name(err));
    return;
  };

  // Устанавливаем режим Half Duplex для COM-порта
  err = uart_set_mode(
    UART_NUM_1,     // Номер COM-порта
    UART_MODE_RS485_HALF_DUPLEX // Режим Half Duplex RS485
  );
  if (err != ESP_OK) {
    ESP_LOGE("MODBUS", "UART1 set mode failure: %d %s", (int)err, esp_err_to_name(err));
    return;
  };

  // Запускаем modbus контроллер
  err = mbc_master_start(
    master_handle     // Указатель на хендл контроллера
  );
  if (err != ESP_OK) {
    ESP_LOGE("MODBUS", "MB controller start failure: %d %s", (int)err, esp_err_to_name(err));
    return;
  };

  ESP_LOGI("MODBUS", "Modbus started");

  // Основной цикл
  while (1)
  {
    // Буфер под получаемые данные
    uint16_t buffer[1];

    // Настраиваем параметры запроса
    mb_param_request_t request = {
      .slave_addr = 0x01,             // Адрес slave устройства
      .command = 0x03,                // Код команды
      .reg_start = 0x0090,            // Начальный адрес регистра
      .reg_size = 1                   // Количество регистров подряд
    };

    // Отправляем запрос
    err = mbc_master_send_request(
      master_handle,                  // Указатель на хендл контроллера
      &request,                       // Параметры запроса
      &buffer[0]                      // Указатель на начало буфера
    );
    if (err == ESP_OK) {
      // Выводим состояние входов в лог
      ESP_LOGI("MODBUS", "Read register: 0x%04X", (int)buffer[0]);
    } else {
      ESP_LOGE("MODBUS", "Read slave failure: %d %s", (int)err, esp_err_to_name(err));
    };

    // Ожидание
    vTaskDelay(pdMS_TO_TICKS(1000));
  }

  ESP_LOGI("MAIN", "Program stopped");
}

 

Результаты её работы:

I (312) main_task: Calling app_main()
I (312) uart: queue free spaces: 20
I (312) mb_port.serial: mbm_rtu@0x3ffb5be0, suspend port from task.
I (312) MODBUS: Modbus started
I (332) MODBUS: Read register: 0x0020
I (1352) MODBUS: Read register: 0x0020
I (5432) MODBUS: Read register: 0x0020
I (6442) MODBUS: Read register: 0x0000
I (7462) MODBUS: Read register: 0x0008
I (8482) MODBUS: Read register: 0x0008
I (9492) MODBUS: Read register: 0x0008
I (10512) MODBUS: Read register: 0x0008
I (11532) MODBUS: Read register: 0x0008

Вначале был замкнут вывод 7, потом я переставил перемычку на вывод 4.

 

На этом разрешите откланяться, с вами был Александр aka kotyara12. Благодарю за внимание.


Пожалуйста, оцените статью:
[ 5 из 5, всего 1 оценок ]

-= Каталог статей (по разделам) =-   -= Архив статей (подряд) =-

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

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