ModbusRTU

Acuma
Offline
Зарегистрирован: 08.02.2022

Здравствуйте. Прошу помощи. Пытаюсь подружить 16-ти канальный мультиплексор с Arduino Slave по ModbusRTU(RS485);

Суть в том чтобы выводить в SIG на мультиплексоре только тот аналоговый вход, номер которого пришел от Мастера по модбас. 

Всего будет 2 мультиплексора, но я пытаюсь подружить пока 1.

Вот код который получился:

#include<ModbusRtu.h>
Modbus bus;
uint16_t modbus_array[4];
int multi1;
int multi2;

#define EN 3
#define S0 4
#define S1 5
#define S2 6
#define S3 7 

void setup() {
  Serial.begin(9600);
  bus = Modbus(100,1,10);
  bus.begin(9600);
  pinMode(S0, OUTPUT); 
  pinMode(S1, OUTPUT); 
  pinMode(S2, OUTPUT); 
  pinMode(S3, OUTPUT);   

  digitalWrite(S0, LOW);
  digitalWrite(S1, LOW);
  digitalWrite(S2, LOW);
  digitalWrite(S3, LOW);

  pinMode(EN, OUTPUT); 
  digitalWrite(EN, LOW);
 

}

void loop() {
  
bus.poll(modbus_array,sizeof(modbus_array)/sizeof(modbus_array[0]));
multi1 = modbus_array[2];
Serial.print("multiplexor1");
Serial.print("-");
Serial.println(multi1);
SetMuxAddress(multi1);
delay(100);

multi2 = modbus_array[3];
Serial.print("multiplexor2");
Serial.print("-");
Serial.println(multi2);
delay(100);
}

void SetMuxAddress(int address)
{
    digitalWrite(S0, (address >> 0) & 0x1);
    digitalWrite(S1, (address >> 1) & 0x1);
    digitalWrite(S2, (address >> 2) & 0x1);
}

В порт ничего не выводится. Подключено все паем - правильно!

Mestniy96
Offline
Зарегистрирован: 31.08.2015

Может дело в том что ваш порт уже используется?

Acuma
Offline
Зарегистрирован: 08.02.2022

Я использую Arduino Mega. RS подключено к RX0.TX0; Вы про это? Нужно перепаять на RX1 и TX1? Если да, то как тогда поменять код прошивки под RX1, TX1?

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Ляпнул :)

А можете рассказать, что у вас в 15 строке за такое..... ?

Acuma
Offline
Зарегистрирован: 08.02.2022

Инициализируем подключение указываем адресс, по мему режим и пин подключения.

У меня подключен Rs - так: 

AB-AB

DI-TX

DE-D10

RE-D10

VCC-VCC

GND-GND

Acuma
Offline
Зарегистрирован: 08.02.2022

В Сериал выводит:

22:42:34.152 -> multiplexor2-0
22:42:34.246 -> multiplexor1-0

Но ничего не приходит. 

Не знаю как добавить условие обработки запроса модбас и вывода в терминал, только когда что то пришло.

b707
Offline
Зарегистрирован: 26.05.2017

Acuma пишет:

Не знаю как добавить условие обработки запроса модбас и вывода в терминал, только когда что то пришло.

функция bus.poll() имеет возвращаемое значение, при успешном приеме пакета это значение, по-моему, должно быть > 4 . посмотрите в описании.

Acuma
Offline
Зарегистрирован: 08.02.2022

Да. все верно.

Acuma
Offline
Зарегистрирован: 08.02.2022

Попробовал использовать другой пример, но видимо увы... я слаб для таких примеров...


#include <ModbusRtu.h>
#define ID   100 // указали адрес модбас слейва
int multi1;
int multi2;

#define EN 3
#define S0 4
#define S1 5
#define S2 6
#define S3 7 

 int32_t myTimer; 
 Modbus slave(ID, 1, 10); // 100 адрес 1 -485  4- пин
 int8_t state = 0;
 
 unsigned long tempus;
 uint16_t au16data[9]; // массив  регистров
  word Reg2; //устройство 
  word Reg3;


void setup() {
  Serial.begin(9600); //открываем порт
  slave.start(); // запуск
  tempus = millis() + 100; // Сохранить текущее время + 100 мс
  digitalWrite(13, HIGH ); //светодиод на плате
pinMode(S0, OUTPUT); 
  pinMode(S1, OUTPUT); 
  pinMode(S2, OUTPUT); 
  pinMode(S3, OUTPUT);   

  digitalWrite(S0, LOW);
  digitalWrite(S1, LOW);
  digitalWrite(S2, LOW);
  digitalWrite(S3, LOW);

  pinMode(EN, OUTPUT); 
  digitalWrite(EN, LOW);
  
  
}

void loop() {

   state = slave.poll( au16data, 9 ); // Параметры: Таблица регистров для обмена информацией
                                      // Размер таблицы записей
                                      // Возвращает 0, если нет запроса данных
                                      // Возвращает от 1 до 4, если произошла ошибка связи
                                      // Возвращает больше 4, если заказ был обработан правильно
  Reg2=au16data[2];
  Reg3=au16data[3];
if (state > 4) { //Si es mayor a 4 = el pedido fué correcto
    tempus = millis() + 50; // Текущее время + 50 мс
Serial.print("multiplexor1");
Serial.print("-");
Serial.println(Reg2);
delay(100);
SetMuxAddress(Reg2);
  }
  if (millis() > tempus) digitalWrite(13, LOW );//гасим через 50 сек
  // Обновляем выводы Arduino с помощью платы Modbus
   io_poll();
   
}
void io_poll(){
  // Diagnóstico de la comunicación (para debug)
  au16data[6] = slave.getInCnt();  //Devuelve cuantos mensajes se recibieron
  au16data[7] = slave.getOutCnt(); //Devuelve cuantos mensajes se transmitieron
  au16data[8] = slave.getErrCnt(); //Devuelve cuantos errores hubieron
}

void SetMuxAddress(int address)
{
    digitalWrite(S0, (address >> 0) & 0x1);
    digitalWrite(S1, (address >> 1) & 0x1);
    digitalWrite(S2, (address >> 2) & 0x1);
    digitalWrite(S3, (address >> 2) & 0x1);
}

 

 

Acuma
Offline
Зарегистрирован: 08.02.2022

Вот чего добился.


#include <ModbusRtu.h>
#define ID   100 // указали адрес модбас слейва
int multi1;
int multi2;

#define EN 3
#define S0 4
#define S1 5
#define S2 6
#define S3 7 

 int32_t myTimer; 
 Modbus slave(ID, 10, 1); // 100 адрес 1 -485  4- пин
 int8_t state = 0;
 
 unsigned long tempus;
 uint16_t au16data[9]; // массив  регистров
  word Reg2; //устройство 
  word Reg3;


void setup() {
  Serial.begin(9600); //открываем порт
  slave.start(); // запуск
  tempus = millis() + 100; // Сохранить текущее время + 100 мс
  digitalWrite(13, HIGH ); //светодиод на плате
pinMode(S0, OUTPUT); 
  pinMode(S1, OUTPUT); 
  pinMode(S2, OUTPUT); 
  pinMode(S3, OUTPUT);   

  digitalWrite(S0, LOW);
  digitalWrite(S1, LOW);
  digitalWrite(S2, LOW);
  digitalWrite(S3, LOW);

  pinMode(EN, OUTPUT); 
  digitalWrite(EN, LOW);
  
  
}

void loop() {

   state = slave.poll( au16data, 9 ); // Параметры: Таблица регистров для обмена информацией
                                      // Размер таблицы записей
                                      // Возвращает 0, если нет запроса данных
                                      // Возвращает от 1 до 4, если произошла ошибка связи
                                      // Возвращает больше 4, если заказ был обработан правильно
if (state == 0)
{
  Serial.println("Нет данных");
}
if (state <4 && state >0)
{
  Serial.println("ERROR");
}
if (state > 4) { //Si es mayor a 4 = el pedido fué correcto
    tempus = millis() + 50; // Текущее время + 50 мс
     io_poll();

  }
  if (millis() > tempus) digitalWrite(13, LOW );//гасим через 50 сек
  // Обновляем выводы Arduino с помощью платы Modbus
  
   
}
void io_poll(){
  Reg2=au16data[2];
  Reg3=au16data[3];
  Serial.print("multiplexor1");
Serial.print("-");
Serial.println(Reg2);
delay(100);
SetMuxAddress(Reg2);
  delay(100);
}

void SetMuxAddress(int address)
{
    digitalWrite(S0, (address >> 0) & 0x1);
    digitalWrite(S1, (address >> 1) & 0x1);
    digitalWrite(S2, (address >> 2) & 0x1);
    digitalWrite(S3, (address >> 2) & 0x1);
}

В сериал выводится : "нет информации".

Что сделано помимо?

В библиотеке ModbusRtu Изменил следующие строки:
 

void begin(long u32speed = 19200) __attribute__((deprecated));

на 

void begin(long u32speed = 9600) __attribute__((deprecated));

И 

 if (u8txenpin > 1)   // pin 0 & pin 1 are reserved for RX/TX

на 

 

 if (u8txenpin > 19)   // pin 0 & pin 1 are reserved for RX/TX

Комментарий по последней замене:

У ардуино Мега RX - 18; TX-19;

Но увы. 

sadman41
Offline
Зарегистрирован: 19.10.2016

В библиотеке ничего менять не нужно.

RX и TX не перепутали местами?

Acuma
Offline
Зарегистрирован: 08.02.2022
Сегодня купил еще один rs. Попробую без изменения библы. 
А как не менять если от мастера идёт скорость 9600? А в библиотеке стоит параметр 19200.
Мне вернуть rx-tx на 0,1? 
В таком случае не будет коннфликта, когда я буду смотреть мониторинг порта?
sadman41
Offline
Зарегистрирован: 19.10.2016

Вообще не понял, что написали. 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

ТС, похоже, мировой чемпион по генерации чуши. 

Acuma
Offline
Зарегистрирован: 08.02.2022

DetSimen пишет:

ТС, похоже, мировой чемпион по генерации чуши. 

 

Есть такое. 

Венул все в исходное состояние - перепаял RO - RX(0), DI-TX(1);

Скетч:
 

#include <ModbusRtu.h>
#define ID   100 // указали адрес модбас слейва
int multi1;
int multi2;

#define EN 3
#define S0 4
#define S1 5
#define S2 6
#define S3 7 

 int32_t myTimer; 
 Modbus slave(ID, 10, 1); // 100 адрес 1 -485  4- пин
 int8_t state = 0;
 
 unsigned long tempus;
 uint16_t au16data[9]; // массив  регистров
  word Reg2; //устройство 
  word Reg3;


void setup() {
  Serial.begin(9600); //открываем порт
  slave.start(); // запуск
  tempus = millis() + 100; // Сохранить текущее время + 100 мс
  digitalWrite(13, HIGH ); //светодиод на плате
pinMode(S0, OUTPUT); 
  pinMode(S1, OUTPUT); 
  pinMode(S2, OUTPUT); 
  pinMode(S3, OUTPUT);   

  digitalWrite(S0, LOW);
  digitalWrite(S1, LOW);
  digitalWrite(S2, LOW);
  digitalWrite(S3, LOW);

  pinMode(EN, OUTPUT); 
  digitalWrite(EN, LOW);
  
  
}

void loop() {

   state = slave.poll( au16data, 9 ); // Параметры: Таблица регистров для обмена информацией
                                      // Размер таблицы записей
                                      // Возвращает 0, если нет запроса данных
                                      // Возвращает от 1 до 4, если произошла ошибка связи
                                      // Возвращает больше 4, если заказ был обработан правильно
/*if (state == 0)
{
  Serial.println("Нет данных");
}
*/
if (state <4 && state >0)
{
  Serial.println("ERROR");
}
if (state > 4) { //Si es mayor a 4 = el pedido fué correcto
    tempus = millis() + 50; // Текущее время + 50 мс
     io_poll();

  }
  if (millis() > tempus) digitalWrite(13, LOW );//гасим через 50 сек
  // Обновляем выводы Arduino с помощью платы Modbus
  
   
}
void io_poll(){
  Reg2=au16data[2];
  Reg3=au16data[3];
  Serial.print("multiplexor1");
Serial.print("-");
Serial.println(Reg2);
delay(100);
SetMuxAddress(Reg2);
  delay(100);
}

void SetMuxAddress(int address)
{
    digitalWrite(S0, (address >> 0) & 0x1);
    digitalWrite(S1, (address >> 1) & 0x1);
    digitalWrite(S2, (address >> 2) & 0x1);
    digitalWrite(S3, (address >> 2) & 0x1);
}

Но теперь появилась проблема. Начинает сильно греться чип. В прошлый раз тоже самое было. Поэтому и менял модуль. Теперь и этот начал греться. При том я с ним провозился час примерно. И он начал греться! Судя по всему придется ехать завтра за новым.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Каждый час новый модуль?

Ну Вы уж закупите хотя бы штук 720, чтобы на месяц хватило.

Acuma
Offline
Зарегистрирован: 08.02.2022

andriano пишет:

Каждый час новый модуль?

Ну Вы уж закупите хотя бы штук 720, чтобы на месяц хватило.

Сарказм - дело хорошее.

Только вот не могу понять почему горят эти модули! Подключено все напрямую. A(RS485) - A(Устройство); B(RS485) - B(Устройство); Земли не соединял! Неужели паразитное питание?!

sadman41
Offline
Зарегистрирован: 19.10.2016

У меня тоже один китайский счетчик работал-работал по 485 через модуль для ардуины, а потом как херакнул что-то в линию, модуль как нагрелся... и потом стал чушь выдавать ардуине.

Это же не промышленные изделия, а так - для учебы.

Acuma
Offline
Зарегистрирован: 08.02.2022

Полностью согласен. Но мне даже в учебном варианте не справиться =)

b707
Offline
Зарегистрирован: 26.05.2017

Acuma, так куда в итоге у вас подключен Модбас на ардуине - к каким пинам? Если к обычному Сериал - то не ясно, где вы сообщаете библиотеке, что надо использовать этот порт?

Acuma
Offline
Зарегистрирован: 08.02.2022

b707 пишет:

Acuma, так куда в итоге у вас подключен Модбас на ардуине - к каким пинам? Если к обычному Сериал - то не ясно, где вы сообщаете библиотеке, что надо использовать этот порт?

Использую Arduino Mega.

Подключено все так:

Маршрутизатор A - RS485 A;

Маршрутизатор B - RS485 B;



RS485 RO - Arduino RX(0);

RS485 DI - ArduinoTX(1);

RS485 DE и RE - Arduino D10;

RS485 VCC - Arduino 5v;

RS485 GND - Arduino GND;

 

В прошивке подключение к сериалу идет командой: 

slave.start();

В библиотеке эта команда, как я понял, расписана так:

void Modbus::start()
{
    if (u8txenpin > 1)   // pin 0 & pin 1 are reserved for RX/TX
    {
        // return RS485 transceiver to transmit mode
        pinMode(u8txenpin, OUTPUT);
        digitalWrite(u8txenpin, LOW);
    }

 

sadman41
Offline
Зарегистрирован: 19.10.2016

Дак вам же сказали - перенесите 485 с Serial на другой порт. Например, на Serial2. И проверьте RX-TX у Serial2 - бывает, что на меге с алиэкспресса подписаны неправильно входы/выходы.

Библиотеку вообще трогать не надо. У тысяч людей она работает нормально, а у вас порченная что ли?

Acuma
Offline
Зарегистрирован: 08.02.2022

Спасибо. Буду пробовать.

b707
Offline
Зарегистрирован: 26.05.2017

ни в библитеке, ни в примерах нет такого описания обьекта:

Modbus slave(ID, 10, 1); 

откуда вы это взяли?

подробнее - на амперке

b707
Offline
Зарегистрирован: 26.05.2017

sadman41 пишет:

Дак вам же сказали - перенесите 485 с Serial на другой порт. Например, на Serial2. И проверьте RX-TX у Serial2 - бывает, что на меге с алиэкспресса подписаны неправильно входы/выходы.

Библиотеку вообще трогать не надо. У тысяч людей она работает нормально, а у вас порченная что ли?

в первую очередь ему надо разобраться с конструктором, у него сейчас в коде чушь написана. А там может и не придется Сериал менять, если все сделать правильно.