Modbus, rs485, не хотят разговаривать

yden
Offline
Зарегистрирован: 30.01.2016

Здравствуйте.

Прошу помощи, плиз. Есть 2 arduino nano, 2 конвертера rs485, испытательный стенд передачи информации между ардуинками используя modbus. Схема соединения - из интернета. Использую библиотеки SimpleModbusSlave.h и SimpleModbusMaster.h, так же примеры этих библиотек.
 
master:
Код (C++):
#include <SimpleModbusMaster.h>
//////////////////// Макроопределения портов и настройки программы  ///////////////////
#define baud        9600 // скоростьобмена по последовательному интерфейсу. (UART)
#define timeout     1000 // Длительность ожидание ответа (таймаут modbus)
#define polling     200  // скорость опроса по modbus
#define retry_count 10   // количесво запросов modbus до ошибки и останова обмена
#define TxEnablePin 2    // Tx/Rx пин RS485
#define LED1        13    // светодиод 1
 
// Общая сумма доступной памяти на master устройстве, для хранения данных
// не забудьте изменить макроопределение TOTAL_NO_OF_REGISTERS. Если из слейва
// запрашиваешь 4 регистра, то тогда в массиве reg должно быть не меньше 4х ячеек
// для хранения полученных данных.
#define TOTAL_NO_OF_REGISTERS 4
 
// Масив пакетов modbus
// Для добавления новых пакетов просто добавте ихсюда
// сколько вам нужно.
enum
{
  PACKET1,
  PACKET2,
  PACKET3,
  PACKET4,
  TOTAL_NO_OF_PACKETS // эту строку неменять
};
 
// Масив пакетов модбус
Packet packets[TOTAL_NO_OF_PACKETS];
 
// Массив хранения содержимого принятых и передающихся регистров
unsigned int regs[TOTAL_NO_OF_REGISTERS];
 
void setup()
{
  Serial.begin(9600);
// Настраиваем пакеты
// Шестой параметр - это индекс ячейки в массиве, размещенном в памяти ведущего устройства, в которую будет
// помещен результат или из которой будут браться данные для передачи в подчиненное устройство. В нашем коде - это массив reg
// Пакет,SLAVE адрес,функция модбус,адрес регистра,количесво запрашиваемых регистров,локальный адрес регистра.
modbus_construct(&packets[PACKET1], 1, READ_HOLDING_REGISTERS,    0, 1, 0); // чтение данных slave-master (slave адрес 1, регистр 0)
modbus_construct(&packets[PACKET2], 1, READ_HOLDING_REGISTERS,    1, 1, 1); // чтение данных slave-master (slave адрес 1, регистр 1)
// Пакет,SLAVE адрес,функция модбус,адрес регистра,данные,локальный адрес регистра.
modbus_construct(&packets[PACKET3], 1, PRESET_MULTIPLE_REGISTERS, 2, 1, 2); // запись данных master-slave (slave адрес 1, регистр 2)
modbus_construct(&packets[PACKET4], 1, PRESET_MULTIPLE_REGISTERS, 3, 1, 3); // запись данных master-slave (slave адрес 1, регистр 3)
// инициализируем протокол модбус
modbus_configure(&Serial, baud, SERIAL_8N1, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS, regs);
pinMode(LED1, OUTPUT);
 
} // конец void setup()
 
void loop()
{
  modbus_update(); // запуск обмена по Modbus
 
  Serial.println(regs[0]);
  regs[2] = 255;           // запись данных master-slave (slave адрес 1, регистр 2), запись константы
 
} // конец void loop()/*
slave:
Код (C++):
#include <SimpleModbusSlave.h>
//////////////////// Макроопределения портов и настройки программы  ///////////////////
#define TxEnablePin  2       // Tx/Rx пин RS485
#define baud         9600  // скоростьобмена по последовательному интерфейсу. (UART)
#define timeout      1000  // Длительность ожидание ответа (таймаут modbus)
#define polling      200   // скорость опроса по modbus
#define retry_count  10    // количесво запросов modbus до ошибки и останова обмена
#define Slave_ID     1     // Адрес Slave устройсва
#define LED1         13    // светодиод 1
//const int  buttonPin = 3;     // номер входа, подключенный к кнопке
// переменные
int buttonState = 0;         // переменная для хранения состояния кнопки
 
//////////////// Регистры вашего Slave ///////////////////
enum
{    
//Просто добавьте или удалите регистры. Первый регистр начинается по адресу 0
  slave_to_master_val_1,          //  с адресом массива 0
  slave_to_master_val_2,          //  с адресом массива 1
  master_to_slave_val_1,          //  с адресом массива 2
  master_to_slave_val_2,          //  с адресом массива 3
  HOLDING_REGS_SIZE // Это не удалять размер массива HOLDING_REGS.
  //общее количество регистров для функции 3 и 16 разделяет тотже самый массив регистров
  //т.е. то же самое адресное пространство
};
unsigned int holdingRegs[HOLDING_REGS_SIZE]; // функции 3 и 16 массив регистров
////////////////////////////////////////////////////////////
 
void setup()
{
  /* parameters(HardwareSerial* SerialPort,long baudrate,unsigned char byteFormat,unsigned char ID,
     unsigned char transmit enable pin,unsigned int holding registers size,unsigned int* holding register array)
     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
     SERIAL_8N1 option
  */
 
   Serial.begin(9600);
   modbus_configure(&Serial, baud, SERIAL_8N1, Slave_ID, TxEnablePin, HOLDING_REGS_SIZE, holdingRegs);
   modbus_update_comms(baud, SERIAL_8N1, 1); 
   pinMode(LED1, OUTPUT);
  
}// конец void setup()
 
void loop()
{
  int temp;
 
  temp=255;
  modbus_update(); // запуск обмена по Modbus
 
  holdingRegs[slave_to_master_val_1] = temp; // запись данных slave-master
                                                       // (регистр 0), значение из аналогового входа 0.
  holdingRegs[slave_to_master_val_2] = temp;           // запись данных slave-master
                                                       // (регистр 1), запись значения переменной temp. по нажатию кнопки.
  Serial.println(holdingRegs[master_to_slave_val_2]);
}// конец void loop()
Соответственно все это хозяйство собрано на столе. Подключаю модули, поочередно смотрю serial монитор. 
У мастера регистры reg0 и reg1 в мониторе выводит 0. Мастер записывает в регистры (для слейва) reg2 числовое значение 255 - в мастере в мониторе оно видно.
У слейва регистры от мастера так же равны 0. Регистры слейва принимают значение 255 - соответвенно видны в сериал.
Что хочу - число 255 передавалось в слейв и обратно.
 
Если не трудно покажите мою ошибку, очень нужно.
 
Благодарю
nik182
Offline
Зарегистрирован: 04.05.2015

А почитать форум? не? Тем же полно. Вот здесь несколько дней боролись и победили.
https://www.arduino.ru/forum/programmirovanie/modbus-rtu
И да, прочитайте как правильно вставлять код. Есть спец. тема.

yden
Offline
Зарегистрирован: 30.01.2016

Читал я форум, и не один, и не одну тему. Темный лес. А ссылку, выше постом, я вообще как настольную книгу использую - из нее и брал используемые библиотеки и примеры. 

Немного изменил код.

Мастер:

#include <SimpleModbusMaster.h>
//////////////////// Макроопределения портов и настройки программы  ///////////////////
#define baud        9600 // скоростьобмена по последовательному интерфейсу. (UART)
#define timeout     1000 // Длительность ожидание ответа (таймаут modbus)
#define polling     300  // скорость опроса по modbus
#define retry_count 10   // количесво запросов modbus до ошибки и останова обмена
#define TxEnablePin 2    // Tx/Rx пин RS485
#define LED1        13    // светодиод 1

// Общая сумма доступной памяти на master устройстве, для хранения данных
// не забудьте изменить макроопределение TOTAL_NO_OF_REGISTERS. Если из слейва
// запрашиваешь 4 регистра, то тогда в массиве reg должно быть не меньше 4х ячеек
// для хранения полученных данных.
#define TOTAL_NO_OF_REGISTERS 4

// Масив пакетов modbus
// Для добавления новых пакетов просто добавте ихсюда
// сколько вам нужно.
enum
{
  PACKET1,
  PACKET2,
  PACKET3,
  PACKET4,
  TOTAL_NO_OF_PACKETS // эту строку неменять
};

// Масив пакетов модбус
Packet packets[TOTAL_NO_OF_PACKETS];

// Массив хранения содержимого принятых и передающихся регистров
unsigned int regs[TOTAL_NO_OF_REGISTERS];

void setup()
{
  Serial.begin(9600);
// Настраиваем пакеты
// Шестой параметр - это индекс ячейки в массиве, размещенном в памяти ведущего устройства, в которую будет
// помещен результат или из которой будут браться данные для передачи в подчиненное устройство. В нашем коде - это массив reg
 
// Пакет,SLAVE адрес,функция модбус,адрес регистра,количесво запрашиваемых регистров,локальный адрес регистра.
modbus_construct(&packets[PACKET1], 1, READ_HOLDING_REGISTERS,    0, 1, 0); // чтение данных slave-master (slave адрес 1, регистр 0)
modbus_construct(&packets[PACKET2], 1, READ_HOLDING_REGISTERS,    1, 1, 1); // чтение данных slave-master (slave адрес 1, регистр 1)
// Пакет,SLAVE адрес,функция модбус,адрес регистра,данные,локальный адрес регистра.
modbus_construct(&packets[PACKET3], 1, PRESET_MULTIPLE_REGISTERS, 2, 1, 2); // запись данных master-slave (slave адрес 1, регистр 2)
modbus_construct(&packets[PACKET4], 1, PRESET_MULTIPLE_REGISTERS, 3, 1, 3); // запись данных master-slave (slave адрес 1, регистр 3)
// инициализируем протокол модбус
modbus_configure(&Serial, baud, SERIAL_8N1, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS, regs);
 
pinMode(LED1, OUTPUT);

} // конец void setup()

void loop()
{
  modbus_update(); // запуск обмена по Modbus

  //Serial.println(regs[0]);
 
  regs[2] = 20; // запись данных master-slave (slave адрес 1, регистр 2), запись константы
  regs[3] = 20;
  
  if (regs[0] == 30)
 {
  digitalWrite(LED1, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED1, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
 }
 else
 {
  digitalWrite(LED1, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(250);                       // wait for a second
  digitalWrite(LED1, LOW);    // turn the LED off by making the voltage LOW
  delay(250);      
 }
  
} // конец void loop()/*
   

Слейв:

#include <SimpleModbusSlave.h>
//////////////////// Макроопределения портов и настройки программы  ///////////////////
#define TxEnablePin  2	   // Tx/Rx пин RS485
#define baud         9600  // скоростьобмена по последовательному интерфейсу. (UART)
#define timeout      1000  // Длительность ожидание ответа (таймаут modbus)
#define polling      300   // скорость опроса по modbus
#define retry_count  10    // количесво запросов modbus до ошибки и останова обмена
#define Slave_ID     1     // Адрес Slave устройсва
#define LED1         13    // светодиод 1
//const int  buttonPin = 3;     // номер входа, подключенный к кнопке
// переменные
int buttonState = 0;         // переменная для хранения состояния кнопки
 

//////////////// Регистры вашего Slave ///////////////////
enum 
{     
//Просто добавьте или удалите регистры. Первый регистр начинается по адресу 0
  slave_to_master_val_1,          //  с адресом массива 0
  slave_to_master_val_2,          //  с адресом массива 1
  master_to_slave_val_1,          //  с адресом массива 2
  master_to_slave_val_2,          //  с адресом массива 3
  HOLDING_REGS_SIZE // Это не удалять размер массива HOLDING_REGS.
  //общее количество регистров для функции 3 и 16 разделяет тотже самый массив регистров
  //т.е. то же самое адресное пространство
};
unsigned int holdingRegs[HOLDING_REGS_SIZE]; // функции 3 и 16 массив регистров
////////////////////////////////////////////////////////////

void setup()
{ 
  /* parameters(HardwareSerial* SerialPort,long baudrate,unsigned char byteFormat,unsigned char ID, 
     unsigned char transmit enable pin,unsigned int holding registers size,unsigned int* holding register array)
     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
     SERIAL_8N1 option 
  */

   Serial.begin(9600);
   modbus_configure(&Serial, baud, SERIAL_8N1, Slave_ID, TxEnablePin, HOLDING_REGS_SIZE, holdingRegs);
   modbus_update_comms(baud, SERIAL_8N1, 1);  
   pinMode(LED1, OUTPUT);
   digitalWrite(LED1, LOW);
   
}// конец void setup()

void loop()
{
  int temp;
  
  temp=30;
 
  modbus_update(); // запуск обмена по Modbus
  
  holdingRegs[slave_to_master_val_1] = temp; // запись данных slave-master 
                                                       // (регистр 0), значение из аналогового входа 0.
  holdingRegs[slave_to_master_val_2] = temp;           // запись данных slave-master 
                                                       // (регистр 1), запись значения переменной temp. по нажатию кнопки.

 if (holdingRegs[master_to_slave_val_2] == 20)
 {
  digitalWrite(LED1, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED1, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
 }
 else
 {
  digitalWrite(LED1, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(250);                       // wait for a second
  digitalWrite(LED1, LOW);    // turn the LED off by making the voltage LOW
  delay(250);      
 }
  //Serial.println(holdingRegs[master_to_slave_val_2]);
}// конец void loop()

Суть: мастер передает число 20 слейву. Если это число получено, то мигаем 13 пином раз в секунду, если нет такого числа - мигает в 4 раза чаще. И в свою очередь слейв должен ответить мастеру, послав число 30. Если такое число получено\неполучено выполняется аналогичный сценарий с миганием светика.

Итог - ни мастер ни слейв ничего не шлет.

Подскажите плиз, где я не прав.

yden
Offline
Зарегистрирован: 30.01.2016

Попробовал соеднить по этой схеме: http://arrduinolab.blogspot.ru/2015/02/arduino-rs485-2.html

Ардуинки заговорили. Но мне нужен modbus.

На буржуйском форуме рекомендовали притянуть 10к резистором rx к vcc. Сделал, все так же, молчат.

В сериал слейва появляется значение 8L, в мастере - ромбики.