昨天写完了USART1的初始化代码和读写函数,我在结尾的时候说:发送数据采用死等待的方式,这没毛病,而接收数据采用中断的方式。但这里是有问题的,如果某个任务想要读取USART数据,但不知道数据什么时候会发送过来,如果直接采用while(1)死等的方式,则会让MCU在相当长的时间内空转,效率很低。我们暂时先不考虑这个问题,先把中断函数读取到的字节存入缓冲区,这里就有问题了:缓冲区分配多大内存?分配多了,空间浪费;分配少了,数据溢出。我们希望这个缓冲区能够复用,这就是环形缓冲区。
一.环形缓冲区
1.为什么要使用环形缓冲区?上面说到,缓冲区分配多大内存?分配多了,空间浪费;分配少了,数据溢出,我们希望这个缓冲区能够复用。也就是说写数据到了末尾可以从头开始继续写,而不用去分配新的内存。
2.环形缓冲区的设计。缓冲区由一个结构体组成,其成员为:线性数组,读指针和写指针。数据结构本质上有两种:线性和链式结构,本项目不使用链式结构因为单片机资源和性能有限,而链表的遍历和空间分配比较麻烦,因此直接使用数组,并增加读指针和写指针作为读写位置标志。
3.环形缓冲区的使用过程。假设现在向缓冲区写数据,写指针不断向后移动。之后开始读数据,读指针 也不断向后移动,一直将写指针的数据读走,此时所有的数据都读完了,后面位置的数据是未知的,缓冲区空。现在向缓冲区写数据,写指针一直写到了BUF_SIZE-1的位置,此时如果要继续写, 写指针应该回到0位置,继续写,一直写到读指针的前一个位置。此时就不能继续写了,因为后面的数据写入了但没来得及读走,继续写会覆盖原来的数据,造成数据丢失。
4.环形缓冲区的实质。环形缓冲区就是为了复用内存资源而设计的,其读写过程就是读指针和写指针相互追赶的过程。当读指针移动比较快,赶上了写指针时,环形缓冲区空,后面的数据是未知的不能读;当写指针移动比较快,移动到读指针的前一个位置时,环形缓冲区满,后面的数据还没来得及读走,不能继续写。
5.环形缓冲区实例程序
typedef struct ring_buf {
unsigned char ring_buffer[BUF_SIZE];
unsigned int pW;
unsigned int pR;
} ring_buffer;
void ring_buffer_init(ring_buffer* dst_buf)
{
/* 写位置和读位置都初始化为0 */
dst_buf->pR = 0;
dst_buf->pW = 0;
}
int8_t ring_buffer_read(unsigned char* c, ring_buffer* dst_buf)
{
if (dst_buf->pR != dst_buf->pW)
{
*c = dst_buf->ring_buffer[dst_buf->pR];
//第一次写pR指针更新时因为惯性思维直接写了dst_buf->pR ++
//这样显然不对,会造成数组越界
//采用(dst_buf->pR + 1) % BUF_SIZE的方式即实现了循环移动,又不会越界
//因为取模操作本身就是在一个区间内循环
dst_buf->pR = (dst_buf->pR + 1) % BUF_SIZE;
return 0;
}
return -1;
}
void ring_buffer_write(unsigned char c, ring_buffer* dst_buf)
{
/* 写入之前要先判空,缓冲区非空则可以写入;否则忽略掉数据 */
unsigned int write_pos = (dst_buf->pW + 1) % BUF_SIZE;
if (write_pos != dst_buf->pR)
{
dst_buf->ring_buffer[dst_buf->pW] = c;
dst_buf->pW = write_pos;
}
}
测试程序:第一个问题没有解决,作者此时也不知道怎么判断环形缓冲区接收到了数据。但是作者突发奇想,假如确定中断函数先写数据,过一段时间后在读缓冲区就可以测试了。怎么实现呢?答案是延时,在MCU上电后,PC迅速发送数据给MCU,而MCU延时10秒后在读缓冲区。
int main(void)
{
OLED_Init();
myUSART1_Init();
ring_buffer_init(&buffer);
myUSART1_Write('A');
Delay_s(10);
ring_buffer_read(&RxData1, &buffer);
ring_buffer_read(&RxData2, &buffer);
OLED_ShowHexNum(1, 1, RxData1, 2);
OLED_ShowHexNum(2, 1, RxData2, 2);
}
关于文章最开始的问题,作者准备明天再解决,see you tommrow@.@