ESP32 + RS-485(Mudbus RTU) = работает
- Войдите на сайт для отправки комментариев
Втр, 27/03/2018 - 10:47
Приветствую.
Собственно столкнулся с задачей, надо считать при помощи ESP32 данные из промышленного контроллера OWEN МВ110-8А(использую MAX485).
Пока что не одна библиотека даже не заставила мигнуть индикатор RS-485 на Овене.
Пробовал считать при помощи Arduino Nano - без проблем, библиотека SimpleModbusMaster справляется на ура, под ESP32 компилится, но переводит состояние ножки RE/DE раз в 20 медленее.
Может кто-то сталкивался с подобными делами, пусть даже на ESP8266?
Чуть позже сделаю фото осциллограм, что происходит.
OFFTOP: Привіт, друже, рад видеть ))).
По теме сказать нечего, моя ESP32 где-то в дороге ещё...
Araris - здоровенькі були.
А если конкретнее - к Овену подключен промышленный термодатчик, и стоит задача получить от Овена по интерфейсу RS-485 температуру которую она измеряет.
Вот этот код на ардуино нано работает так как мне нужно:
/* The example will use packet1 to read a register from address 0 (the adc ch0 value) from the arduino slave (id=1). It will then use this value to adjust the brightness of an led on pin 9 using PWM. It will then use packet2 to write a register (its own adc ch0 value) to address 1 on the arduino slave (id=1) adjusting the brightness of an led on pin 9 using PWM. */ unsigned long previousMillis = 0; // will store last time LED was updated // constants won't change: const long interval = 1; // interval at which to blink (milliseconds) #include <SimpleModbusMaster.h> //////////////////// Port information /////////////////// #define baud 9600 #define timeout 1000 #define polling 200 // скорость опроса по модбус #define retry_count 0 #define TxEnablePin 25 // Tx/Rx пин RS485 int16_t val1 = 0; int16_t val2 = 0; int16_t val3 = 0; int16_t val4 = 0; int32_t val5 = 0; int32_t val6 = 0; float VAL = 0.0; //Общая сумма доступной памяти на ведущем устройстве, чтобы хранить данные //Локальный регистр это регистры хранения в памяти мастера тоесть масив регистров с адресами от 0 до 29 //ВСЕГО 30 это важно иначе работать не будет всетаки это ардуино а не плк #define TOTAL_NO_OF_REGISTERS 10 // Это самый простой способ для создания новых пакетов // Добавить столько, сколько вы хотите. TOTAL_NO_OF_PACKETS // обновляется автоматически. enum { PACKET1, // PACKET2, // PACKET3, TOTAL_NO_OF_PACKETS // leave this last entry }; // Масив пакетов модбус Packet packets[TOTAL_NO_OF_PACKETS]; // Массив хранения содержимого принятых и передающихся регистров unsigned int regs[TOTAL_NO_OF_REGISTERS]; /* float convert_uint_to_float(unsigned int hw, unsigned int lw) { union { float f; unsigned short i[2]; } convert_float_uint; convert_float_uint.i[0] = lw; convert_float_uint.i[1] = hw; return (convert_float_uint.f); } */ void setup() { // инициализируем протокол модбус //Valid modbus byte formats are: // SERIAL_8N2: 1 start bit, 8 data bits, 2 stop bits // SERIAL_8E1: 1 start bit, 8 data bits, 1 Even parity bit, 1 stop bit // SERIAL_8O1: 1 start bit, 8 data bits, 1 Odd parity bit, 1 stop bit modbus_configure(&Serial, baud, SERIAL_8N1, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS, regs); // Настраиваем пакеты // Шестой параметр - это индекс ячейки в массиве, размещенном в памяти ведущего устройства, в которую будет // помещен результат или из которой будут браться данные для передачи в подчиненное устройство. В нашем коде - это массив reg // Пакет,SLAVE адрес,функция модбус,адрес регистра,количесво запрашиваемых регистров,локальный адрес регистра. // modbus_construct(&packets[PACKET1], 100, READ_COIL_STATUS, 48, 1, 0); // modbus_construct(&packets[PACKET2], 100, READ_INPUT_STATUS, 48, 1, 1); // modbus_construct(&packets[PACKET3], 100, READ_HOLDING_REGISTERS, 48, 1, 2); modbus_construct(&packets[PACKET1], 16, READ_HOLDING_REGISTERS, 0, 6, 0); // modbus_construct(&packets[PACKET2], 50, READ_HOLDING_REGISTERS, 49, 1, 1); // modbus_construct(&packets[PACKET3], 50, READ_HOLDING_REGISTERS, 50, 1, 2); // modbus_construct(&packets[PACKET2], 14, READ_HOLDING_REGISTERS, 11, 1, 1); // modbus_construct(&packets[PACKET3], 15, READ_HOLDING_REGISTERS, 11, 1, 1); // modbus_construct(&packets[PACKET4], 16, READ_HOLDING_REGISTERS, 11, 1, 1); // modbus_construct(&packets[PACKET5], 17, READ_HOLDING_REGISTERS, 11, 1, 1); // Пакет,SLAVE адрес,функция модбус,адрес регистра,количесво запрашиваемых регистров,локальный адрес регистра. //modbus_construct(&packets[PACKET3], 1, PRESET_MULTIPLE_REGISTERS, 2, 1, 2); //modbus_construct(&packets[PACKET4], 1, PRESET_MULTIPLE_REGISTERS, 3, 1, 3); } void loop() { unsigned long currentMillis = millis(); if (currentMillis - previousMillis >= interval) { // save the last time you blinked the LED previousMillis = currentMillis; modbus_update(); //val_f_1 = regs[0]; // чтение данных slave-master (slave адрес 4, в регистр 0) (регистр 0 находится на ардуине) val1 = regs[0]; val2 = regs[1]; val3 = regs[2]; val4 = regs[3]; val5 = regs[4]; val6 = regs[5]; VAL = val2 / 10.0; // Вывод в сериал // val2 = regs[1]; // чтение данных slave-master (slave адрес 100, регистр 1) // val3 = regs[2]; // чтение данных slave-master (slave адрес 100, регистр 2) // int val = val1 + val2 + val3; // if (val > 0){digitalWrite(LED1, HIGH);} // else{digitalWrite(LED1, LOW);}//если пришло 255 зажигаем светодиод // if (val1 > 0){digitalWrite(LED1, HIGH);} // if (val2 > 0){digitalWrite(LED1, HIGH);} // if (val3 > 0){digitalWrite(LED1, HIGH);} // else{digitalWrite(LED1, LOW);}//если пришло 255 зажигаем светодиод //unsigned int temp2; //regs[0] = analogRead(0); // запись данных master-slave //analogWrite(LED, regs[0]>>2); // чтение данных slave-master (ограничеть количесво бит данных числом 255) //regs[0] = 255; // запись данных master-slave (slave адрес 1, регистр 1) //temp2 = regs[3]; // чтение данных slave-master (slave адрес 1, регистр 4) //if (temp2 == 255){digitalWrite(LED1, HIGH);}else{digitalWrite(LED1, LOW);} Serial.print("val1="); Serial.println(val1); Serial.print("val2="); Serial.println(val2); Serial.print("val3="); Serial.println(val3); Serial.print("val4="); Serial.println(val4); Serial.print("val5="); Serial.println(val5); Serial.print("val6="); Serial.println(val6); Serial.print("Temperature = "); Serial.println(VAL); } }Синий луч - изменение состояния на RE/DE ножках микросхемы MAX485, жёлтый - TXD микроконтроллера.
Данный код под ESP32 компилится и работает, но ооочень медленно(обратите внимание на временную равёртку):
Мало того, ещё и переключает режим MAX485 раньше чем нужно:
Подключился к RS-485 через USB переходник и вижу что в шине нули:
Из-за особенностей реализации Serial.flush() для ESP32 переключение ноги прием-передача происходит раньше. Естественно, никакого вменяемого пакета клиент не получает, поскольку контрольная сумма не совпадает. Нужно изменять реализацию sendPack, в файле SimpleModbusMaster.cpp.
Например вот так
void sendPacket(unsigned char bufferSize) { if (TxEnablePin > 1) digitalWrite(TxEnablePin, HIGH); previousTimeout = millis(); // <=тут изменить for (unsigned char i = 0; i < bufferSize; i++) Serial.write(frame[i]); unsigned int timeout=((10000UL * (bufferSize+3))/(35000000/3_5)); // <=тут изменить while(millis()-previousTimeout<timeout) delay(1); // <=тут изменить if (TxEnablePin > 1) digitalWrite(TxEnablePin, LOW); previousTimeout = millis(); // initialize timeout delay }Да, функция Serial.flush() на ESP32 работает некорректно, это факт.
Пожалуйста.
Вот этот код чётко работает на Arduino Nano:
/* The example will use packet1 to read a register from address 0 (the adc ch0 value) from the arduino slave (id=1). It will then use this value to adjust the brightness of an led on pin 9 using PWM. It will then use packet2 to write a register (its own adc ch0 value) to address 1 on the arduino slave (id=1) adjusting the brightness of an led on pin 9 using PWM. */ #include <SimpleModbusMaster.h> //////////////////// Port information /////////////////// #define baud 9600 #define timeout 1000 #define polling 200 // скорость опроса по модбус #define retry_count 0 #define TxEnablePin 13 // Tx/Rx пин RS485 int16_t val1 = 0; int16_t val2 = 0; int16_t val3 = 0; int16_t val4 = 0; int32_t val5 = 0; int32_t val6 = 0; float VAL = 0.0; unsigned long previousMillis = 0; // will store last time LED was updated const long interval = 250; // interval at which to blink (milliseconds) //Общая сумма доступной памяти на ведущем устройстве, чтобы хранить данные //Локальный регистр это регистры хранения в памяти мастера тоесть масив регистров с адресами от 0 до 29 //ВСЕГО 30 это важно иначе работать не будет всетаки это ардуино а не плк #define TOTAL_NO_OF_REGISTERS 10 // Это самый простой способ для создания новых пакетов // Добавить столько, сколько вы хотите. TOTAL_NO_OF_PACKETS // обновляется автоматически. enum { PACKET1, // PACKET2, // PACKET3, TOTAL_NO_OF_PACKETS // leave this last entry }; // Масив пакетов модбус Packet packets[TOTAL_NO_OF_PACKETS]; // Массив хранения содержимого принятых и передающихся регистров unsigned int regs[TOTAL_NO_OF_REGISTERS]; void setup() { // инициализируем протокол модбус //Valid modbus byte formats are: // SERIAL_8N2: 1 start bit, 8 data bits, 2 stop bits // SERIAL_8E1: 1 start bit, 8 data bits, 1 Even parity bit, 1 stop bit // SERIAL_8O1: 1 start bit, 8 data bits, 1 Odd parity bit, 1 stop bit modbus_configure(&Serial, baud, SERIAL_8N1, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS, regs); modbus_construct(&packets[PACKET1], 16, READ_HOLDING_REGISTERS, 0, 6, 0); /* modbus_construct(&packets[PACKET1], a, READ_HOLDING_REGISTERS, b, c, d); a - SLAVE адрес b - адрес регистра c - колличество запрашиваемых регистров d - номер ячейки массива куда запишутся данные */ } void loop() { unsigned long currentMillis = millis(); if (currentMillis - previousMillis >= interval) { previousMillis = currentMillis; modbus_update(); val1 = regs[0]; val2 = regs[1]; // возвращает температуру в формате 123 - 12.3 градуса val3 = regs[2]; val4 = regs[3]; val5 = regs[4]; val6 = regs[5]; VAL = val2 / 10.0; // Вывод в сериал Serial.print("val1 = "); Serial.println(val1); Serial.print("val2 = "); Serial.println(val2); Serial.print("val3 = "); Serial.println(val3); Serial.print("val4 = "); Serial.println(val4); Serial.print("val5 = "); Serial.println(val5); Serial.print("val6 = "); Serial.println(val6); Serial.print("Temoerature = "); Serial.println(VAL,1); } }Ссылка на библиотеку SimpleModbusMasterV2rev2:
https://drive.google.com/file/d/1AQggEa6UnQLptpZGrw3t3ZvFZ_RR3wzH/view?usp=sharing
Вот так работа выглядит на осциллографе:
Жёлтый - TX ардуины, синий - RE/DE ножка микросхемы MAX485.
Вот такое наблюдаю в RS-485 шине при помощи переходника с RS-485 на USB.
Сейчас попробую аналогичным образом всё показать как на ESP32 этот же код крутится.
На ESP32 приведённая мною выше библиотека работает следующим образом:
В сериале ESP32 полная тишына, если подключить USB - RS-485 переходник то можно в шине увидить следующее:
Как видно одни нули.
На осциллографе следующая картина:
Обратите внимание на время через которее изменяется состояние на ножке RE/DE, это секунд 7-8 примерно, что наталкивает на мысль - библиотека работает значительно медленее чем ра Arduino Nano.
имхо, если на нано все работает - надо сделать из атмеги переходник для общения с ОВЕНом и все дела. Если пойдет библиотека, можно под переходник взять не атмегу328, а что-нибудь попроще, типа тини45 или 85
Пробовал считать при помощи Arduino Nano - без проблем
Схему подключения не скинете?
Да, вот:
Питаю микросхему от 3.3 В в случае с ESP32, и от 5-ти - Arduino.
имхо, если на нано все работает - надо сделать из атмеги переходник для общения с ОВЕНом и все дела. Если пойдет библиотека, можно под переходник взять не атмегу328, а что-нибудь попроще, типа тини45 или 85
Я думал над этим... Но хз как-то, городить горы микроконтроллеров это вообще как-то не это... Комильфо. Хотя в данный момент ничего не вижу кроме как сделать так.
На осциллограмме скорее всего шум. Что на шине МодБас, можно посмотреть ?
В "новой" библиотеке так же используется flush, так почему же она должна работать ? Я же дал вам пример исправления библиотеки, чем он вам не подошел ?
На осциллограмме скорее всего шум. Что на шине МодБас, можно посмотреть ?
В "новой" библиотеке так же используется flush, так почему же она должна работать ? Я же дал вам пример исправления библиотеки, чем он вам не подошел ?
Нет, не шум это, это шлёт ЕСПшка по мудбас, как я и говорил - в шине мудбас нули одни.
Спасибо большое за код, я подставлял его, всё равно ничего корректно не отрабатывало. Скорее всего где-то есть привязка к частоте микроконтроллера, у ардуины 16, а у есп32 240 МГц.
Не, нет никаких привязок. Вы можете в цикле с поднятой ножкой передача просто отправлять что то типа 0xAA и глянуть осциллографом что на шинах A и B ?
Да, вот:
Спасибо. Попробую Ваш скетч прикрутить к своей задаче, а то на библиотеке
ModbusRtu.hу меня пока не получается.Спасибо. Попробую Ваш скетч прикрутить к своей задаче, а то на библиотеке
ModbusRtu.hу меня пока не получается.Нет, это не мой скетч.
Не, нет никаких привязок. Вы можете в цикле с поднятой ножкой передача просто отправлять что то типа 0xAA и глянуть осциллографом что на шинах A и B ?
Без диференциирования интересует осциллограмма?
Лучше отдельно A-земля и B-земля...
Таки да, рекомендуютпитать от 5V.
Не, нет никаких привязок. Вы можете в цикле с поднятой ножкой передача просто отправлять что то типа 0xAA и глянуть осциллографом что на шинах A и B ?
Прошил код из этого поста в ESP32, на линии А относительно земли следующая картина(синий луч - А, жёлтый - RE/DE):
На линии В:
Вот такое с Вашей функцией, A:
На линии B:
Ножка направления явно рано сбрасывается
Попробуйте 11 строку в моей правке изменить :
А по правильности данных - не понятно. Меня вообще эти осциллограммы удивляют. У вас A и B обязаны быть противофазными. А я вижу обратное. Точно знаю что чудес не бывает. А у вас - чудо.
Вообщем принял решение выгрузить работу с RS-485 на ардуинку, устроил общение посредтвом UART и AT команд.
Надо же, нашёл библиотеку, которая завелась на ESP32, обзывается она - SimpleModbusMasterV2rev2_DUE.
Скетч:
Крутость этого решения заключается в том, что тут тебе и 2 ядра, и вай фай, и блютуз, АЦП и ЦАП... Я в своих наработках использую одно ядро под RS-485 а второе под простенький вебсервер, и ещё куча процессорного времени есть в запасе. ESP32 можная штука, это факт.
Ирония заключается в том, что когда вообщем всё сделал уже на ардуине в формате АТ-комманд, случайно наткнулся на эту библиотеку, месяц тупежа по сути.
Предлагаю изменить название темы на "ESP32 + RS-485(Mudbus RTU) = работает"
[ Araris: - изменил )) ]
Подтверждаю работу на ESP32 библиотеки SimpleModbusSlaveV10_DUE(режим Slave) из поста выше.
Прикинулся Овеном по ID и отсылал содержимое нужных регистров.
Схема подключения аналогичная как в этом посте, только питаю MAX485 от 5 В и сигнал подаю на RX/TX еэспэшки.
Вообщем огромный простор для полёта фантазии учитывая колличество памяти в ESP32 ;)
Ха, поспешил я радоваться. примерно через минут 5 еспшка перестаёт отвечать на запросы по RS-485
И лечится всё только перегрузкой платы...
Похоже всё решилось, слишком часто теребил функцию modbus_update(); - прибавил делей на 50 мс и всё заработало.
Похоже всё решилось, слишком часто теребил функцию modbus_update(); - прибавил делей на 50 мс и всё заработало.
Hello HWMan,
can you please share the code and modifications done to run this library on ESP32
Похоже всё решилось, слишком часто теребил функцию modbus_update(); - прибавил делей на 50 мс и всё заработало.
Hello HWMan,
can you please share the code and modifications done to run this library on ESP32
#include <SimpleModbusSlave_DUE.h> // github.com/jecrespo/simple-modbus //Debuging settings: #define DebugToUART false #define ReDePin 12 // Re/De Pin int maxNumRegisters = 6; // 6 regs int RS485Result[] = {4, 8, 15, 16, 23, 42}; // 6 enum { d0, d1, d2, d3, d4, d5, HOLDING_REGS_SIZE // leave this one }; unsigned int holdingRegs[HOLDING_REGS_SIZE]; void setup() { modbus_configure(&Serial, 9600, 10, ReDePin, HOLDING_REGS_SIZE, holdingRegs); modbus_update_comms(9600, 10); // register addres 10 } void loop() { modbus_update(); holdingRegs[d0] = RS485Result[0]; holdingRegs[d1] = RS485Result[1]; holdingRegs[d2] = RS485Result[2]; holdingRegs[d3] = RS485Result[3]; holdingRegs[d4] = RS485Result[4]; holdingRegs[d5] = RS485Result[5]; #if DebugToUART debuging(); #endif } void debuging() { for (int dbg = 0; dbg < maxNumRegisters; dbg++) { Serial.print(" "); Serial.print(dbg); Serial.print(" = "); Serial.print(RS485Result[dbg]); Serial.print(","); } Serial.println(""); }Здравствуйте господа! Может кто знает? Библиотека SimpleModbusMaster_DUE, опрос, а также запись регистров ведется пачкой, и по циклу при помощи modbus_update();, есть ли в этой библиотеке возможность записи отдельно каждого пакета? Смысл в том, что мне необходимо запись производить только один раз, когда мне это нужно, а не в цикле вмеcте с чтением. И если есть, может примеры найдутся? В сети информацию на эту тему найти не получается.
Приведённая в статье библиотека не работает на передачу. Пробовал её использовать в своём проекте - мастер не может корректно прочитать данные, причём на любой скорости. Читает две переменные по два регистра, а третью уже не читает. На приём всё работает.
Для ESP32 используйте лучше вот это:
emelianov/modbus-esp8266: Наиболее полная библиотека Modbus для Arduino. Библиотека, которая позволяет вашей плате Arduino взаимодействовать по протоколу Modbus, выступая в качестве хозяина, ведомого или обоих. Поддержка сетевого транспорта (Modbus TCP) и последовательной линии/RS-485 (Modbus RTU). Поддержка безопасности Modbus TCP для ESP8266/ESP32. (github.com)
Объектно-ориентированный драйвер MODBUS, поддерживает весь стандарт MODBUS, поддерживает многопоточность и события. Можно несколькими потоками работать с общим портом. Можно несколькими портами обращаться к одним и тем же данным. Рекомендую.
З.Ы. Как убрать простыню текста из ссылки я не понял. Куча каких-то мутных настроек, которые ни на что не влияют.
...
Приведённая в статье библиотека не работает на передачу. Пробовал её использовать в своём проекте - мастер не может корректно прочитать данные, причём на любой скорости. Читает две переменные по два регистра, а третью уже не читает. На приём всё работает.
Для ESP32 используйте лучше вот это:
emelianov/modbus-esp8266: Наиболее полная библиотека Modbus для Arduino. Библиотека, которая позволяет вашей плате Arduino взаимодействовать по протоколу Modbus, выступая в качестве хозяина, ведомого или обоих. Поддержка сетевого транспорта (Modbus TCP) и последовательной линии/RS-485 (Modbus RTU). Поддержка безопасности Modbus TCP для ESP8266/ESP32. (github.com)
Объектно-ориентированный драйвер MODBUS, поддерживает весь стандарт MODBUS, поддерживает многопоточность и события. Можно несколькими потоками работать с общим портом. Можно несколькими портами обращаться к одним и тем же данным. Рекомендую.
З.Ы. Как убрать простыню текста из ссылки я не понял. Куча каких-то мутных настроек, которые ни на что не влияют.
Здравствуйте. Вопрос к МОРЗЕ.
Поработал с библиотекой, что вы порекомендовали (https://github.com/emelianov/modbus-esp8266)
Возможно у вас есть рабочий пример кода записи с ЕСП32 в ПЛК, или в ПР200. Поделитесь пожалуйста, не могу справиться с библиотекой.
Вот мой код для считывания с ПР200-го. Он рабочий, а вот записать не получается.
#include <ModbusRTU.h> #define SLAVE_ID 16 #define FIRST_REG 512 #define REG_COUNT 2 ModbusRTU mb; bool cb(Modbus::ResultCode event, uint16_t transactionId, void* data) { if (event != Modbus::EX_SUCCESS) { Serial.print("Request result: 0x"); Serial.print(event, HEX); } return true; } void setup() { Serial.begin(115200); Serial2.begin(9600, SERIAL_8N1, 19, 18); mb.begin(&Serial2, 17); mb.master(); } void loop() { uint16_t res[REG_COUNT]; if (!mb.slave()) { mb.readHreg(SLAVE_ID, FIRST_REG, res, REG_COUNT, cb); while(mb.slave()) { mb.task(); delay(10); } Serial.println(res[0]); Serial.println(res[1]); } delay(1000); }Записать может только мастер. Слейв может только ответить. Мастер поднимается в 19 строке, но дальше в коде вызова нет. Нужно заполнить так называемую телеграмму и отправить. В примерах работа с мастером есть.
А вы вообще в курсе, как MODBUS работает? В сегменте сети MODBUS есть один ведущий (он же мастер) и до 32 ведомых. Ведущий по очереди отправляет ведомым сообщения. Ведомые отвечают только тогда, когда у них запрашивают данные. Сами по себе ведомые никогда ничего не отправляют. Говоря компьютерными терминами, мастер является клиентом, а все ведомые - серверами.
Я делал ведомого, работу с ПЛК через обработчики событий реализовал, работал только с регистрами. Но там можно с любой адресной зоной MODBUS работать, смотрите примеры.
1. Делаете ПЛК мастером, а ардуинку ведомым.
2. Настраиваете у мастера в свойствах скорость обмена, адрес ведомого в сети и опрашиваемые регистры.
Вот пример программы:
#include <ModbusRTU.h> //стартовый регистр MODBUS #define HOLDING_REGS_START 0 //число регистров MODBUS #define HOLDING_REGS_SIZE 24 //настройки порта MODBUS #define MODBUS_SPEED 19200 //115200 #define MODBUS_CONFIG SERIAL_8N1 #define MODBUS_ID 18 #define MODBUS_RX_PIN 22 #define MODBUS_TX_PIN 23 #define MODBUS_TX_ENABLE_PIN 21 //массив регистров MODBUS unsigned int holdingRegs[HOLDING_REGS_SIZE]; //порт MODBUS ModbusRTU Port; //Обработчик события чтения регистра uint16_t cbPortRead(TRegister* reg, uint16_t val) { if(reg->address.isHreg() && reg->address.address - HOLDING_REGS_START >= 0 && reg->address.address - HOLDING_REGS_START < HOLDING_REGS_SIZE) { val = holdingRegs[reg->address.address - HOLDING_REGS_START]; } return val; } //Обработчик события записи регистра uint16_t cbPortWrite(TRegister* reg, uint16_t val) { if(reg->address.isHreg() && reg->address.address - HOLDING_REGS_START >= 0 && reg->address.address - HOLDING_REGS_START < HOLDING_REGS_SIZE) { holdingRegs[reg->address.address - HOLDING_REGS_START] = val; } return val; } void setup() { //инициализация порта для отладки Serial.begin(9600, SERIAL_8N1); //инициализация регистров MODBUS int i; for(i = 0; i < HOLDING_REGS_SIZE; i++) { holdingRegs[i] = 0; } //инициализация порта MODBUS Serial1.begin(MODBUS_SPEED, SERIAL_8N1, MODBUS_RX_PIN, MODBUS_TX_PIN); //инициализация сервера MODBUS Port.begin(&Serial1, MODBUS_TX_ENABLE_PIN); Port.setBaudrate(MODBUS_SPEED); Port.server(MODBUS_ID); Port.cbEnable(true); Port.addHreg(HOLDING_REGS_START, 0, HOLDING_REGS_SIZE); Port.onGetHreg(HOLDING_REGS_START, cbPortRead, HOLDING_REGS_SIZE); Port.onSetHreg(HOLDING_REGS_START, cbPortWrite, HOLDING_REGS_SIZE); } void loop() { //выполнить цикл обмена с ведомым порта MODBUS Port.task(); yield(); }строчки 45-50 лишние....
Угу, давайте не будем чистить регистры перед отладкой чтобы любоваться мусором в них. :)
Угу, давайте не будем чистить регистры перед отладкой чтобы любоваться мусором в них. :)
так вы не регистры чистите, а локальный массив для них. А в нем и так нули после ресета, читайте описание языка
МОРЗЕ если уж вы хотите, чтобы инициализация массива была явной, просто добавте ее в обьявление массива:
unsigned int holdingRegs[HOLDING_REGS_SIZE] = {0};хотя повторяю. по стандарту языка в этом нет необходимости
Я очень хорошо знаю как работать c MODBUS. Написал кучу мастеров и слейвов и даже на Delphi PCшном. У меня в реальном режиме времени через него графики шестифазного выпрямителя бегают. Вот только проблема в том, что мастера ничего нельзя попросить. Совсем нельзя. Если сделать мастером ПЛК, то надо его программировать на выдачу данных либо через интервалы времени, либо по внешнему событию. Очень интересно узнать, как у Вас реализован обработчик событий.
Точно мусором ?
Я все время думал, что при объявлении переменных в них не мусор, а инициализация по умолчанию (0)...
Записать может только мастер. Слейв может только ответить. Мастер поднимается в 19 строке, но дальше в коде вызова нет. Нужно заполнить так называемую телеграмму и отправить. В примерах работа с мастером есть.
Я знаю что записать может только мастер
У меня ПР-200 будет точно "slave", и ЕСП32 "master", я хочу слать команды с ЕСП32 на овен.
Я сейчас ничего не отписываю, нашел эту тему (http://arduino.ru/forum/programmirovanie/modbus-rtu), перечитываю ее и пытаюсь разобраться.
В данной ветке обсуждается несколько библиотек
1. (https://github.com/emelianov/modbus-esp8266)
#include <ModbusRTU.h>
2. (https://github.com/smarmengol/Modbus-Master-Slave-for-Arduino)
#include <ModbusRtu.h>
Видите слово RTU / Rtu один раз большие а второй раз маленькие буквы, это две разные библиотеки.
Сейчас пытаюсь разобраться с той, где телеграмм (https://github.com/smarmengol/Modbus-Master-Slave-for-Arduino).
Для ESP святцы рекомендуют только #11
Для ESP святцы рекомендуют только #11
Я и начинал с этой библиотеки. И вот на ней получилось получить данные с ОВЕН (конфигарация ESP- master, овен - slave) #34.
Но тогда вы сказали, что нужно слать через телеграмму, а в данной библиотеке я не нашел как это сделать, поэтому и начал пробовать на такой (https://github.com/smarmengol/Modbus-Master-Slave-for-Arduino)
В этой библиотеке телеграмму спрятали в библиотеку. Упростили до нельзя. Пример тут. Создание запроса строка 38. Печать ответа слэйва 43-44.
В этой библиотеке телеграмму спрятали в библиотеку. Упростили до нельзя. Пример тут. Создание запроса строка 38. Печать ответа слэйва 43-44.
Получилось. Спасибо.
Здравствуйте, люди добрые. Помогите, пожалуйста. Что-то я совсем застрял.
Пример из сообщения #47 не выводит в сериал-порт содержимое регистров.
Ведомое устройство (прога на компе) получает запрос и правильно отвечает на него:
Rx:000000-01 03 00 00 00 02 C4 0B
Tx:000001-01 03 04 00 42 7E B2 FB F2
А ESP32(master) с кодом из примера #47 в сериал выводит только:
Request result: 0xE40
0
Request result: 0xE40
0
...
Как я догадываюсь, обработка ответа уже есть в библиотеке modbus-esp8266 и строки 43-44 должны печать ответ слэйва?
Или ESP32 нужен обработчик ответа (как в примерах для слэйва из той же библиотеки)?
Меня смущает, что контакты DE, RE у MAX485 висят в воздухе.
А ни кто не обещал что с 485 будет работать. Тут только 485 с автоматическим Rx-Tx пользовать. А результат должен быть 0 если всё правильно, иначе печатает код ошибки - Е4, что мы и видим. Пробуйте без 485, когда всё получится думайте как 485 прикрутить.