欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

串口环形缓冲区学习

程序员文章站 2024-02-29 22:26:40
...

说明&感谢

  • 互联网是个开放的世界, 感谢无数开源和分享者, 本次学习主要参考了杰杰的分享, 经了解杰杰现在大学尚未毕业, 而本人工作8年了, 闻道有先后术业有专攻,再次感谢!
  • 参考链接: 杰杰CSDN

环形缓冲区作用

串口数据接收, 如果数据量过大, 很可能来不及处理这些数据, 因此需要把接收的数据存放到一个位置缓存, 待空闲时间处理, 防止接收的数据丢失; 环形缓冲区越大, 那么可以缓存的数据就越多, 这样就是以空间换时间的做法.

编程步骤

  1. UART初始化, 打开串口发送和接收;
  2. UART中断优先级配置NVIC;
  3. 环形缓冲区定义
  4. 环形缓冲区数据接收: 在串口中断中读取收到的数据到环形缓冲;
  5. 环形缓冲区数据发送: 在主程序中把环形缓冲区的数据发送给串口;

代码&分析

#define RINGBUFF_LEN    200     //定义最大接收字节数
#define FLASE   1
#define TRUE    0
  • 结构体定义, 定义了头位置, 尾位置, 和头尾之间间隔数(lenght)
typedef struct
{
    uint16_t heard;
    uint16_t tail;
    uint16_t lenght;    //这个长度指头到尾的长度
    uint8_t  ring_buffer[RINGBUFF_LEN]; //环形缓冲区数组
}RingBufferStruct;
  • 每写一个数据到缓冲区, 尾的位置+1, 即第一次写数据到数组ring_buffer[0], 那么下一次数据写到ring_buffer[1]; 且和头的间隔lenght增加1;
uint8_t write_ring_buffer(uint8_t data)
{
    if(RingBuffer.lenght >= RINGBUFF_LEN) //判断缓冲区是否已满
    {
        return FLASE;
    }
    RingBuffer.ring_buffer[RingBuffer.tail] = data;
    RingBuffer.tail = (RingBuffer.tail + 1) % RINGBUFF_LEN; //防止越界非法访问
    RingBuffer.lenght++;
    return TRUE;
}
  • 每读一个数据, 则头+1; 即第一次读ring_buffer[0], 下一次读数据就是ring_buffer[1]; 且和尾的间隔lenght减1;
uint8_t read_ring_buffer(uint8_t *rData)
{
    if(RingBuffer.lenght == 0)//判断非空
    {
        return FLASE;
    }
    *rData = RingBuffer.ring_buffer[RingBuffer.heard];//先进先出FIFO,从缓冲区头出
    RingBuffer.heard = (RingBuffer.heard + 1) % RINGBUFF_LEN; //防止越界非法访问
    RingBuffer.lenght--;
    return TRUE;
}
  • 串口接收中断中, 把接收的数据写到环形缓冲区;
void USART1_IRQHandler(void)
{
    if(USART_GetFlagStatus(DEBUG_UART, USART_FLAG_RXNE))
    {
        USART_ClearFlag(DEBUG_UART,USART_FLAG_RXNE);//清除中断标志
        write_ring_buffer(USART_ReceiveData(DEBUG_UART));//读取接收到的数据
    }
}
  • 主程序中, 把环形缓冲区的数据读出来, 发送到串口, 打印出来
uint8_t data;
if(0==read_ring_buffer((uint8_t*) &data))
 {
       USART_SendData(DEBUG_UART,data);
 }

实验现象

如果单次发送的数据大于环形缓冲区的大小, 还是会有丢数据的可能;
串口环形缓冲区学习

源代码

MCU型号: STM32F103VET6
开发板: 野火指南者
平台: keil V5.27.0.0
源代码