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

STM32读取TESEO LIV3FL时GPGGA消息过滤异常问题排查

问题原因分析

1. NMEA帧边界处理缺失

NMEA每条消息都是以\r\n结尾的完整帧,你之前的代码应该是在数据流中直接匹配$GPGGA,没等整帧接收完成就输出,导致下一条消息的开头被错误拼接在当前GPGGA消息后,出现内容错乱。

2. 重启乱码&数据截断的诱因

  • 外设配置不同步:重启后初始化顺序错误,导致UART/I2C的波特率、时钟配置未同步,直接引发乱码
  • 缓冲区残留旧数据:重启后未清空接收缓冲区,新数据与残留的旧数据混合,造成乱码
  • I2C读取不完整:GNSS模块分批发送数据,若每次仅读取部分字节,剩余数据会留在I2C缓冲区中,导致后续帧错位、数据截断
解决办法

1. 先收整帧再过滤,避免边收边处理

核心做法:

用环形缓冲区暂存I2C接收的所有字节,从中提取以\r\n结尾的完整NMEA帧,再判断是否为$GPGGA消息,确认后再输出。

代码修改示例(基于HAL库):

#define RING_BUF_SIZE 512
uint8_t ring_buf[RING_BUF_SIZE];
uint16_t buf_head = 0;
uint16_t buf_tail = 0;

// I2C中断接收完成回调
void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c) {
    // 将接收字节存入环形缓冲区
    ring_buf[buf_head] = recv_byte; // 替换为实际接收的字节变量
    buf_head = (buf_head + 1) % RING_BUF_SIZE;
    
    // 开启下一次I2C中断接收
    HAL_I2C_Master_Receive_IT(hi2c, GNSS_I2C_ADDR, &recv_byte, 1);
}

// 帧处理函数,放在主循环中调用
void parse_nmea_frames(void) {
    static uint8_t frame_buf[128]; // NMEA单帧最长约80字节,留冗余空间
    static uint16_t frame_len = 0;
    
    while(buf_head != buf_tail) {
        uint8_t byte = ring_buf[buf_tail];
        buf_tail = (buf_tail + 1) % RING_BUF_SIZE;
        
        if(byte == '\n') {
            // 完整帧接收完成
            frame_buf[frame_len] = '\0';
            // 过滤$GPGGA消息
            if(strstr((char*)frame_buf, "$GPGGA") != NULL) {
                HAL_UART_Transmit(&huart2, frame_buf, frame_len, HAL_MAX_DELAY);
                HAL_UART_Transmit(&huart2, (uint8_t*)"\r\n", 2, HAL_MAX_DELAY);
            }
            frame_len = 0; // 重置帧缓冲区
        } else {
            if(frame_len < sizeof(frame_buf)-1) {
                frame_buf[frame_len++] = byte;
            } else {
                // 缓冲区溢出,直接重置避免异常数据
                frame_len = 0;
            }
        }
    }
}

2. 修复重启乱码问题

  • 调整初始化顺序:先初始化系统时钟(RCC),再初始化I2C和UART,确保外设时钟配置稳定
  • 初始化时清空缓冲区:在main函数初始化阶段,手动清空所有缓冲区,避免旧数据干扰
    // 清空环形缓冲区
    memset(ring_buf, 0, RING_BUF_SIZE);
    buf_head = 0;
    buf_tail = 0;
    // 清空帧缓冲区
    memset(frame_buf, 0, sizeof(frame_buf));
    frame_len = 0;
    
  • 核对I2C速率:TESEO LIV3FL默认I2C速率为100kHz或400kHz,检查STM32的I2C初始化配置,确保两者速率匹配

3. 解决数据截断问题

  • 增大缓冲区容量:若GNSS数据发送速率较高,可将环形缓冲区大小调整为1024字节,避免数据溢出丢包
  • 批量读取I2C数据:先查询GNSS模块I2C缓冲区的可用字节数,一次性读取所有数据,减少中断开销,避免漏读
    // 批量读取可用数据,替代单字节接收
    uint32_t avail_bytes = HAL_I2C_GetRxDataSize(&hi2c1);
    if(avail_bytes > 0) {
        uint8_t temp_buf[32];
        HAL_I2C_Master_Receive(&hi2c1, GNSS_I2C_ADDR, temp_buf, avail_bytes, HAL_MAX_DELAY);
        // 将批量数据存入环形缓冲区
        for(uint32_t i=0; i<avail_bytes; i++) {
            ring_buf[buf_head] = temp_buf[i];
            buf_head = (buf_head + 1) % RING_BUF_SIZE;
        }
    }
    
验证步骤
  1. 烧录修改后的代码,重启设备,检查串口输出是否无乱码
  2. 等待GNSS模块锁定卫星后,确认仅输出完整的$GPGGA消息,无其他内容拼接
  3. 长时间运行设备,验证是否不再出现数据截断或帧错位问题

内容的提问来源于stack exchange,提问作者Airlangga Fidiyanto

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 00:25:30