重点--环形缓冲区-----适合在通信中接收数据

为什么要用环形缓冲区
当有大量数据的时候,我们不能存储所有的数据,那么计算机处理数据的时候,只能先处理先来的,处理之后就会把数据释放掉,再处理下一个。那么已经处理的数据的内存就会被浪费掉。因为后来的数据只能往后排队,如果要将剩余的数据都往前移动一次,那么效率就会低下了,肯定不现实,所以,环形队列就出现了。

环形缓冲区是一项很好的技术,不用频繁的分配内存,而且在大多数情况下,内存的反复使用也使得我们能用更少的内存块做更多的事。

例如在串口数据接受中,外设某次发送的报文最大是100个字节,如果使用普通接收方式则需要申请一个100字节的数组。而外设并不是每次都是发送100个字节,当发送50个字节的时候,剩余的50个字节就会被浪费掉。因此引入环形缓冲区,mcu接收到一个数据在串口中断往环形缓冲区里面写一个数据,另一个线程就读一个数据,互相追逐,使用这种方式接收100字节的报文或许只需要20个字节的环形缓冲区,大大节省了内存。

typedef struct {
volatile unsigned int pW; //写位置
volatile unsigned int pR; //读位置
volatile unsigned char buff[RING_BUFF_SIZE];//缓冲区
}RingBuff;
环形缓冲区实现原理

环形缓冲区通常有一个表示读位置的变量和写位置的变量。读位置指向环形缓冲区可读的数据,写位置只想环形缓冲区可写的数据。我们只需要移动读写位置就可以获实现缓冲区的读写。初始化时读写位置都为0。

void RingBuffInitial(RingBuff *dst_buff)
{
dst_buff->pW = 0;
dst_buff->pR = 0;
}
在这里插入图片描述
写数据
往环形缓冲区里面写数据数据时要考虑缓冲区是否已经满了,如果满了就放弃这次的数据。每写入成功一个数据pW位置都要更新W

判断环形缓冲区满的条件是pR ==(pW +1)%RING_BUFF_SIZE则为满

void RingBuffWrite(RingBuff *dst_buff, unsigned char dat)
{

int i;
i = (dst_buff->pW + 1)%RING_BUFF_SIZE;
if(i != dst_buff->pR)
{
    dst_buff->buff[dst_buff->pW] = dat;
    dst_buff->pW = i; //更新pW位置
}

}
在这里插入图片描述
读数据
读取数据要考虑环形缓冲区是否为空。判断条件是pW == pR则为空,读取成功返回0 失败返回-1

每读取成功一个数据pR位置都要更新

int RingBuffRead(RingBuff *dst_buff, unsigned char *dat)
{

if(dst_buff->pW == dst_buff->pR)
{
    return -1;
}
else
{
    *dat = dst_buff->buff[dst_buff->pR];
    dst_buff->pR = (dst_buff->pR+1)%RING_BUFF_SIZE; 更新pW位置
    return 0;
}

}
在这里插入图片描述
可以看出来,读取位置和写位置一直在互相追逐,当读位置追上写位置的时候,表示环形缓冲区数据为空。反过来则表示为满。

完整代码如下
#include <stdio.h>

#define RING_BUFF_SIZE 10

typedef struct {
volatile unsigned int pW;
volatile unsigned int pR;
volatile unsigned char buff[RING_BUFF_SIZE];
}RingBuff;

void RingBuffInitial(RingBuff *dst_buff)
{
dst_buff->pW = 0;
dst_buff->pR = 0;
}

void RingBuffWrite(RingBuff *dst_buff, unsigned char dat)
{

int i;
i = (dst_buff->pW + 1)%RING_BUFF_SIZE;
if(i != dst_buff->pR)
{
    dst_buff->buff[dst_buff->pW] = dat;
    dst_buff->pW = i;
}

}

int RingBuffRead(RingBuff *dst_buff, unsigned char *dat)
{

if(dst_buff->pW == dst_buff->pR)
{
    return -1;
}
else
{
    *dat = dst_buff->buff[dst_buff->pR];
    dst_buff->pR = (dst_buff->pR+1)%RING_BUFF_SIZE; 更新pW位置
    return 0;
}

}

int main()
{
int i=0;
int ret;
unsigned char read_dat;
RingBuff RecvBuff;
RingBuffInitial(&RecvBuff);

 printf("当前位置RecvBuff.pW = %d, RecvBuff.pR = %d\n",RecvBuff.pW,RecvBuff.pR);
for(i = 0; i < 5; i++)
{
    RingBuffWrite(&RecvBuff,'A'+i);
    printf("RecvBuff.pW = %d ,RecvBuff.pR = %d ,RecvBuff.buff[%d] = %c\n",\
           RecvBuff.pW,RecvBuff.pR,i,RecvBuff.buff[i]);
}
printf("当前位置RecvBuff.pW = %d, RecvBuff.pR = %d\n",RecvBuff.pW,RecvBuff.pR);
for(i = 0; i < 5; i++)
{
    ret = RingBuffRead(&RecvBuff,&read_dat);
    if(!ret)
        printf("read_dat = %c\n",read_dat);
    else
        printf("read err\n");
}
printf("当前位置RecvBuff.pW = %d, RecvBuff.pR = %d\n",RecvBuff.pW,RecvBuff.pR);
for(i = 0; i < 5; i++)
{
    ret = RingBuffRead(&RecvBuff,&read_dat);
    if(!ret)
        printf("read_dat = %c\n",read_dat);
    else
        printf("read err\n");
}
printf("当前位置RecvBuff.pW = %d, RecvBuff.pR = %d\n",RecvBuff.pW,RecvBuff.pR);
for(i = 5; i < 10; i++)
{
    RingBuffWrite(&RecvBuff,'A'+i);
    printf("RecvBuff.pW = %d ,RecvBuff.pR = %d ,RecvBuff.buff[%d] = %c\n",\
           RecvBuff.pW,RecvBuff.pR,i,RecvBuff.buff[i]);
}
printf("当前位置RecvBuff.pW = %d, RecvBuff.pR = %d\n",RecvBuff.pW,RecvBuff.pR);
    for(i = 0; i < 5; i++)
{
    ret = RingBuffRead(&RecvBuff,&read_dat);
    if(!ret)
        printf("read_dat = %c\n",read_dat);
    else
        printf("read err\n");
}
printf("当前位置RecvBuff.pW = %d, RecvBuff.pR = %d\n",RecvBuff.pW,RecvBuff.pR);
return 0;

}
在这里插入图片描述
原文连接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值