51单片机串口通信 环形缓冲区队列
最近在做毕业设计刚好涉及到51单片机,简单的研究一下发现51单片机串口只有一个字节的缓存,如果遇到单片机串口中断没有及时处理SBUF的值或者串口中断长时间未退出很容易照成数据丢失,于是就自己写了个缓冲区,代价就是消耗一部分内存空间,时间-空间本来就是一对矛盾体,想减少串口通信中数据丢失问题只能牺牲部分空间,来减少数据通信过程中的丢失问题。
- 核心代码如下所示:
#define BUFFER_MAX 16
typedef struct _circle_buffer{
unsigned char head_pos;
unsigned char tail_pos;
unsigned char circle_buffer[BUFFER_MAX];
}circle_buffer;
circle_buffer buffer;
void bufferPop(unsigned char* _buf)
{
if(buffer.head_pos==buffer.tail_pos)
*_buf=0xFF;
else
{
*_buf=buffer.circle_buffer[buffer.head_pos];
if(++buffer.head_pos>=BUFFER_MAX)
buffer.head_pos=0;
}
}
void bufferPush(const unsigned char _buf)
{
buffer.circle_buffer[buffer.tail_pos]=_buf;
if(++buffer.tail_pos>=BUFFER_MAX)
buffer.tail_pos=0;
if(buffer.tail_pos==buffer.head_pos)
if(++buffer.head_pos>=BUFFER_MAX)
buffer.head_pos=0;
}
考虑到看到此博文的人可能有很多小白并不知道如何使用,在此简单的说一下,假设你已经能进行简单的串口发送接收了,然后串口中断部分可以这样写
void serial1(void) interrupt 4
{
if(RI)
{
bufferPush(SBUF);
RI=0;
}
if(TI)
{
TI=0;
}
}
在主程序中我们只需要调用函数就行了如:
void main()
{
unsigned char dat ;
bufferPop(&dat);
}
bufferPop函数中没调用一次,便从缓冲区取出一个字符,头部指针就会进行偏移,具体看源码并不是很复杂 只是一个数组类型的环形FIFO缓冲区。
有一点要注意的是,如果缓冲区满的话,后面的数据会覆盖最前面的数据。
你可以把缓冲区设置大些,就可以尽可能的减少数据覆盖问题,但是带来的额外问题就是51或者其他系列的单片机RAM是非常小的,并不像PC中缓冲区动不动就1024KB。所以缓冲区设置多大,根据自己需求调整就行了。