You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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();
    }

}

问题分析与解决方案

核心原因

  1. 串口频繁启停:每次读取都打开/关闭串口,导致缓冲区数据未完全读取就被中断,出现行合并或截断。
  2. ignore()函数滥用:直接丢弃输入流字符,破坏了数据完整性。
  3. 串口配置不匹配:两端波特率、奇偶校验等参数不一致,可能引发数据乱码。

修复方案

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 20:50:25