首页 > 基础资料 博客日记

环形缓冲区在嵌入式系统中的应用:串口中断VS主循环

2026-04-07 18:30:02基础资料围观1

文章环形缓冲区在嵌入式系统中的应用:串口中断VS主循环分享给大家,欢迎收藏极客资料网,专注分享技术知识

为什么要用环形缓冲区

假设有这样的场景:串口中断正在快速读取数据,主循环中较慢地解析数据。如果保存串口当前发送的数据后立即做处理,可能会有丢帧的风险。如果我们使用先进先出的数据结构——环形缓冲区,把串口存取的数据存进去,主循环可随时读取,既可以规避掉丢帧的风险,也确保了数据次序正确。

环形缓冲区的实现

需要一个缓存数组,它是固定大小的,来作为环形缓冲区。为了正确的读取数据,我们还需要写指针和读指针。指针的移动,通过_next()函数中指针+1取模实现,确保数组不会越界。

// 1. 缓存数组:固定大小的存储空间(比如256字节)
static volatile uint8_t  s_rxbuf[IMU_UART_RX_BUF_SIZE];
// 2. 写指针:下一个要写入的位置
static volatile uint16_t s_wr = 0;
// 3. 读指针:下一个要读取的位置
static volatile uint16_t s_rd = 0;
// 4. 计算下一个位置(核心:取模实现“环形”)
static inline uint16_t _next(uint16_t idx)
{
   return (uint16_t)((idx + 1u) % IMU_UART_RX_BUF_SIZE);
}

环形缓冲区的使用

回到我们一开始的场景,也就是我们决定使用环形缓冲区的起点,我们遭遇的是串口中断和主循环之间的矛盾。
我们应该在中断中使用写指针写数据。如下_push()函数:计算下一个写入位置,把字节写入写指针指向的环形缓冲区位置。当下一个写位置与读位置相等时,说明缓冲区满了,将读位置后移一位,即丢弃最旧的一个字节。最后把当前写指针后移。

  1. 写入数据 _push() :中断里调用
static inline void _push(uint8_t b)
{
    // 计算下一个写入位置
    uint16_t next = _next(s_wr);
    // 如果【下一个写位置 == 读位置】= 缓冲区满了
    if (next == s_rd) {
        s_rd = _next(s_rd);   // 丢弃最旧的一个字节
    }
    s_rxbuf[s_wr] = b;  // 把字节写入缓存
    s_wr = next;        // 写指针后移
}

同样地,在主循环解析数据时需要用到读指针读取数据。如下_pop()函数:当写指针和读指针指向同一个位置时,说明没有待读数据,返回-1;如果有待读数据,则读出数据,读指针后移。
2. 读取数据 _pop() : 主循环解析调用

static inline int _pop(uint8_t *out)
{
    if (s_wr == s_rd) return -1;  // 空的,没数据可读
    *out = s_rxbuf[s_rd];         // 读出数据
    s_rd = _next(s_rd);           // 读指针后移
    return 0;
}
  1. 状态判断总结
    缓冲区空(没数据)-》s_wr == s_rd
    缓冲区满(存不下)-》 _next(s_wr) == s_rd

文章来源:https://www.cnblogs.com/HPC2H2/p/19831581
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:jacktools123@163.com进行投诉反馈,一经查实,立即删除!

标签:

相关文章

本站推荐

标签云