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

Тема в разделе "Arduino & Shields", создана пользователем yden, 17 фев 2017.

  1. yden

    yden Гик

    Здравствуйте.
    Прошу помощи, плиз. Есть 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 передавалось в слейв и обратно.

    Если не трудно покажите мою ошибку, очень нужно.

    Благодарю
     
  2. yden

    yden Гик

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

    Мастер:
    Код (C++):
    /*
       Пример будет использовать packet1, чтобы считать регистр из адреса 0 (значение adc ch0)
       от arduino раба (id=1). Это будет тогда использовать это значение, чтобы скорректировать яркость
       из вовлеченного контакт 9 использований PWM.
       Это будет тогда использовать packet2, чтобы записать регистр (его собственное значение adc ch0), чтобы адресоваться 1
       на arduino рабе (id=1) корректировка яркости вовлеченного контакт 9 использований PWM.
    */

    #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()/*
       
    Слейв:
    Код (C++):
    #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. Если такое число получено\неполучено выполняется аналогичный сценарий с миганием светика.

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

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

    yden Гик

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

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

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

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