• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

ESP8266 как Modbus Master

Alexandr.Seleznev

New member
Всем привет.
Подключаю esp8266 NodeMCU как мастера к слэйву. При помощи библиотеки хочу прочитать значения регистров слэйва. Не понимаю почему не выводит значения регистров.
Настройки подключения(скорость, четность, стоп биты) подключены правильно. ESP подключаю преобразователем UART -> RS485 на MAX485.
Слэйвом выступает счетчик энергии map3et.

C++:
/*
  Modbus Library for Arduino Example - Modbus RTU Client
  Read Holding Registers from Modbus RTU Server in blocking way
  ESP8266 Example
 
  (c)2020 Alexander Emelianov (a.m.emelianov@gmail.com)
  https://github.com/emelianov/modbus-esp8266
*/

#include <ModbusRTU.h>
#include <SoftwareSerial.h>

#define SLAVE_ID 39
#define FIRST_REG 128
#define REG_COUNT 2
// MODBUSRTU_REDE_SWITCH_US 1200
#define DE_RE 12 //D6  For MAX485 chip
#define RX 3      // RX Node MCU
#define TX 1      // TX Node MCU

SoftwareSerial S(RX, TX);
ModbusRTU mb;

bool cb(Modbus::ResultCode event, uint16_t transactionId, void* data) { // Callback to monitor errors
  if (event != Modbus::EX_SUCCESS) {
    Serial.print("Request result: 0x");
    Serial.println(event, HEX);
  }
  return true;
}

void setup() {
  Serial.begin(115200);
  S.begin(9600, SWSERIAL_8N2, RX, TX);
  mb.begin(&S, DE_RE);
  mb.master();
}

//uint16_t response = 0;
uint16_t regs[REG_COUNT];

void loop() {
  // uint16_t regs;
  if (!mb.slave()) {    // Check if no transaction in progress
    mb.readHreg(SLAVE_ID, FIRST_REG, regs, REG_COUNT, cb); // Send Read Hreg from Modbus Server
    while(mb.slave()) { // Check if transaction is active
      mb.task();
      yield();
      //delay(20);
    }
    //delay(1000);
    //Serial.print("response = "); Serial.println(response);
    Serial.print("regs = "); Serial.println(regs[0]);
  }
  delay(1000);
  //mb.task();
}
 

Вложения

pvvx

Активный участник сообщества
1. Следует проверить полярность подключения проводков. На шине RS-485 два провода, один типа минус, другой плюс.
Желательно осциллографом или другим логгером, приемником RS-485 и т.д., сразу убедиться в правильной работе преобразователя и используемой Ардуино-детской библиотеке для игрушек.
2. Настроить Modbus в счетчике приложенной к нему программой.
 

pvvx

Активный участник сообщества
Далее, если будут получены хоть каткие-то результаты, требуется произвести анализ кода используемой библиотеки на соблюдение стандартов Modbus RTU по задержкам и переключениям направления шины, отработке межсимвольных пауз и интервалов между фреймами при включенном WiFi.
Т.к. они не будут соблюдаться, поиграться и выкинуть данное решение, заменив чем-то не игрушечным.
 

pvvx

Активный участник сообщества
Подключаю esp8266 NodeMCU как мастера к слэйву. При помощи библиотеки хочу прочитать значения регистров слэйва.
В указанной вами библиотеке не найдена установка регистра тишины на линии у UART ESP8266 (для вычисления пауз по спецификации Modbus RTU).
Так же не найдены никакие таймеры для анализа пауз между транзакциями в функциях приема и между приемом-передачей.
Вам придется это вписать самому или надеяться что имеющееся как-то иногда будет работать...
 

pvvx

Активный участник сообщества
У map3et мне не удалось найти полную спецификацию по работе устройства в Modbus RTU. А так-же проверок или сертификации шины Modbus RTU RS-485.

А для работы с устройством на шине Modbus RTU требуется значение максимального времени до ответа устройством.

Иначе послав запрос, придется ждать вечно и вся шина будет занята в вечном ожидании ответа? А если повторить запрос, через придуманную на обум паузу, то имеется большая вероятность вхождения в вечный цикл коллизии:

Запросили, ждем, пауза вышла, производим следующий запрос, а устройство в это время отвечает на прошлый. И так бесконечно, надеясь что драйверы шины RS-485 не перегреются работая друг на друга и другое устройство не словит в этом бардаке похожую для неё команду, т.к. CRC16 не панацея.

По этому в документации должно быть объявлена максимальная пауза до ответа устройством. И если пауза выходит, а ответ у устройства ещё не готов, то посылается короткий стандартный Modbus RTU ответ c идентификатором “Устройство занято”.
 

Alexandr.Seleznev

New member
Т.к. они не будут соблюдаться, поиграться и выкинуть данное решение, заменив чем-то не игрушечным.
Можете порекомендовать что-то не игрушечное? Вы имеете в виду заменить ESP или заменить библиотеку? Или возможно дописать настройки в текущую библиотеку?
И так бесконечно, надеясь что драйверы шины RS-485 не перегреются работая друг на друга и другое устройство не словит в этом бардаке похожую для неё команду, т.к. CRC16 не панацея.
Уже перегревалось.

Спасибо большое за столь развернутый ответ, Вы очень помогли!
 

pvvx

Активный участник сообщества
Это всего предупреждение. Как говорится - предупрежден значит вооружен.
У вас же не сертификация изделия, а игрушка на Arduino - для быстрого анализа возможностей и продумывания алгоритмов, демонстрации концепта - сгодится.
А для пром. применения или применения в других сферах, типа учета - не годится.
 

pvvx

Активный участник сообщества
Можете порекомендовать что-то не игрушечное?
Это сложно и обычно дорого. Не думаю что вам это надо.
Вы имеете в виду заменить ESP или заменить библиотеку? Или возможно дописать настройки в текущую библиотеку?
Там как не меняй, всё равно будут недочеты.
Основные, которые придется учесть - использование С++. Т.к. чип не имеет MMU, то придется отказаться от типа памяти "Heap" - динамического распределения кучи. Только статические буфера. Иначе дефрагментация и падение системы, перезагрузка.
А при использовании статических буферов во всех драйверах, включая WiFi - у вас не хватит памяти для поддержки по стандарту даже простого TCP сокета.
Придется анализировать все вызовы функций с запросом памяти и строить так, чтобы не возникло фрагментации. Для этого обычно сразу отказываются от C++ и строят всё на СИ.
И т.д.... типа перезагрузки всей системы для очистки памяти после выполнения пары функций...
 

pvvx

Активный участник сообщества
Другой метод, если используется динамическая память и нет аппаратного MMU - иметь объем памяти в несколько раз превышающий выполняемые задачи. Но это не имеет смысла, т.к. тогда проще распределить память статически.
По этому пример в Arduino с миганием светодиода не падает. А всё что посложнее не имеет никакой гарантии в стабильности работы.
 

pvvx

Активный участник сообщества
Вместо HEAP часто используют стек. Тогда каждый последующий вложенный вызов в некой функции не вызывает дефрагментации, т.к. когда произойдет выход из начальной функций, то память будет освобождена. Но это требует изменения всех алгоритмов в системе и распределения на поочередный вызов таких функций. Т.е. никакой мультизадачности.
Соответственно С++ и тут не нужен. Если только аккуратно применять его синтаксис, без использования памяти-зависимых функций. Но потребует большего внимания.
В итоге и рекомендуют использовать ESP-IDF с чиcтыми СИ функциями....
 

pvvx

Активный участник сообщества
Для ухода от проблем дефрагментации памяти много-много лет назад был придуман и создан MMU. Он есть во всех архитектурах современных процессоров и многих микроконтроллерах. Т.к. MMU транслирует память для CPU мелкими блоками, то всегда есть возможность набрать большой непрерывный по адресации для CPU фрагмент из кусочков, собранных из малых фрагментиков в памяти находящихся по разным физическим адресам. И как таковая дефрагментация становится невозможна. Это и использовано в С++.
 

pvvx

Активный участник сообщества
Начните c переписывания стека TCP/IP в ESP на соответствие стандарту, чтобы работать хотя-бы с одним TCP сокетом :)

Тогда вам придется содержать в памяти структуры TCP с состоянием TIME_WAIT. И каждые несколько ms сравнивать – вышел или нет таймаут у конкретной структуры в 4 минуты (это нормы TCP/IP в RFC).

За 4-ре минуты при имеющейся скорости WiFi у ESP таких структур может быть создано к 10 тысячам за секунду. Соответственно требуется объем памяти для их содержания на 4 минуты – это 2400000 таких структур. В Lwip одна такая структура использует от сотни байт. Далее считать необходимый объем памяти для поддержки TCP/IP по стандарту для ESP бессмысленно.

Это только одна мелкая частичка стандарта TCP/IP… вырезанная в Arduino и приводящая к приколам, а так-же глюкам у устройств типа роутеров и т.д. по всему пути соединений.
 

pvvx

Активный участник сообщества
Какие могут быть методы уменьшить вероятность глюков в Arduino ESP.

Для TCP/IP соединений необходимо запретить открытие соединений чаще раз в несколько секунд.

Не использовать соединений с эксплорерами, т.к. при открытии страницы они открывают сразу от 4-х соединений для ускорения, а ESP не может обслужить более десятка при подготовке и переписывании кода ESP-IDF. Любой тест сервера HTTP на ESP показывает ошибки при множественных соединениях.

Так же запретить переподключение к внешней WiFi АP с паузой менее 4-х минут.

Этим частично уменьшится вероятность возникновения TIME_WAIT, но не спасет от других глюков.
 
Сверху Снизу