前言

最近在研究为什么之前搭建的Modbus RS485 IIoT系统不work,抽了个周末,debug了一下,发现Serial.write(buf, len)也许在我新买的Arduino Uno R4 Wifi上有兼容性问题,导致了Modbus protocol的CRC检测一直失败(因为传送的CRC总是不全,无奈orz,同时上传了一个Modbus-Master-Slave-for-Arduino上传了一个"Timeout" on Arduino Uno R4 Wifi due to Serial1.write(buf, len) and CRC check #75,希望能帮到各位用Arduino Uno R4 Wifi 同时又要用 RS485 Modbus RTU的人的说)。

具体问题就是Serial.write(buf, len),本应该传送前len个buf中的元素,但是只传送了len-1个,经过测试SoftwareSerial没有这个问题,但是Serial1存在。具体问题已经在uno-r4-library-compatibility中开了Serial1.write(buf, len) (FAIL) #28

正文

1. Serial1.write(buf, len) (len = 8 只传送 7个元素)

Arduino master:

uint8_t au8Buffer[64];

void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);
  au8Buffer[0] = 1;
  au8Buffer[1] = 3;
  au8Buffer[2] = 0;
  au8Buffer[3] = 1;
  au8Buffer[4] = 0;
  au8Buffer[5] = 4;
  au8Buffer[6] = 21;
  au8Buffer[7] = 22;
}

void loop() {
  Serial1.write(au8Buffer, 8);
}

Arduino slave:

void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);
}

void loop() {
  if(Serial1.available()) {
    Serial.println(Serial1.read());
  }
}

结果如下:
Screenshot from 2024-02-18 21-37-04

2. Serial1.write(buf, len) (len = 9 正好传送 8个元素)

Arduino master:

uint8_t au8Buffer[64];

void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);
  au8Buffer[0] = 1;
  au8Buffer[1] = 3;
  au8Buffer[2] = 0;
  au8Buffer[3] = 1;
  au8Buffer[4] = 0;
  au8Buffer[5] = 4;
  au8Buffer[6] = 21;
  au8Buffer[7] = 22;
}

void loop() {
  Serial1.write(au8Buffer, 9);
}

Arduino slave:

void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);
}

void loop() {
  if(Serial1.available()) {
    Serial.println(Serial1.read());
  }
}

结果如下:
Screenshot from 2024-02-18 21-40-45

3. SoftwareSerial (工作正常 len = 8 就传送 8个)

Arduino master:

#include <SoftwareSerial.h>

#define RX     8
#define TX     11

uint8_t au8Buffer[64];

SoftwareSerial mySerial(RX, TX);

void setup() {
  Serial.begin(9600);
  //Serial1.begin(9600);
  mySerial.begin(9600);
  au8Buffer[0] = 1;
  au8Buffer[1] = 3;
  au8Buffer[2] = 0;
  au8Buffer[3] = 1;
  au8Buffer[4] = 0;
  au8Buffer[5] = 4;
  au8Buffer[6] = 21;
  au8Buffer[7] = 22;
}

void loop() {
  //Serial1.write(au8Buffer, 9);
  mySerial.write(au8Buffer, 8);
}

Arduino slave:

#include <SoftwareSerial.h>

#define RX     8
#define TX     11

SoftwareSerial mySerial(RX, TX);

void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);
}

void loop() {
  //if(Serial1.available()) {
  //  Serial.println(Serial1.read());
  //}

  if(mySerial.available()) {
    Serial.println(mySerial.read());
  }
}

结果如下:
Screenshot from 2024-02-18 21-48-04

4. 解决办法

在所有用到Serial.write(buf, len)的地方,给len手动+1。

总结

挺无奈,但是目前唯一的办法就是在所有用Serial.write(buf, len)的地方,手动给len + 1吧。 /(ㄒoㄒ)/~~

参考

[1] Modbus-Master-Slave-for-Arduino
[2] "Timeout" on Arduino Uno R4 Wifi due to Serial1.write(buf, len) and CRC check #75
[3] uno-r4-library-compatibility
[4] Serial1.write(buf, len) (FAIL) #28

Q.E.D.


立志做一个有趣的碳水化合物