Arduino Nano в качестве мастера modbus rtu
- Войдите на сайт для отправки комментариев
Втр, 17/12/2019 - 12:16
Добрый день!
Использовал библиотеку https://github.com/4-20ma/ModbusMaster
Последовательный порт для вывода результатов не использую
Вывод на дисплей работает нормально
Подключение:
RS485 - Arduino
TX - DI
RX - RO
RE/DE - D8
Соответственно 485 и устройство А к А, В к В
Питание у "устройства" свое, плата преобразователя 485 питается от 5В Arduino
Ведомое устройство, к сожалению, назвать не могу? *секрет*.. но вот его параметры:
Скорость 38400, 8N1
Slave ID 4
Всего нужно считать 22 регистра с 1000 по 1021 (параметр точно 0х03), данные в формате HEX
Все стандартно: не работает, на первой строке дисплея выдает сообщение из else (Error get data)
Посмотрите, пожалуйста, скетч (он не мой, нашел на каком-то форуме, там у товарища все работает. Я только привел его визуально в порядок, сделал комментарии и т.д.)
При этом если подключить "устройство" к ПК через USB-485 конвертер и воспользоваться программой https://sourceforge.net/projects/qmodmaster/ то там все прекрасно работает и считывается.
Физическое подключение вроде бы верное, так как при снятии питания с "устройства" перебор регистров на дисплее сильно замедляется, так же происходит если отключить от него 485..
// Подключаем библиотеки
#include <ModbusMaster.h>
#include <LiquidCrystal.h>
// Макроопределения пинов
// Определяем пины для подключения LCD дисплея и инициализируем библиотеку LiquidCrystal.h
const int rs = 2, en = 3, d4 = 4, d5 = 5, d6 = 6, d7 = 7;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
// Автоматический выбор приема/передачи RS-485
#define MAX485_DE 8
// Светодиод индикации успешных пакетов
#define LED_SUCCESS 13
// Создаем экземпляр объекта ModbusMaster
ModbusMaster node;
void preTransmission(){
digitalWrite(MAX485_DE, true);
}
void postTransmission(){
digitalWrite(MAX485_DE, false);
}
void setup()
{
// Указываем количество столбцов и строк на LCD дисплее
lcd.begin(16, 2);
// Конфигурируем пины на выход
pinMode(MAX485_DE, OUTPUT);
pinMode(LED_SUCCESS, OUTPUT);
// Устанавливаем RS485 на прием
digitalWrite(MAX485_DE, false);
// Запускаем Modbus на скорости 38400
Serial.begin(38400);
// Определяем Modbus ведомый ID 4, используем Serial
node.begin(4, Serial);
// Обратные вызовы позволяют нам правильно настроить приемопередатчик RS485
node.preTransmission(preTransmission);
node.postTransmission(postTransmission);
}
// какая то хрень для светодиода
void led_blink(int blk)
{
for (int j=0; j < blk; j++)
{
digitalWrite(LED_SUCCESS, HIGH);
delay(100);
digitalWrite(LED_SUCCESS,LOW);
delay(100);
}
}
void loop()
{
// Поочередно перебираем регистры с 1000 по 1021 (с каждым новым циклом +1 к значению)
for (int holdreg = 0x3E8; holdreg < 0x3FD; holdreg++)
{
// Выводим номер текущего регистра на LCD дисплей
lcd.setCursor(0,0);
lcd.print("Reg: ");
lcd.print(holdreg);
delay(100);
// Объявляем переменную и пишем в нее значение считанного регистра
uint8_t result = node.readHoldingRegisters(holdreg, 1);
// Если успешно считали регистр то выполняем if, иначе else
if (result == node.ku8MBSuccess)
{
led_blink(5); // что это и для чего
lcd.print("Value for:");
lcd.print(holdreg);
lcd.setCursor(0,1);
lcd.print(node.getResponseBuffer(0));
delay(1500);
digitalWrite(LED_SUCCESS,LOW);
}
else
{
led_blink(1); // что это и для чего
lcd.setCursor(0,1);
lcd.print("Error get data");
}
}
}
Убрал конструкцию с if - else, в каждом из регистров якобы лежит FFFF
Вообще фигня какая-то, что есть такого в программе под винду, чего нет в скетче
Вообще фигня какая-то, что есть такого в программе под винду, чего нет в скетче
В библиотеке некорректно идёт переключение на приём RS-485. Конкретно в этих строчках:
u8ModbusADUSize = 0; _serial->flush(); // flush transmit buffer if (_postTransmission) { _postTransmission(); }Переключаться надо не когда софтовый сериал буфер опустел, а когда последний байт полностью ушёл из UDR. Автор тестировал на MAX488, а он полнодуплексный. Так что у вас последний байт обрезается, и слэйв вас не понимает.
Переключаться надо не когда софтовый сериал буфер опустел, а когда последний байт полностью ушёл из UDR. Автор тестировал на MAX488, а он полнодуплексный. Так что у вас последний байт обрезается, и слэйв вас не понимает.
Для меня это очень сложно, сможете мне в этом помочь?
Скажите, пожалуйста, что нужно сделать, чтобы все заработало?
Простейший способ для вас - вставить задержку в текст коллбэка окончания передачи, до переключения на приём. На 38400 один байт идёт где-то 260 мкс. Ставить можно на период до 4.5 байт, в Modbus есть период тишины между пакетами. Например, delayMicroseconds(1000). Хотя и задержка, но не такая уж большая.
Есть решение изящнее, но попробуйте так пока.
Простейший способ для вас - вставить задержку в текст коллбэка окончания передачи, до переключения на приём
Это первый скетч по данной теме, мало чего осознаю, делал все по чужой инструкции не вникая в детали и единственное, что пришло в голову это влепить задержку перед строкой:
Само собой это не помогло :)
Само собой это не помогло :)
Порылся в папке библиотеки, если в файле ModbusMaster.h
// idle callback function; gets called during idle time between TX and RX void (*_idle)(); // preTransmission callback function; gets called before writing a Modbus message void (*_preTransmission)(); // postTransmission callback function; gets called after a Modbus message has been sent void (*_postTransmission)();В этих строках попробовать залезть, то не компилируется
Ок, полез в ModbusMaster.cpp
void ModbusMaster::postTransmission(void (*postTransmission)()) { delayMicroseconds(1000); _postTransmission = postTransmission; }Там влепил задержку, компилируется, но не помогает
Не не там, только здесь:
void postTransmission(){ delayMicroseconds(1000); digitalWrite(MAX485_DE, false); }Попробуйте разные задержки. И выведите в блоке else что вам возвращает библиотека, какую ошибку, на LCD.
Не не там, только здесь:
Попробовал несколько, вплоть до 10мс, только регистры на дисплее медленнее стали перебираться..
выведите в блоке else что вам возвращает библиотека, какую ошибку, на LCD.
Как это сделать?
Как это сделать?
Выведите result на LCD.
Выведите result на LCD.
Блин, я то уж начал монструозые конструкции искать типа таких:
bool getResultMsg(ModbusMaster *node, uint8_t result) { String tmpstr2 = "\r\n"; switch (result) { case node->ku8MBSuccess: return true; break; case node->ku8MBIllegalFunction: tmpstr2 += "Illegal Function"; break; case node->ku8MBIllegalDataAddress: tmpstr2 += "Illegal Data Address"; break; case node->ku8MBIllegalDataValue: tmpstr2 += "Illegal Data Value"; break; case node->ku8MBSlaveDeviceFailure: tmpstr2 += "Slave Device Failure"; break; case node->ku8MBInvalidSlaveID: tmpstr2 += "Invalid Slave ID"; break; case node->ku8MBInvalidFunction: tmpstr2 += "Invalid Function"; break; case node->ku8MBResponseTimedOut: tmpstr2 += "Response Timed Out"; break; case node->ku8MBInvalidCRC: tmpstr2 += "Invalid CRC"; break; default: tmpstr2 += "Unknown error: " + String(result); break; } Serial.println(tmpstr2); return false; }Вывел result, на всех регистрах говорит "224"
Это ku8MBInvalidSlaveID. Типа ответил не тот, кого спрашивали.
Типа ответил не тот, кого спрашивали.
Ух ты, а где можно увидеть остальные коды ошибок? Сколько лазал по мануалам разработчика библиотеки не видел этого.. А то лишний раз хорошим людям голову по мелочам забиваю :)
Второй вопрос, а как это лечить если на линии больше никого нет?
Ух ты, а где можно увидеть остальные коды ошибок? Сколько лазал по мануалам разработчика библиотеки не видел этого.. А то лишний раз хорошим людям голову по мелочам забиваю :)
Второй вопрос, а как это лечить если на линии больше никого нет?
В файле ModbusMaster.h прописаны коды ошибок.
Лечить сложно сказать как. Может быть электрическая проблема - искажение данных в линии. Может быть прием обрезанной с головы посылки. Может быть со скоростью проблемы. Но поскольку ваше устройство точно работает, ошибка точно на вашей стороне, и это сильно упрощает дело.
Попробуйте ещё библиотеку поменять. Мне вот эта больше нравится: https://github.com/BlackBrix/Simple-Modbus-Master. Написана получше. И у меня работал Slave этого автора из коробки.
Типа ответил не тот, кого спрашивали.
Ух ты, а где можно увидеть остальные коды ошибок?
Так, с этим вроде разобрался, 224 это 0xE0, поиском в ModBusMaster.h нашел:
/** ModbusMaster invalid response slave ID exception. The slave ID in the response does not match that of the request. @ingroup constant */ static const uint8_t ku8MBInvalidSlaveID = 0xE0;В файле ModbusMaster.h прописаны коды ошибок.
Да, спасибо, пока писал и вы об этом же сказали))
это сильно упрощает дело
Хорошо, попробую заменить железную часть, может быть действительно есть с этим проблемы. Однако, пробовал простенький скетч, который выводит всякую чушь в Serial, железо, собственно, использовал это же, но там насколько я знаю, линии RE/DE у 485 не использовались, так как это передача в одну сторону, от arduino к 485-USB и в ПК.
Мне вот эта больше нравится
Видел ее, очередной клон от некого Juan.. сколько примеров в сети и ни в одном нормально не описана моя задача, а сам я, как вы уже, думаю, заметили, не шибко прошарен в данной теме :)
А вы говорили об каком-то "изящном" способе, может быть с ним чего-то получится?
А вы говорили об каком-то "изящном" способе, может быть с ним чего-то получится?
Просто имел ввиду ту же задержку не делать блокирующей. Это не поможет.
Сейчас попробовал скормить скетчу заведомо неверный slave ID
Выдает ошибку E2, типа: "Ответ не был получен в выделенный период ожидания".
Буду пробовать менять железо, а может и библиотеку, хотя с этой даже как-то подружился немного :)
В любом случае, спасибо за помощь! Хорошего вечера!
Сейчас попробовал скормить скетчу заведомо неверный slave ID
Выдает ошибку E2, типа: "Ответ не был получен в выделенный период ожидания".
Буду пробовать менять железо, а может и библиотеку, хотя с этой даже как-то подружился немного :)
В любом случае, спасибо за помощь! Хорошего вечера!
Это говорит о том, что устройство вас слышит и понимает, и отвечает, но ваш мастер его не понимает. Копайте в эту сторону. Ну и смена библиотеки. То, что я рекомендовал - на порядок лучше вашей, проверено. Там автор очень хороший сишник.
Ну и смена библиотеки
Попробовал использовать библиотеку, что вы предложили
// Подключаем библиотеки #include <SimpleModbusMaster.h> #include <LiquidCrystal.h> // Макроопределения пинов // Определяем пины для подключения LCD дисплея и инициализируем библиотеку LiquidCrystal.h const int rs = 2, en = 3, d4 = 4, d5 = 5, d6 = 6, d7 = 7; LiquidCrystal lcd(rs, en, d4, d5, d6, d7); #define baud 38400 // Скорость обмена по последовательному интерфейсу (UART) #define timeout 1000 // Длительность ожидание ответа (таймаут ModBus) #define polling 200 // Скорость опроса по ModBus #define retry_count 2 // Количесво запросов ModBus до ошибки и останова обмена #define TxEnablePin 8 // Автоматический выбор приема/передачи RS-485 (RE/DE) #define Slave_ID 4 // Адрес ведомого устройсва // Общий объем доступной памяти на ведущем устройстве для хранения данных #define TOTAL_NO_OF_REGISTERS 4 // Способ создания новых пакетов. enum { PACKET1, // Адрес пакета 0 PACKET2, // Адрес пакета 1 PACKET3, // Адрес пакета 2 PACKET4, // Адрес пакета 3 TOTAL_NO_OF_PACKETS //Данная строка не должна быть изменена! }; // Создаем массив пакетов для конфигурации Packet packets[TOTAL_NO_OF_PACKETS]; // Создаем массив регистров ведущего unsigned int regs[TOTAL_NO_OF_REGISTERS]; void setup() { // Initialize each packet modbus_construct(&packets[PACKET1], Slave_ID, READ_HOLDING_REGISTERS, 1000, 1, 0); modbus_construct(&packets[PACKET2], Slave_ID, READ_HOLDING_REGISTERS, 1001, 1, 1); modbus_construct(&packets[PACKET3], Slave_ID, READ_HOLDING_REGISTERS, 1002, 1, 2); modbus_construct(&packets[PACKET4], Slave_ID, READ_HOLDING_REGISTERS, 1003, 1, 3); // Initialize the Modbus Finite State Machine modbus_configure(&Serial, baud, SERIAL_8N1, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS, regs); lcd.begin(16, 2); //Указываем тип LCD дисплея 16 символов, 2 строки) } void loop() { modbus_update(); lcd.setCursor(0, 0); lcd.print(regs[0]); lcd.print(" | "); lcd.print(regs[1]); lcd.setCursor(0, 1); lcd.print(regs[2]); lcd.print(" | "); lcd.print(regs[3]); }Посмотрите, пожалуйста, скетч.. на дисплей выводятся нули, что-то делаю не так?
Разобрался, дело было не в бобине, как говорится..
Сам модуль преобразователя какой-то бракованный попался, не знаю, что с ним не так.. ведь при обычном обмене с компьютером проблем не было, а вот с modbus появились. Поменял на другой такой же и пакеты посыпались.
В конечном счете заработал первый скетч, по совету ув. Schwarz78, обязательно проверю другую библиотеку.
Большое спасибо за помощь!
У меня такое было, когда девайс пожёг китайский модуль RS485 - что-то так подал в линию, что микросхема впала в горячку. После чего часть пакетов начали приходить битыми.
Товарищи, есть еще вопрос в продолжение этой темы.
При считывании регистра (два байта), получаю, например, A26, а хотелось бы 0A26..
Куда пропал ноль? Это довольно важно, так как, например, первые два регистра в моем случае - это серийный номер устройства.
Должен быть номер: 1234 0567, а приходит 1234 567.. где опять потерялся ноль?
Товарищи, есть еще вопрос в продолжение этой темы.
При считывании регистра (два байта), получаю, например, A26, а хотелось бы 0A26..
Куда пропал ноль? Это довольно важно, так как, например, первые два регистра в моем случае - это серийный номер устройства.
Должен быть номер: 1234 0567, а приходит 1234 567.. где опять потерялся ноль?
А как именно получаете? Приведите код, иначе непонятно.
Подозреваю, что библиотека вашего LCD жрёт лидирующий ноль просто напросто. Даже скорее всего. Lcd.print - это форматированный вывод, конечно. Берите сырое значение, и делайте с ним что угодно. Нули не пропадают, их может скрывать функция вывода на экран)
Приведите код, иначе непонятно.
Библиотека из стандартных примеров Arduino. Вот так спрашиваю:
Как отвечает, думаю, вы поняли из предыдущего сообщения
Подозреваю, что библиотека вашего LCD жрёт лидирующий ноль просто напросто
А может сам дисплей быть "не такой как все"?
Берите сырое значение, и делайте с ним что угодно
Это как? Через lcd.write?
Получается для разных типов данных использовать разные варианты вывода?
Но ведь это будет не String? Как бы хуже не сделать..
Вы используете форматированный вывод, он убирает лидирующие нули с экрана, для читаемости. Из реальных значений нули никуда не пропадают. Попробуйте почитать это для начала: https://cpp.com.ru/shildt_spr_po_c/. Функция printf(). Там всё написано очень простым языком.
Но ведь это будет не String? Как бы хуже не сделать..
Рано вам о String думать) Думайте о char[], то есть об обычных строках символов.
Вот ещё посмотрите: http://arduino.ru/Reference/Serial/Print
Ваш lcd.print явно наследует от этого общего с print родителя. Но вам точно рано об этом думать. Подумайте, как вам получить целое 16-разрядное число от вашего "устройства", вам больше и не надо.
Как в ModbusRtu https://github.com/smarmengol/Modbus-Master-Slave-for-Arduino задавать стартовый регистр для входящих пакетов?
Как вывести в print шестнадцатеричные числа в десятичной системы в формате 001? Числа от 1 до 999 кодируются в два байта 0х0000, к примеру число 3 выводиться в принт как 3, а нужно в трехзначном виде 003 или число 25 как 025. Не соображу как это сделать.
выводить лидирующие нули, если <=9 то два, если <=99 то один
uint16_t a[] = {7, 17, 177}; void setup() { Serial.begin(115200); for (int i = 0; i < 3; i++) { Serial.print("a="); if (a[i] <= 9)Serial.print("00"); if (a[i] > 9 && a[i] <= 99)Serial.print("0"); Serial.println(a[i]); } } void loop() { }if (a[i] < 10)Serial.print('0');
if (a[i] < 100)Serial.print('0');
таки да )))
Скетч использует 262108 байт (25%) памяти устройства. Всего доступно 1044464 байт.
Глобальные переменные используют 26912 байт (32%) динамической памяти, оставляя 55008 байт для локальных переменных. Максимум: 81920 байт.
против твоих
Скетч использует 262104 байт (25%) памяти устройства. Всего доступно 1044464 байт.
Глобальные переменные используют 26900 байт (32%) динамической памяти, оставляя 55020 байт для локальных переменных. Максимум: 81920 байт.
Понял, уже что-то получается)
Как указать диапазон чисел от и до? После 1000 выводит и до 100 выводит, а вот как от 100 до 1000 указать не знаю.
u8g2.setCursor(50, 60); // указываем положение курсора if (au16data[1]< 999)u8g2.print('0'); // выводим строку на дисплей u8g2.setCursor(60, 60); // указываем положение курсора if (au16data[1]< 99)u8g2.print('0'); // выводим строку на дисплей u8g2.setCursor(50, 60); // указываем положение курсора if (au16data[1] > 998)u8g2.print(au16data[1]); // выводим строку на дисплей u8g2.setCursor(60, 60); // указываем положение курсора if (au16data[1] > 100 < 1000)u8g2.print(au16data[1]); // ???? u8g2.setCursor(70, 60); // указываем положение курсора if (au16data[1] < 100)u8g2.print(au16data[1]); // выводим строку на дисплей u8g2.sendBuffer();тебе разжевали и в рот положили, обе строки задействуй при разборе значения до вывода
Понял. if (au16data[1] > 100 && au16data[1] < 1000)u8g2.print(au16data[1]);
Понял. if (au16data[1] > 100 && au16data[1] < 1000)u8g2.print(au16data[1]);
с логикой у тебя совсем не айс...Садман жеж подсказал оптимальный алгоритм
u8g2.setCursor(50, 60); if (a[i] < 10)Serial.print('0'); if (a[i] < 100)Serial.print('0'); Serial.print(a[i]);Ещё можно открыть для себя snprintf().
Я не совсем правильно вопрос задал. С установкой нулей я сделал как Садман подсказал. Остальное для того чтоб числа с нулями не пересекались на дисплее.
u8g2.setCursor(50, 60); // указываем положение курсора if (au16data[1]< 999)u8g2.print('0'); // выводим строку на дисплей u8g2.setCursor(60, 60); // указываем положение курсора if (au16data[1]< 99)u8g2.print('0'); // выводим строку на дисплей u8g2.setCursor(50, 60); // указываем положение курсора if (au16data[1] > 998)u8g2.print(au16data[1]); // выводим строку на дисплей u8g2.setCursor(60, 60); // указываем положение курсора if (au16data[1] > 100 && au16data[1] < 1000)u8g2.print(au16data[1]); // u8g2.setCursor(70, 60); // указываем положение курсора if (au16data[1] < 100)u8g2.print(au16data[1]); // выводим строку на дисплей u8g2.sendBuffer();Собрал строчку, но что то длинная портянка получилась, а всего то одна строчка на дисплее "-9999.9999", точка зафиксирована на дисплее.
#include <Arduino.h> #include <U8g2lib.h> #ifdef U8X8_HAVE_HW_SPI #endif #ifdef U8X8_HAVE_HW_I2C #include <Wire.h> #endif #include <ModbusRtu.h> #define ID 1 Modbus slave(ID, 0, 0); uint16_t au16data[3]; int8_t state = 0; char rob1 = '-'; char rob2 = '+'; //au16data[0] mm //au16data[1] десятитысячные //au16data[2]; 0x00- 0x01+ U8G2_LC7981_240X128_F_6800 u8g2(U8G2_R0, 52, 50, 48, 46, 44, 42, 40, 38, /*enable=*/ 36, /*cs=*/ 34, /*dc=*/ 26, /*reset=*/ 30); // Connect RW with GND void setup(void) { slave.begin( 9600 ); u8g2.begin(); u8g2.enableUTF8Print(); } void loop(void) { state = slave.poll(au16data, 3); if (state>4) { u8g2.clearBuffer(); u8g2.setFont(u8g2_font_unifont_t_symbols); //Минус if (au16data[2] == 1 && au16data[0]<= 9) { u8g2.setCursor(32, 60); u8g2.print(rob1); } if (au16data[2] == 1 && au16data[0] <= 99 && au16data[0] >= 10) { u8g2.setCursor(24, 60); u8g2.print(rob1); } if (au16data[2] == 1 && au16data[0] >= 100 && au16data[0] <= 999) { u8g2.setCursor(16, 60); u8g2.print(rob1); } if (au16data[2] == 1 && au16data[0] >= 1000 && au16data[0] <= 9999) { u8g2.setCursor(8, 60); u8g2.print(rob1); } //Плюс if (au16data[2] == 0 && au16data[0]<= 9) { u8g2.setCursor(32, 60); u8g2.print(rob2); } if (au16data[2] == 0 && au16data[0] <= 99 && au16data[0] >= 10) { u8g2.setCursor(24, 60); u8g2.print(rob2); } if (au16data[2] == 0 && au16data[0] >= 100 && au16data[0] <= 999) { u8g2.setCursor(16, 60); u8g2.print(rob2); } if (au16data[2] == 0 && au16data[0] >= 1000 && au16data[0] <= 9999) { u8g2.setCursor(8, 60); u8g2.print(rob2); } //ММ u8g2.setCursor(40, 60); if (au16data[0] <= 9)u8g2.print(au16data[0]); u8g2.setCursor(32, 60); if (au16data[0] >= 10 && au16data[0] <= 99)u8g2.print(au16data[0]); u8g2.setCursor(24, 60); if (au16data[0] >= 100 && au16data[0] <= 999)u8g2.print(au16data[0]); u8g2.setCursor(16, 60); if (au16data[0] >= 1000 && au16data[0] <= 9999)u8g2.print(au16data[0]); //Точка u8g2.setCursor(45, 60); u8g2.print('.'); //Нули u8g2.setCursor(50, 60); if (au16data[1] <= 999)u8g2.print('0'); u8g2.setCursor(58, 60); if (au16data[1] <= 99)u8g2.print('0'); u8g2.setCursor(66, 60); if (au16data[1] <= 9)u8g2.print('0'); //после точки u8g2.setCursor(50, 60); if (au16data[1] >= 1000)u8g2.print(au16data[1]); u8g2.setCursor(58, 60); if (au16data[1] >= 100 && au16data[1] <= 999)u8g2.print(au16data[1]); u8g2.setCursor(66, 60); if (au16data[1] >= 10 && au16data[1] <= 99)u8g2.print(au16data[1]); u8g2.setCursor(74, 60); if (au16data[1] <= 9)u8g2.print(au16data[1]); u8g2.sendBuffer(); } }Есть вариант проще, подсказали в разделе программирования:
Но строку типа данных float нельзя отцентровать по точке, строка плавающая в зависимости от количества чисел или можно?
Добрый день.
Можно ли редактировать в этой библиотеке (https://github.com/4-20ma/ModbusMaster) параметры связи, такие как четность, стоповые биты и длина данных? В тексте программы я этой возможности не нашел. как можно решить эту проблему?
Спасибо.
Добрый день.
Можно ли редактировать в этой библиотеке (https://github.com/4-20ma/ModbusMaster) параметры связи, такие как четность, стоповые биты и длина данных? В тексте программы я этой возможности не нашел. как можно решить эту проблему?
Спасибо.
@param &serial reference to serial port object (Serial, Serial1, ... Serial3)
ua6em : @param &serial reference to serial port object (Serial, Serial1, ... Serial3)
Не понял, что это. Как этим воспользоваться для задания четности, стоповых бит и длины данных?
К модбасу эти параметры не относятся. Смотри как настраивается сериал. https://www.arduino.cc/reference/en/language/functions/communication/serial/begin/
Cпасибо.
Добрый день. Schwarz78
Я попробовал рекомендованную Вами библиотеку https://github.com/BlackBrix/Simple-Modbus-Master.
Задача у меня простая - прочитать с датчика температуры и влажности (Slave addr 1, 9600, Serial_8N2) значения температуры (HR0) и влажности (HR1). Однако читаются нули. Датчик исправен (проверен с помощью другого Modbus мастера). Привожу текст скетча:
/* -------------------------------------------------------------------------------------------------------------------------------------- Задача: прочитать со Slave(address 1, 9600, SERIAL_8N2) два регистра типа uint16_t по адресам 0 (значение температуры Т) и 1 (значение влажности Hum). */ //------------------------------------------------------------------------------------------------------------------------------------- #include <SimpleModbusMaster.h> #include <SoftwareSerial.h> #define swRx 4 #define swTx 5 #define LED 9 #define TxEnablePin 3 // The total amount of available memory on the master to store data #define TOTAL_NO_OF_REGISTERS 1 //////////////////// Port information /////////////////// #define baud 9600 #define timeout 1000 #define polling 200 // the scan rate #define retry_count 10 SoftwareSerial swSer(swRx, swTx); // This is the easiest way to create new packets // Add as many as you want. TOTAL_NO_OF_PACKETS // is automatically updated. enum { PACKET1, // PACKET2, TOTAL_NO_OF_PACKETS // leave this last entry }; // Create an array of Packets to be configured Packet packets[TOTAL_NO_OF_PACKETS]; // Masters register array unsigned int regs[TOTAL_NO_OF_REGISTERS], T, Hum; //---------------------------------------------------------------------------------------- void setup() { swSer.begin(115200); pinMode(LED, OUTPUT); // Initialize each packet modbus_construct(&packets[PACKET1], 1, READ_HOLDING_REGISTERS, 0, 2, 0); //modbus_construct(&packets[PACKET2], 1, PRESET_MULTIPLE_REGISTERS, 1, 1, 0); // Initialize the Modbus Finite State Machine modbus_configure(&Serial, baud, SERIAL_8N2, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS, regs); // Print hello message swSer.println("Modbus communication over RS-485"); swSer.println("Modbus to I(4-20mA) converter. V1.0"); delay(100); } void loop() { modbus_update(); T = regs[0]; Hum = regs[1]; swSer.print("T="); swSer.println(T); swSer.print("Hum="); swSer.println(Hum); swSer.println(); delay(5000); }Что не так?
Спасибо
В обычной SoftwareSerial не было возможности назначать параметры, посмотрели, в вашей есть?
Да, работает.
Скажите, почему задача прочитать два регистра, а количество регистров 1 (строка 18)?
В данном случае читается только значение температуры = 0. Я устанавливал 2 - читались два параметра, равные нулю.
SoftwareSerial на 115200 - это безудержный оптимизм. 9600 ставьте.
Да бог с ним, с SoftwareSerial на 115200 (хотя он работает). Как насчет моей проблемы?
Спасибо.