在嵌入式开发中,外设通信(如UART、SPI、I2C)的数据接收常面临两大挑战:不定时、不定量数据的实时处理和高频率数据流下的稳定性保障。传统的轮询方式效率低下,而中断驱动的接收逻辑又容易因处理延迟导致数据丢失。
本文提出了一种基于STM32 HAL库的轻量级环形缓冲区解决方案!
已解决
非阻塞数据接收:避免因数据处理延迟导致外设中断阻塞
动态数据缓存:支持UART、SPI、I2C等多种外设的异步数据流
内存高效利用:通过环形缓冲区设计减少内存碎片
跨平台兼容:提供GCC与Keil双版本静态库,无缝适配不同开发环境
实现原理
- HAL库的RxXferCount机制
STM32 HAL库为每个外设句柄(如UART_HandleTypeDef)维护了RxXferCount成员。该计数器在每次接收一个字节后递增,当传输完成时触发回调并重置。项目通过监控RxXferCount的值变化,动态追踪接收数据的边界。
- 环形缓冲区设计
写入策略:通过比较当前RxXferCount与上次记录值的差值,计算新数据长度
覆盖保护:当缓冲区满时自动覆盖旧数据(可配置为阻塞模式)
使用示例- #include "peripheral_buff.h"
- PeripheralBufHandle PeripheralUart1Buf;
- UART_HandleTypeDef uart1_handle;
- char uart1_buffer[1024];
- int uart1_buffer_len;
- int main()
- {
- HAL_Init();
- SystemClock_Config(); // 此处未实现
- USART1_Init(921600); // 此处未实现
- // 缓冲区初始化
- PeripheralUart1Buf = PeripheralBuffer_Init((const uint16_t *)&uart1_handle.RxXferCount, 1024);
- if (!PeripheralUart1Buf)
- {
- printf("peripheral_buffer 初始化失败!(calloc();返回 NULL,检查 startup_stm32fxx_hd.s Heap_Size 值)\n");
- printf("相关网址: https://blog.csdn.net/weixin_42518229/article/details/108574311 \n");
- }
- // 开启中断接收
- HAL_UART_Receive_IT(&uart1_handle, (uint8_t *)PeripheralUart1Buf->Buf, PeripheralUart1Buf->Size);
- while (1)
- {
- if (PeripheralBuffer_ReadInterval(PeripheralUart1Buf)) // 判断当前传输是否已停止,非必要
- {
- uart1_buffer_len = PeripheralBuffer_ReadAvailable(PeripheralUart1Buf); // 读取缓冲区内内容长度
- if (uart1_buffer_len > 0)
- {
- if (uart1_buffer_len > sizeof(uart1_buffer))
- uart1_buffer_len = sizeof(uart1_buffer);
- PeripheralBuffer_ReadBytes(PeripheralUart1Buf, uart1_buffer, uart1_buffer_len); // 读取缓冲区内内容
- uart1_buffer[uart1_buffer_len] = 0;
- printf("缓冲区数据 %s\n", uart1_buffer);
- }
- }
- HAL_Delay(10);
- }
- return 0;
- }
复制代码 注意
1.单次接收超长文件而又未及时处理,会导致数据覆盖。
2.用户缓冲区数据边界
仓库地址
[https://github.com/DYXX-X/peripheral_buff]
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |