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

Thingy91 UART缓冲区管理问题:首次收数据正常后续返回垃圾值

问题根本原因
  • 未处理uart_fifo_read返回值:该函数返回实际从UART FIFO中读取到的字节数,你每次直接按缓冲区总大小100字节读取,而串口中断触发时FIFO中通常只有几字节有效数据,未被覆盖的缓冲区区域仍残留旧数据或初始随机值。
  • 缺少字符串终止符:C语言字符串要求末尾必须以\0结尾,你所用的传感器发送的原始字符串不会自带\0。首次接收时全局缓冲区默认初始化为全0,因此首次打印正常;后续接收时旧数据未清空,也没有主动补终止符,printk("%s")会一直读到内存中随机出现的\0才停止,就会输出垃圾值。
  • 无拼包处理:1200波特率传输速率极低,传感器发送的较长字符串会分多次中断触发才能完成接收,你每次中断都直接覆盖整个缓冲区,会导致不完整的帧数据混杂,进一步产生乱码。
正确UART缓冲区管理流程
  1. 分配带写入偏移标记的接收缓冲区(简单场景用带偏移的线性缓冲区即可,高并发场景建议用环形缓冲区),记录当前已写入的有效字节数,禁止每次直接覆盖整个缓冲区。
  2. 中断回调中先获取FIFO中可读的字节数,仅读取实际存在的有效数据,逐字节追加到自有接收缓冲区中,同时累加写入偏移。
  3. 每次追加数据后判断是否收到约定的帧结束标记(通常是传感器字符串末尾的\r、\n,或自定义的结束字符),收到结束标记后主动在缓冲区末尾补\0,再交给上层逻辑解析,最后重置写入偏移等待下一帧。
  4. 增加缓冲区溢出保护:写入偏移即将超过缓冲区总大小时,主动重置缓冲区或丢弃旧数据,避免内存越界。
修复参考代码
#include <string.h>
uint8_t message_buf[100];
// 记录当前缓冲区已写入的字节偏移
uint8_t buf_offset = 0;

void uart_cb(struct device *x) {
  uart_irq_update(x);
  int read_bytes;
  uint8_t tmp_byte;

  if (uart_irq_rx_ready(x)) {
    // 逐字节读,避免一次读太多覆盖未处理的数据
    while((read_bytes = uart_fifo_read(x, &tmp_byte, 1)) > 0) {
      // 溢出保护,留1个位置放终止符
      if(buf_offset >= sizeof(message_buf) - 1) {
        buf_offset = 0;
        memset(message_buf, 0, sizeof(message_buf));
      }
      // 假设传感器字符串以换行符\n为结束标记,可根据实际协议修改
      if(tmp_byte == '\n') {
        message_buf[buf_offset] = '\0';
        // 完整帧接收完成,这里可以调用解析逻辑或者打印
        printk("%s", message_buf);
        // 重置缓冲区偏移
        buf_offset = 0;
        memset(message_buf, 0, sizeof(message_buf));
      } else {
        message_buf[buf_offset++] = tmp_byte;
      }
    }
  }
}

void main(){
  struct device *uart = device_get_binding(UART_PORT);
  // 初始化缓冲区
  memset(message_buf, 0, sizeof(message_buf));
  buf_offset = 0;
  // 原有初始化逻辑不变
  uart_irq_callback_set(uart, uart_cb);
  // ...其余逻辑
}

内容的提问来源于stack exchange,提问作者Adeel Ahmed

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 11:45:08