本文介绍如何在单片机等小型嵌入式系统中引入环形缓冲区。
一、环形缓冲的结构。
环形缓冲区,我们知道,有一个读指针,一个写指针,还要有一段连续的内存。它的操作无非是写入数据、读出数据、检查是否为空、是否缓冲区满这四种。于是我们构造一个环形缓冲区的结构体:
这样就构成了环形缓冲的结构体了,因此我们定义一个缓冲区之后,需要初始化这个结构体,还需要对应地写出读、写和判断缓冲区空和缓冲区满的函数。
voidring_buffer_init ( ring_buffer_def *ring_buf , unsigned char *buf , unsigned int length );
unsigned intring_buffer_read ( ring_buffer_def*ring_buffe ,unsigned char *dat ,unsigned int length );
一、采用中断提高串口效率。
uart打印的波特率常见的有4800、9600、19200、38400、57600、115200,但是对于单片机运行起来而言,耗费的时间是巨大的,例如51单片机常见的串口输出函数是这样写的:
voiduart_send_byte( uint8 dat )
串口输出的时候,以9600的波特率计算,发送100个字符,需要的时间是100ms以上,则MCU的大量时间花费在了while(!TI ) 上了,使得MCU整体效率降低,如何提高串口输出效率?当然有办法,那就是利用串口的中断或者DMA,现介绍中断方式提高输出效率的方法。
在使用中断方式发送数据之前,得先有个数据发送缓冲区,用来存放要发送的数据。缓冲区可以选用环形缓冲区的方式,建立环形缓冲区的方法如下:
#defineUART_BUFFER_MAX_LEN 128 //环形缓冲区大小
unsigned charuart_ring_buffer[UART_BUFFER_MAX_LEN]={0};//环形缓冲区数组
unsigned intwrite_pt = 0; //写指针,初始化为0
unsigned intread_pt = 0; //读指针,初始化为0
/* 向环形缓冲区中写一个数据,成功返回0,失败返回1,缓冲区满 */
usnsigned charring_buffer_write ( unsigned char dat )
if ( write_pt + 1 % UART_BUFFER_MAX_LEN != read_pt ){ //缓冲区有数据
uart_ring_buffer[write_pt++] = dat;
write_pt %= UART_BUFFER_MAX_LEN;
/* 向环形缓冲区中读一个数据,成功返回0,失败返回1,缓冲区空 */
unsigned charring_buffer_read ( unsigned char *dat )
if ( read_pt != write_pt ){ //缓冲区有数据
*dat = uart_ring_buffer[read_pt++];
read_pt %= UART_BUFFER_MAX_LEN;
以上,一个简单的环形缓冲区就建立起来了。接下来要修改一下串口发送函数和中断服务函数,以51单片机为例,代码如下:
unsigned charis_data_null = 1; //定义全局变量,标志是否全部发送
voiduart_send_byte ( uint8 dat )
if ( is_data_null ){ //如果发送缓冲区空
SBUF = dat; //需要发送一次,用以激活中断
while ( ring_buffer_write ( dat ) ); //则写入缓存,如果缓存已满,则等待。
void uart_isr ()interrupt 4
unsigned char dat; //临时变量
if ( ring_buffer_read ( &dat ) ){ //如果缓冲区有数据
is_data_null = 0; //否则,标记为空
这样,就可以使用中断方式进行串口打印输出了。该方法可以很简单移植到其他单片机上。当然,接收部分用中断方式更加常见,建议也使用环形缓冲或者乒乓缓冲的方式接收数据,后面专门介绍环形缓冲和乒乓缓冲的方法,这里暂不做介绍。
串口是单片机开发、嵌入式开发中不可或缺的调试和通讯工具,本文介绍的技巧思路很容易移植到其他平台上,用上它,可以调高开发效率,希望我的经验思路能够帮助到你。