【问题标题】:Arduino MODBUS RTU communication Delay?Arduino MODBUS RTU 通讯延迟?
【发布时间】:2022-01-10 13:16:59
【问题描述】:

使用 Arduino 编写 MODBUS RTU 代码时出现问题。

首先,通讯成功。 但是,通信是按照请求 -> 请求 -> 响应 -> 请求 -> 请求 -> 响应的顺序进行的。

请参阅下面的视频。 https://youtu.be/Z8tkmY7l-oo

我不知道我的代码有什么问题。

帮帮我..

我的代码是...

#include <Crc16.h>
Crc16 crc;

#define EN0 2

uint8_t n8ID = 1;
uint8_t FunctionCode = 3;

const int DIP_1 = 6;
const int DIP_2 = 7;
const int DIP_3 = 8;
const int DIP_4 = 9;

uint8_t MODBUS_Request[10];

uint8_t Data[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

void setup() 
{
  pinMode(EN0, OUTPUT);

  pinMode(DIP_1, INPUT_PULLUP);
  pinMode(DIP_2, INPUT_PULLUP);
  pinMode(DIP_3, INPUT_PULLUP);
  pinMode(DIP_4, INPUT_PULLUP);
  
  digitalWrite(EN0, LOW);
  
  Serial.begin(9600);

}

void loop() 
{
  digitalWrite(EN0, LOW);

  n8ID = 0;
  n8ID += (!digitalRead(DIP_1)) << 0;
  n8ID += (!digitalRead(DIP_2)) << 1;
  n8ID += (!digitalRead(DIP_3)) << 2;
  n8ID += (!digitalRead(DIP_4)) << 3;

  if (Serial.available())
  {
    uint8_t leng = Serial.readBytes(MODBUS_Request, 8);    
    
    if(MODBUS_Request[0] == n8ID && MODBUS_Request[1] == FunctionCode && MODBUS_Request[2] == 0 && MODBUS_Request[3] == 0)
    {
      uint8_t Request_dataBuff[6];

      for (int i = 0; i < 6; i++)
      {
        Request_dataBuff[i] = MODBUS_Request[i];
      }
      
      unsigned short RequestCRC = (unsigned short)(MODBUS_Request[7] << 8 | MODBUS_Request[6]);
      crc.clearCrc();

      for (uint8_t i = 0; i < 6; i++)
        crc.updateCrc(Request_dataBuff[i]);

      unsigned short CRC_Check = crc.getCrc();
      CRC_Check = crc.Modbus(Request_dataBuff, 0, 6);

      if(RequestCRC == CRC_Check)
      {
        uint8_t send_dataBuff[15] = {n8ID, FunctionCode, 12, Data[0], Data[1], Data[2], Data[3], Data[4], Data[5], Data[6], Data[7], Data[8], Data[9], Data[10], Data[11]};

        crc.clearCrc();
        
        for (uint8_t i = 0; i < 15; i++)
          crc.updateCrc(send_dataBuff[i]);

        unsigned short ResponseCRC = crc.getCrc();
        ResponseCRC = crc.Modbus(send_dataBuff, 0, 15);

        uint8_t Response_CRC_H = ResponseCRC >> 8;
        uint8_t Response_CRC_L = ResponseCRC & 0xFF;

        uint8_t MODBUS_Response[17] = {n8ID, FunctionCode, 12, Data[0], Data[1], Data[2], Data[3], Data[4], Data[5], Data[6], Data[7], Data[8], Data[9], Data[10], Data[11], Response_CRC_L, Response_CRC_H};
        
        digitalWrite(EN0, HIGH);
        
        for(int i = 0; i < 17; i++)
        {
          Serial.write(MODBUS_Response[i]);
          Serial.flush();
        }
        digitalWrite(EN0, LOW);
      }
    }
  }
}

【问题讨论】:

    标签: c++ arduino modbus rs485


    【解决方案1】:

    您的代码增加了大部分延迟。一次写入一个字节的端口会带来巨大的开销。

    也许你可以尝试更换这部分:

    for(int i = 0; i < 17; i++)
        {
          Serial.write(MODBUS_Response[i]);
          Serial.flush();
        }
    

    用更简单的东西:

    Serial.write(MODBUS_Response,17);
    Serial.flush();
    

    一次性写入整个 Modbus 帧。

    如果仅此更改不能解决您的问题,您可能需要就链接另一端的问题提供更多详细信息。

    【讨论】:

    • 感谢您的回答。但是,即使按照您所说的进行更改,症状也是一样的。目前我的设备连接的是Master:1,Slave:1,PC软件作为master。 PC 软件是一个模拟器,可以作为 MODBUS RTU 主机。如果您在 Google 上搜索“MODSCAN64”,您将能够获得有关该软件的信息。所以我的代码一定有问题。
    【解决方案2】:

    您不能连续发送两个请求。

    如果您向两个从站发送两个请求并且它们都同时响应,会发生什么?

    串行通信没有任何机制来避免冲突。

    必须是按照严格顺序同步的master: 请求 -> 响应 -> 请求 -> 响应 ... 等等。

    在收到前一个请求的响应之前,您不能发送新请求。

    【讨论】:

    • 我不明白有两个请求。目前我的设备连接的是Master:1,Slave:1,PC软件作为master。 PC 软件是一个模拟器,可以作为 MODBUS RTU 主机。如果您在 Google 上搜索“MODSCAN64”,您将能够获得有关该软件的信息。
    【解决方案3】:

    原因似乎找到了,但似乎不是根本的解决办法。

    arduino 的默认 Timeout 值为 1000 ms,master 每 1000 ms 向 Slave 请求数据。

    当接收缓冲区 8byte 来自下面的代码时,我想我会继续下一个代码,但我想我正在等待超时时间。 Serial.readBytes(MODBUS_Request, 8);

    我使用Serial.setTimeout()函数作为减少超时时间的解决方案,但这似乎不是一个根本的解决方案。

    即使您使用该功能,只要我设置它,代码就会停止。 我想用Serial.readBytesUntil()函数,但是最后收到的数据是CRC,所以无法预测最后的数据。

    收到数据后,如何继续下一个代码?

    【讨论】:

      【解决方案4】:

      首先

      尝试在 TXEN 线变低之前添加一点延迟,

              digitalWrite(EN0, HIGH);
              
              for(int i = 0; i < 17; i++)
              {
                Serial.write(MODBUS_Response[i]);
                Serial.flush();
              }
              delay(1)  # <-- add a little delay to allow transmission finish 
              digitalWrite(EN0, LOW);
      

      如果波特率真的很低,可能需要增加延迟。

      第二

      在您的代码接收到的实际请求字节之前可能会有一些“0”或随机/噪声值,因此您不能只在一批中读取 8 个字节并将其假定为实际请求。相反,您可能需要一一阅读并弄清楚请求的起始字节在哪里。

      看下面的案例,

      0 0 0 0 0 1 3 x x x x c c   ...   1 3 x x x x c c
      ^ first read  ^ ^ second read     ^ third read  ^  
      | (discard)   | | (timeout)       | (success)   |
      
      

      【讨论】:

      • 添加“延迟”也是如此。将波特率更改为 115200 并不能解决问题......
      猜你喜欢
      • 2022-06-21
      • 2012-10-05
      • 2021-04-20
      • 1970-01-01
      • 2020-06-10
      • 2014-03-06
      • 2019-06-17
      • 2022-08-16
      • 1970-01-01
      相关资源
      最近更新 更多