《stm32自学笔记》环形队列简单实现,通俗易懂

环形数组,(循环队列,环形队列,环形缓冲,circular buffer ,ring buffer),能够很好的接收不定长数据。

# define BUFFERMAX 256 /* 1*/ 
static uint8_t UsartBuffer[BUFFERMAX]; /* 2 */ 
static uint8_t BufferWptr =0; /* 3*/ 
static uint8_t BufferRptr =0; /* 4 */ 

/*static volatile uint8_t BufferWptr = 0; // 声明为volatile以避免编译器优化导致的问题  
static volatile uint8_t BufferRptr = 0; */


/*函数名 :BufferWrite 
*函数描述:缓冲区写函数(由通信接口接收中断服务调用)  
*输入参数:无 
*输出结果:无
*返回值 :无
*/ 
void BufferWrite(void){
    if(BufferWptr==(BufferRptr - 1)) /* 5 */ 

/*

  1. if(BufferWptr == (BufferPtr - 1)):检查是否即将发生缓冲区溢出。这里需要注意,(BufferPtr - 1)需要处理BufferPtr为0的情况,否则当BufferPtr为0时,(BufferPtr - 1)会变为BUFFERMAX - 1,可能导致错误的溢出判断。
  2. 正确的溢出判断应该检查BufferWptr的下一位是否等于BufferPtr,而不是BufferWptr是否等于BufferPtr - 1

*/
        return; /* 6 */ 
    UsartBuffer[BufferWptr]=USART_ReceiveData(USART1); /* 7*/ 
    BufferWptr++ ; /* 8 */ 
    BufferWptr = BufferWptr % BUFFERMAX; /* 9*/ 
}

/*

void BufferWrite(void) {  
    uint8_t tempWptr;  
    // 获取当前写指针,并准备增加  
    tempWptr = BufferWptr;  
    tempWptr++;  
    if (tempWptr >= BUFFERMAX) {  
        tempWptr = 0; // 循环回到缓冲区开始  
    }  
    // 检查是否即将发生缓冲区溢出  
    if (tempWptr != BufferRptr) {  
        // 没有溢出,可以安全写入  
        UsartBuffer[BufferWptr] = USART_ReceiveData(USART1);  
        BufferWptr = tempWptr; // 更新写指针  
    }  
    // 否则,忽略这次写入,因为缓冲区已满  

*/

/*函数名 :BufferRead 
*函数描述:缓冲区读函数   
*输人参数:data,待存放读出数据的内存空间地址
*输出结果:无 
*返回值 :0一无数据,1一有数据 
*/
uint8_t BufferRead(uint8_t *data)
{
    if(BufferRptr == BufferWptr) /*10 */ 
        return 0; /* 11 */ 
    *data= UsartBuffer[BufferRptr]; /* 12 */ 
    BufferRptr++; /* 13 */ 
    BufferRptr = BufferRptr %BUFFERMAX; /* 14 */ 
    return 1; /* 15 */ 
}

/*

uint8_t BufferRead(uint8_t *data) {  
    uint8_t tempRptr;  
    // 获取当前读指针,并准备增加  
    tempRptr = BufferRptr;  
    tempRptr++;  
    if (tempRptr >= BUFFERMAX) {  
        tempRptr = 0; // 循环回到缓冲区开始  
    }  
    // 检查缓冲区是否为空  
    if (tempRptr != BufferWptr) {  
        // 非空,可以安全读取  
        *data = UsartBuffer[BufferPtr];  
        BufferPtr = tempRptr; // 更新读指针  
        return 1; // 有数据可读  
    }  
    return 0; // 无数据可读  

*/
//对程序清单6.6.1进行逐一解释。首先是程序定义部分。
//第1句:定义将要开辟的缓冲区的大小,在此定义为256(字节)。
//第2句:开辟一片大小为256字节的缓冲区,供串口设备接收数据暂存使用。
//第3句:定义一个字节变量作为缓冲区写指针。
//第4句:定义一个字节变量作为缓冲区读指针。
//(2)然后是缓冲区写函数BufferWrite。
//第5句:此句的功能是判断缓冲区是否处于“已写满”的状态,下文会给出解释。
//第6句:缓冲区已写满,函数返回。
//第7句:缓冲区未满,读出串口设备接收到的数据,并存放在缓冲区里,存放位置由缓冲区写指针 BufferWptr确定。
//第8句:更新缓冲区写指针BufferWptr。
//第9句:将缓冲区写指针的BufferWptr最大值和最小值对接,形成环形,即该写指针在[0:255]范围内依次循环变化。
//③之后是缓冲区读函数BufferRead。
//第10句:判断缓冲区是否有数据。
//第11句:缓冲区无数据,返回0(表示无数据)。
//第12句:缓冲区有数据,将缓冲区数据读出,读出位置由缓冲区读指针确定BufferRptr。
//第13句:更新缓冲区读指针BufferRptr。
//第14句:将缓冲区读指针BufferRptr的最大值与最小值对接,形成环形,即该写指针也在[0:255]范围内依次循环变化。
//第15句:返回1(表示已有数据读出)。
//可以对程序清单6.6.1的几个重点配合程序的运行过程进行分析。
//首先当然要有数据写进缓冲区才会有数据能被读出来,因此率先对缓冲区进行存取的是BufferWrite函数。
//该函数主要功能为把串口接收到的数据写入缓冲区中,并更新写指针。
//而BufferRead函数则是读出缓冲区的数据,并更新读指针。
//缓冲区主要通过读/写指针的变化来指示缓冲区当前的读/写位置,并且由读/写指针的最大、最小值对接而形成了环形缓冲区。


//!!!不难理解,读指针总是处在一种“追赶”写指针的状态。
//但由于缓冲区被设计成环形,当缓冲区写速度比读速度快时,随着时间的推移,
//最终会出现写指针比读指针整整快了一圈的情况(想象环形跑道上赛跑运动中运动员的套圈情形)。
//因此当这种读指针正好被写指针“套圈”时,就意为着缓冲区已被写满了,无法再写人新的数据。
//Buffer Write函数的第5、6句正是针对这种情况而设的。
//同时这也说明了,读指针却不总是小于写指针的。


//!!!因此判断缓冲区是否有数据,必须使用第10句的写法,而不能写成if(BufferRptr< BufferWptr){…},
//!!!这是一个比较隐蔽的容易忽略的地方。
//但同时读者也应该想到,缓冲区保持在写满的状态,则不会将新接收到的数据保存,这样也是一种数据丢失的情况。

阅读记录,版权归原书作者所有

  • 19
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值