Arduino Nano 33 BLE与Due通过UART传输float传感器数据异常如何解决?
你当前代码的核心故障原因如下:
Serial.write()直接传入float类型参数时,仅会输出该float在内存中存储的首字节,无法完整传输占用4字节存储空间的float数据- 接收端
Serial.read()仅返回单字节的int类型值,无法直接还原为原始float数据
方案1:二进制传输(无精度损失、传输效率最高)
通过共用体将float拆分为4字节数组传输,增加帧头帧尾避免数据错位,适合高频率数据采集场景。
Nano端修改后核心代码
float h = 22.5; float x, y, z; int i = 0; unsigned long previousMillis = 0; const long interval = 500; // 定义共用体,用于float和字节数组的互转 union FloatConvert { float value; uint8_t bytes[4]; }; void Acceleration(); void setup() { Serial.begin(9600); Serial1.begin(9600); if (!IMU.begin()) { Serial.println("Failed to initialize IMU!"); while (1); } Serial.println("Read the serial"); } void loop() { Acceleration(); } void Acceleration() { if (IMU.accelerationAvailable()) { IMU.readAcceleration(x, y, z); } unsigned long currentMillis = millis(); if (currentMillis - previousMillis >= interval) { previousMillis = currentMillis; FloatConvert xConv, yConv; xConv.value = x; yConv.value = y; // 帧结构:帧头0xAA + X的4字节 + Y的4字节 + 帧尾0xBB Serial1.write(0xAA); Serial1.write(xConv.bytes, 4); Serial1.write(yConv.bytes, 4); Serial1.write(0xBB); i++; Serial.print("X ist: "); Serial.println(x); Serial.print("y ist: "); Serial.println(y); } }
Due端修改后核心代码
// 共用体定义和发送端保持一致 union FloatConvert { float value; uint8_t bytes[4]; }; uint8_t rxCache[10]; uint8_t rxPos = 0; float recX, recY; void setup() { Serial.begin(9600); Serial1.begin(9600); } void loop() { if(Serial1.available() > 0) { uint8_t curByte = Serial1.read(); // 未找到帧头时直接丢弃无效字节 if(rxPos == 0 && curByte != 0xAA) return; rxCache[rxPos++] = curByte; // 一帧总长度为10字节,收满后解析 if(rxPos == 10) { // 校验帧尾是否正确 if(rxCache[9] == 0xBB) { FloatConvert xConv, yConv; memcpy(xConv.bytes, &rxCache[1], 4); memcpy(yConv.bytes, &rxCache[5], 4); recX = xConv.value; recY = yConv.value; Serial.print("接收X: "); Serial.println(recX); Serial.print("接收Y: "); Serial.println(recY); } // 重置缓存等待下一次接收 rxPos = 0; memset(rxCache, 0, sizeof(rxCache)); } } }
方案2:字符串传输(调试简单、容错性高)
将float转为字符串格式传输,用分隔符区分不同参数,调试时可直接查看串口原始数据,适合低频率采集场景。
Nano端发送代码修改
仅需替换Acceleration函数中的发送逻辑:
void Acceleration() { if (IMU.accelerationAvailable()) { IMU.readAcceleration(x, y, z); } unsigned long currentMillis = millis(); if (currentMillis - previousMillis >= interval) { previousMillis = currentMillis; // 用逗号分隔两个参数,换行作为帧结束标记 Serial1.print(x); Serial1.print(","); Serial1.println(y); i++; Serial.print("X ist: "); Serial.println(x); Serial.print("y ist: "); Serial.println(y); } }
Due端接收代码修改
float recX, recY; void setup() { Serial.begin(9600); Serial1.begin(9600); } void loop() { if(Serial1.available() > 0) { recX = Serial1.parseFloat(); // 跳过分隔符逗号 if(Serial1.read() == ',') { recY = Serial1.parseFloat(); // 跳过结束标记换行 while(Serial1.read() != '\n' && Serial1.available()>0); Serial.print("接收X: "); Serial.println(recX); Serial.print("接收Y: "); Serial.println(recY); } } }
通用注意事项
- 两端串口波特率必须严格一致,建议使用115200替代9600提升传输效率
- 二进制传输场景下如果出现偶发数据错位,帧头帧尾校验机制会自动恢复后续数据的正确性
- 字符串传输场景下不要在参数内容中使用和分隔符、结束标记相同的字符
内容的提问来源于stack exchange,提问作者Alaa Mousa
相关产品推荐
相关产品推荐

