UART读取Xbee 3 Pro传输数据异常:行数据合并问题求助
问题:Xbee 3 Pro数据传输出现行合并、结构混乱
我将连接在Teensy 4.0上的Xbee 3 Pro(路由端)数据发送到另一台Xbee 3 Pro(协调器端),能成功接收,但接收的行数据大多合并,结构混乱。
错误的接收数据示例
1.00,4096.00 ,-0.21,-161,-0.79,1.03,23.13,1020.02,-0.21,-16.52,0,0,0,0,0.00,0.00,0.90,0.00,131.00,4096.00 ,-190.00,-225.00,119.00,-0.51,-0.79,1.03,23.13,1020.02,-0.23,-16.52,0,0,0,0,0.00,0.0,1020.02,-0.23,-16.52,0,0,0,0,0.00,0.00,0.89,0.00,131.00,4096.00 .52,0,0,0,0,0.00,0.00,0.8932,-16.52,0,0,0,0,0.00,0.00,0.88,0.00,131.00,4096.00 020.03,-0.43,-16.52,0,0,0,0,0.00,0.00,0.87,00.79,1.03,23.15,1020.06,-0.50,-16.52,0,0,0,0,0.00,0.00,0.86,0.00,131.00,4096.00 214.00,115.00,-0.52,-0.80,1.03,23.13,10,0.06,0.26,0.98,-182.00,-214.00,115.00,-0.52,-0.80,1.03,23.13,1020.03,-0.27,-16.52,00.80,1.03,23.13,1020.03,-0.27,-16.52,0,0,0,0,0.00,0.00,0.83,0.00,131.00,4096.00
Teensy端发送代码
void sendDataTotelemetry(){ Serial3.print(millis()); Serial3.print(","); Serial3.print(data.Accel_X); Serial3.print(","); Serial3.print(data.Accel_Y); Serial3.print(","); Serial3.print(data.Accel_Z); Serial3.print(","); Serial3.print(data.Gyro_X_Raw); Serial3.print(","); Serial3.print(data.Gyro_Y_Raw); Serial3.print(","); Serial3.print(data.Gyro_Z_Raw); Serial3.print(","); Serial3.print(data.Gyro_Yaw); Serial3.print(","); Serial3.print(data.Gyro_Roll); Serial3.print(","); Serial3.print(data.Gyro_Pitch); Serial3.print(","); Serial3.print(data.Baro_Temp); Serial3.print(","); Serial3.print(data.Baro_Pressure); Serial3.print(","); Serial3.print(data.Baro_Altitude); Serial3.print(","); Serial3.print(data.Baro_Altitude_Error); Serial3.print(","); Serial3.print(data.ParachuteOn); Serial3.print(","); Serial3.print(data.LegsDeployed); Serial3.print(","); Serial3.print(data.MotorFired); Serial3.print(","); Serial3.print(data.RocketState); Serial3.print(","); Serial3.print(data.VoltageValue); Serial3.print(","); Serial3.print(data.Voltage); Serial3.print(","); Serial3.print(data.Kal_X_Pos); Serial3.print(","); Serial3.print(data.Kal_X_PosP); Serial3.print(","); Serial3.print(data.Gyro_Sens); Serial3.print(","); Serial3.println(data.Acc_Sens); }
C++端接收代码
void readTelemetryData(){ data.telemetry_conn_port = serial_t_port; serial_t.open(serial_t_port); if (!serial_t.is_open()){ data.telemetry_conn_status = "N/A"; } else{ serial_t.ignore(); getline(serial_t,incoming_data); data.telemetry_conn_status = "SUCCESS"; if (incoming_data.find(',') != std::string::npos){ data_seperated_t = split_data(incoming_data, ','); data.time = data_seperated_t[0]; data.Accel_X = data_seperated_t[1]; data.Accel_Y = data_seperated_t[2]; data.Accel_Z = data_seperated_t[3]; data.Gyro_X_Raw = data_seperated_t[4]; data.Gyro_Y_Raw = data_seperated_t[5]; data.Gyro_Z_Raw = data_seperated_t[6]; data.Gyro_Yaw = data_seperated_t[7]; data.Gyro_Roll = data_seperated_t[8]; data.Gyro_Pitch = data_seperated_t[9]; data.Baro_Temp = data_seperated_t[10]; data.Baro_Pressure = data_seperated_t[11]; data.Baro_Altitude = data_seperated_t[12]; data.Baro_Altitude_Error = data_seperated_t[13]; data.ParachuteOn = data_seperated_t[14]; data.LegsDeployed = data_seperated_t[15]; data.MotorFired = data_seperated_t[16]; data.RocketState = data_seperated_t[17]; data.VoltageValue = data_seperated_t[18]; data.Voltage = data_seperated_t[19]; data.Kal_X_Pos = data_seperated_t[20]; data.Kal_X_PosP = data_seperated_t[21]; data.Gyro_Sens = data_seperated_t[22]; data.Acc_Sens = data_seperated_t[23]; } else { data.message.push_back(incoming_data) ; } serial_t.close(); } }
问题分析与解决方案
核心原因
- 串口频繁启停:每次读取都打开/关闭串口,导致缓冲区数据未完全读取就被中断,出现行合并或截断。
ignore()函数滥用:直接丢弃输入流字符,破坏了数据完整性。- 串口配置不匹配:两端波特率、奇偶校验等参数不一致,可能引发数据乱码。
修复方案
1. 重构接收端串口逻辑
初始化时打开一次串口,持续读取缓冲区数据,确保完整接收每行:
// 初始化串口(程序启动时执行一次) bool initSerial() { data.telemetry_conn_port = serial_t_port; serial_t.open(serial_t_port); if (!serial_t.is_open()) { data.telemetry_conn_status = "N/A"; return false; } // 配置串口参数(与Teensy端保持一致,示例为115200波特率) serial_t.set_option(boost::asio::serial_port_base::baud_rate(115200)); serial_t.set_option(boost::asio::serial_port_base::character_size(8)); serial_t.set_option(boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::none)); serial_t.set_option(boost::asio::serial_port_base::stop_bits(boost::asio::serial_port_base::stop_bits::one)); data.telemetry_conn_status = "SUCCESS"; return true; } // 持续读取并处理数据 void readTelemetryData() { if (!serial_t.is_open()) return; std::string buffer; char c; // 读取所有可用字符,直到遇到换行符再处理整行 while (serial_t.read_some(boost::asio::buffer(&c, 1))) { buffer += c; if (c == '\n') { // 移除多余的回车符 if (!buffer.empty() && buffer.back() == '\r') buffer.pop_back(); processLine(buffer); buffer.clear(); } } } // 处理单行完整数据 void processLine(const std::string& line) { if (line.find(',') == std::string::npos) { data.message.push_back(line); return; } data_seperated_t = split_data(line, ','); // 先检查数据段数量,避免越界访问 if (data_seperated_t.size() >= 24) { data.time = data_seperated_t[0]; data.Accel_X = data_seperated_t[1]; data.Accel_Y = data_seperated_t[2]; data.Accel_Z = data_seperated_t[3]; data.Gyro_X_Raw = data_seperated_t[4]; data.Gyro_Y_Raw = data_seperated_t[5]; data.Gyro_Z_Raw = data_seperated_t[6]; data.Gyro_Yaw = data_seperated_t[7]; data.Gyro_Roll = data_seperated_t[8]; data.Gyro_Pitch = data_seperated_t[9]; data.Baro_Temp = data_seperated_t[10]; data.Baro_Pressure = data_seperated_t[11]; data.Baro_Altitude = data_seperated_t[12]; data.Baro_Altitude_Error = data_seperated_t[13]; data.ParachuteOn = data_seperated_t[14]; data.LegsDeployed = data_seperated_t[15]; data.MotorFired = data_seperated_t[16]; data.RocketState = data_seperated_t[17]; data.VoltageValue = data_seperated_t[18]; data.Voltage = data_seperated_t[19]; data.Kal_X_Pos = data_seperated_t[20]; data.Kal_X_PosP = data_seperated_t[21]; data.Gyro_Sens = data_seperated_t[22]; data.Acc_Sens = data_seperated_t[23]; } else { data.message.push_back("无效数据行: " + line); } }
2. 验证Xbee配置一致性
使用Xbee XCTU工具检查两端设备:
- 波特率与Teensy的
Serial3.begin(xxx)设置一致 - 奇偶校验设为None,停止位设为1,流控制设为None
3. 可选:添加数据校验
发送端在每行末尾添加校验和,接收端验证后再解析,确保数据完整性:
// 发送端修改 void sendDataTotelemetry(){ String line = ""; line += String(millis()); line += "," + String(data.Accel_X); line += "," + String(data.Accel_Y); // ... 拼接所有数据字段 ... line += "," + String(data.Acc_Sens); // 计算简单校验和 byte checksum = 0; for (char c : line) checksum += c; line += "," + String(checksum); Serial3.println(line); }
内容的提问来源于stack exchange,提问作者deepfreeze
相关产品推荐
相关产品推荐

