Rs485(modbusrtu)

Тема в разделе "Проводная и беспроводная связь", создана пользователем Acuma, 10 фев 2022.

  1. Acuma

    Acuma Нуб

    Здравствуйте. Столкнулся с проблемой по работе Arduino с внешним устройством по RS485. Мастером в моей цепи выступает некий маршрутизатор с выходом RS485. По протоколу ModbusRtu он отправляет запросы со скоростью 9600 b, 8N2, запросы отправляются командами 0x10 в 2 регистра (2,3). К ардуино так-же подключены мультиплексоры. Принцип работы простой: По модбасу пришло число(0-15), записалось в соответствующий регистр(2 или 3 - первый или второй мультиплексор) и на мультиплексоре выводится значение того порта, номер которого записался в регистр.

    Имею следующий код:
    Код (C++):
    #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);
    }
    Использую 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;

    Данная тема так-же обсуждалась на форуме: http://arduino.ru/forum/pesochnitsa-razdel-dlya-novichkov/modbusrtu - можете ответить и в той ветке...

    Вообще до этого предпринимал изменения библиотеки, тк в ней указана скорость 19200. Думал может в этом дело и поменял значение не 9600. Но на Arduino ru сказали что дело не в этом и я вернул все в исходное положение
    Спасибо за любой ответ=)
     
  2. b707

    b707 Гуру

    откройте описание библиотеки и посмотрите, какие параметры и в каком порядке указываются в этом конструктуоре:
    Код (C++):
    Modbus slave(ID, 10, 1); // 100 адрес 1 -485  4- пин
    а вот это интересненько :
    Код (C++):
    //Si es mayor a 4 = el pedido fué correcto
    hablas espanol?
     
    Acuma нравится это.
  3. Acuma

    Acuma Нуб

    Из примера к библиотеке стоит:
    Код (C++):
    Modbus slave(ID, Serial, 0); //ID del nodo. 0 para el master, 1-247 para esclavo
                            //Puerto serie (0 = TX: 1 - RX: 0)
                            //Protocolo serie. 0 para RS-232 + USB (default), cualquier pin mayor a 1 para RS-485
     
  4. b707

    b707 Гуру

    ссылку на библиотеку дайте, что-то я не видел там испанских комментов :)
     
    Acuma нравится это.
  5. Acuma

    Acuma Нуб

  6. b707

    b707 Гуру

    тогда я не понимаю. откуда вы взяли что Модбас запускается так:
    Код (C++):
    Modbus slave(ID, 10, 1); // 100 адрес 1 -485  4- пин
    когда в библиотеке четко описано так:
    Код (C++):
    Modbus(uint8_t u8id, Stream& port, uint8_t u8txenpin =0);
    в примеры не смотрите, они могут быть устаревшими и даже быть от другой библиотеки. Развивая библиотеку, авторы часто забывают обновить примеры. так что ситуация. что пример относится к версии 1, а библиотека давно версии 12 - не такая уж редкость.
    Правильное описание всегда в исходном коде
     
    Acuma нравится это.
  7. Acuma

    Acuma Нуб

    Хм. Спасибо буду разбираться. 1 - это ID; 2 - это Сериал порт, как я понял; 3 - это что? TX пин?
    Спасибо за оперативный ответ.
     
  8. b707

    b707 Гуру

    да.
    А теперь сравните - как описано у вас. как минимум Сериал и TXпин перепутаны
     
    Acuma нравится это.
  9. Acuma

    Acuma Нуб

    Я правильно понял что Serial пин - это тот пин который я подключил к DE и RE преобразователя?
     
  10. b707

    b707 Гуру

    нет, неправильно
    Я вообще не знаю, что такое "Serial пин", в процитированной мной строчке такого нет:
    Код (C++):
    Modbus(uint8_t u8id, Stream& port, uint8_t u8txenpin =0);
    А пин который вы подключили к DE и RE преобразователя - это TXENpin
     
    Acuma нравится это.
  11. Acuma

    Acuma Нуб

    Да, я не правильно выразился. Сериал порт. Тоесть в моем случае прописать Serial.
     
  12. Acuma

    Acuma Нуб

    Купил новый RS. Все подключил.
    Скетч такой:
    Код (C++):
    #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, Serial1, 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); //открываем порт
      Serial1.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("Нет данных");
    delay(5000);
    }

    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 >> 3) & 0x1);
    }
    В Сериал выводит нет данных. Буду проверять мастер устройство.
     
  13. Acuma

    Acuma Нуб

    Код немного поменял:
    Код (C++):
    #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, Serial1, 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); //открываем порт
      Serial1.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("Нет данных");
    delay(500);
    }
    */

    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 >> 3) & 0x1);
    }
    Теперь выдает это, хотя от маршрутизатора ничего нет:
    Код (Text):
    14:10:34.642 -> multiplexor1-0
    14:10:35.800 -> multiplexor1-0
    14:10:36.971 -> multiplexor1-0
    14:10:38.095 -> multiplexor1-0
    14:10:39.267 -> multiplexor1-0
    14:10:40.431 -> multiplexor1-0
    14:10:41.549 -> multiplexor1-0
    14:10:42.721 -> multiplexor1-0
    14:10:43.893 -> multiplexor1-0
    14:10:45.017 -> multiplexor1-0
    14:10:46.189 -> multiplexor1-0
    14:10:47.361 -> multiplexor1-0
     
    Это что получается? Значение State больше 4?
     
  14. Acuma

    Acuma Нуб

    Все - проверил подключение - заработало! Спасибо большое!
    Не подскажете ,как сделать чтобы выводился только тот регистр, по которому пришла информация? А то у меня в сериал 2 регистра выводятся !
    И еще - как мне отправить ответ мастеру?
    Вот код:
    Код (C++):
    #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, Serial1, 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);
      Serial1.begin(9600); //открываем порт
      slave.start(); // запуск
      tempus = millis() + 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("Нет данных");
    delay(500);
    }
    */

    if (state <4 && state >0)
    {
      Serial.println("ERROR");
    }
    if (state > 4) { //Si es mayor a 4 = el pedido fué correcto
        tempus = millis() + 50; // Текущее время + 50 мс
       

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

        Serial.print("multiplexor2");
    Serial.print("-");
    Serial.println(au16data[3]);
    delay(100);
    SetMuxAddress(au16data[3]);
      delay(100);
     
    }

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

    b707 Гуру

    запоминать предыдущее состояние регистров и выводить только тот, где значение поменялось.