恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

101.嵌入式C语言环形缓冲区实战:从原理到完整代码实现

  • 首页
  • 资讯中心
  • /
  • 101.嵌入式C语言环形缓冲区实战:从原理到完整代码实现

相关资讯

MD常见报错解决方法 2026/8/27 12:59:41
程序员那么卷,就业那么难,为什么你还当一名程序员 2026/8/27 12:59:41
Android Retrofit 高级使用与原理 2026/8/27 12:59:41

最新资讯

操作教程丨MaxKB+Ollama:快速构建基于大语言模型的本地知识库问答系统
Cloudberry (七)二级索引
88%企业已用AI,仅31%规模化落地:麦肯锡报告揭示AI应用真实差距!
如何正确部署DeepSeek R1,坚决不建议ollama,看完这一篇你就懂了!!
AI幻觉的本质:为什么 AI 会 “一本正经地胡说八道”!
RAG从入门到精通系列:基础RAG详解

今日推荐

Go语言构建企业级AI服务网关:统一管理英伟达等AI接口调用
LeetCode Hot100(51-60)算法精解与面试技巧
CRC校验实战:从模2除法到HJ212协议排错

本周热门

Nextcloud 桌面客户端:把同步交给它,你只管改文件
如何将 HTML 转成 Word 文档且格式不丢失?html-to-docx 使用教程
Anki 批量操作卡片完整指南:一次搞定上千张,不再逐张修改

本月精选

如何用DamaiHelper实现演唱会门票的智能自动化抢购:完整技术解决方案指南
第4篇:59 倍性能差距的索引瓶颈定位——一次教科书级的全表扫描调优
终极歌词批量下载神器:5分钟解决离线音乐库歌词同步难题

101.嵌入式C语言环形缓冲区实战:从原理到完整代码实现

发布时间:2026/8/27 13:04:41
101.嵌入式C语言环形缓冲区实战:从原理到完整代码实现 一、核心原理回顾环形缓冲区的本质是一个首尾相连的数组通过两个指针维护数据状态写指针wr_ptr指向下一个可写入的位置读指针rd_ptr指向下一个可读取的位置空判断wr_ptr rd_ptr表示缓冲区无数据满判断采用“牺牲一格”策略当(wr_ptr 1) % 缓冲区大小 rd_ptr时判定为满避免空满状态冲突二、完整代码实现1. 头文件定义ring_buffer.h#ifndef __RING_BUFFER_H #define __RING_BUFFER_H #include stdint.h #include stdbool.h #include string.h // 缓冲区大小可根据实际需求调整建议为2的幂次优化模运算 #define RING_BUF_SIZE 64 // 环形缓冲区结构体定义 typedef struct { uint8_t buffer[RING_BUF_SIZE]; // 数据存储数组 uint16_t wr_ptr; // 写指针 uint16_t rd_ptr; // 读指针 } ring_buf_t; // 函数声明 void ring_buf_init(ring_buf_t *rb); bool ring_buf_is_empty(ring_buf_t *rb); bool ring_buf_is_full(ring_buf_t *rb); uint16_t ring_buf_write(ring_buf_t *rb, const uint8_t *data, uint16_t len); uint16_t ring_buf_read(ring_buf_t *rb, uint8_t *data, uint16_t len); uint16_t ring_buf_used_size(ring_buf_t *rb); // 新增获取已用空间 uint16_t ring_buf_free_size(ring_buf_t *rb); // 新增获取剩余空间 #endif2. 功能实现ring_buffer.c#include ring_buffer.h /** brief 初始化环形缓冲区 param rb 缓冲区结构体指针 */ void ring_buf_init(ring_buf_t *rb) { if (rb NULL) return; // 初始化指针为0 rb-wr_ptr 0; rb-rd_ptr 0; // 清空缓冲区数据 memset(rb-buffer, 0, sizeof(rb-buffer)); } /** brief 判断缓冲区是否为空 param rb 缓冲区结构体指针 return true: 空 false: 非空 */ bool ring_buf_is_empty(ring_buf_t *rb) { return (rb-wr_ptr rb-rd_ptr); } /** brief 判断缓冲区是否为满 param rb 缓冲区结构体指针 return true: 满 false: 未满 */ bool ring_buf_is_full(ring_buf_t *rb) { return ((rb-wr_ptr 1) % RING_BUF_SIZE rb-rd_ptr); } /** brief 获取缓冲区已用空间大小 param rb 缓冲区结构体指针 return 已使用的字节数 */ uint16_t ring_buf_used_size(ring_buf_t *rb) { if (rb NULL) return 0; return (rb-wr_ptr - rb-rd_ptr RING_BUF_SIZE) % RING_BUF_SIZE; } /** brief 获取缓冲区剩余空间大小 param rb 缓冲区结构体指针 return 剩余可用字节数 */ uint16_t ring_buf_free_size(ring_buf_t *rb) { if (rb NULL) return 0; return (RING_BUF_SIZE - 1 - ring_buf_used_size(rb)) % RING_BUF_SIZE; } /** brief 向缓冲区写入数据 param rb 缓冲区结构体指针 param data 待写入数据指针 param len 待写入数据长度 return 实际写入的字节数 */ uint16_t ring_buf_write(ring_buf_t *rb, const uint8_t *data, uint16_t len) { if (rb NULL || data NULL || len 0) return 0; uint16_t write_cnt 0; for (uint16_t i 0; i len; i) { if (ring_buf_is_full(rb)) break; // 写入数据并移动指针 rb-buffer[rb-wr_ptr] data[i]; rb-wr_ptr (rb-wr_ptr 1) % RING_BUF_SIZE; write_cnt; } return write_cnt; } /** brief 从缓冲区读取数据 param rb 缓冲区结构体指针 param data 存储读取数据的指针 param len 期望读取的长度 return 实际读取的字节数 */ uint16_t ring_buf_read(ring_buf_t *rb, uint8_t *data, uint16_t len) { if (rb NULL || data NULL || len 0) return 0; uint16_t read_cnt 0; for (uint16_t i 0; i len; i) { if (ring_buf_is_empty(rb)) break; // 读取数据并移动指针 data[i] rb-buffer[rb-rd_ptr]; rb-rd_ptr (rb-rd_ptr 1) % RING_BUF_SIZE; read_cnt; } return read_cnt; }3. 使用示例main.c#include stdio.h #include ring_buffer.h int main() { // 定义并初始化缓冲区 ring_buf_t uart_rx_buf; ring_buf_init(uart_rx_buf); // 测试数据 uint8_t test_data[] {0x01, 0x02, 0x03, 0x04, 0x05}; uint8_t read_buf[10] {0}; // 写入数据 uint16_t write_len ring_buf_write(uart_rx_buf, test_data, 5); printf(写入 %d 字节数据\n, write_len); // 读取数据 uint16_t read_len ring_buf_read(uart_rx_buf, read_buf, 5); printf(读取 %d 字节数据: , read_len); for (uint16_t i 0; i lt; read_len; i) { printf(0x%02X , read_buf[i]); } printf(\n); // 测试空满状态 printf(缓冲区是否为空: %s\n, ring_buf_is_empty(uart_rx_buf) ? 是 : 否); printf(缓冲区是否为满: %s\n, ring_buf_is_full(uart_rx_buf) ? 是 : 否); return 0; }三、关键设计说明结构体封装将缓冲区数组和指针封装在同一个结构体中便于管理多个独立的缓冲区如串口接收、发送各一个安全检查所有函数都加入了空指针判断避免嵌入式系统中常见的崩溃问题原子操作在中断中使用时建议在读写操作前关闭全局中断防止指针竞争性能优化缓冲区大小设为2的幂次时模运算可优化为位与操作(wr_ptr 1) (RING_BUF_SIZE - 1)提升运行效率四、常见问题与扩展如何获取缓冲区已用空间和剩余空间使用新增的实用函数// 获取已用空间 uint16_t used ring_buf_used_size(uart_rx_buf); printf(已用空间: %d 字节\n, used); // 获取剩余空间 uint16_t free ring_buf_free_size(uart_rx_buf); printf(剩余空间: %d 字节\n, free); // 验证已用 剩余 总容量-1牺牲一格策略 printf(验证: %d %d %d (总容量 %d - 1)\n, used, free, used free, RING_BUF_SIZE);支持多字节数据只需修改buffer类型为uint16_t或自定义结构体指针逻辑保持不变内存不足怎么办可动态分配缓冲区内存将结构体中的buffer改为指针类型初始化时传入外部数组这套实现方案已在多个嵌入式项目中验证可直接用于串口、CAN、SPI等外设的数据收发场景。

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号