单片机应用简单技巧 - 环形缓冲

本文介绍如何在单片机等小型嵌入式系统中引入环形缓冲区。
    一、环形缓冲的结构。
 
       环形缓冲区,我们知道,有一个读指针,一个写指针,还要有一段连续的内存。它的操作无非是写入数据、读出数据、检查是否为空、是否缓冲区满这四种。于是我们构造一个环形缓冲区的结构体:
 
typedef struct {   
 
unsigned int read_ptr;   
 
unsigned int write_ptr;   
 
unsigned int size;   
 
unsigned char* buf;
    
}ring_buffer_def;
 
        这样就构成了环形缓冲的结构体了,因此我们定义一个缓冲区之后,需要初始化这个结构体,还需要对应地写出读、写和判断缓冲区空和缓冲区满的函数。   
 
初始化函数:   
 
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 )   
 
{    
 
SBUF = dat;
    
while(!TI);      //等待发送完成
    
}   
 
       串口输出的时候,以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;
 
   
return 0;
   
 
   
}else{            //缓冲区满
 
 
   
return 1;
 
   
}
 
   
}
 
   
/* 向环形缓冲区中读一个数据,成功返回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;
  
   
return 0;
 
   
 
   
}else{                             //缓冲区空
 
   
 
   
 
   
return 1;
 
   
 
   
}
 
   
}
 
   
     以上,一个简单的环形缓冲区就建立起来了。接下来要修改一下串口发送函数和中断服务函数,以51单片机为例,代码如下:
 
   
unsigned charis_data_null = 1;       //定义全局变量,标志是否全部发送
 
   
/* 串口发送函数 */
 
   
voiduart_send_byte ( uint8 dat )
 
   
{
 
   
 
   
if ( is_data_null ){                                 //如果发送缓冲区空
 
   
 
   
 
   
is_data_null = 0;
 
   
 
   
 
   
SBUF = dat;                                  //需要发送一次,用以激活中断
 
   
 
   
}else{                                        //如果发送缓冲区非空
 
   
 
   
 
   
while ( ring_buffer_write ( dat ) );   //则写入缓存,如果缓存已满,则等待。
 
   
 
   
}
 
   
}
 
 
   
/* 串口终端服务函数 */
 
   
void uart_isr ()interrupt 4
 
   
{
 
   
 
   
unsigned char dat;            //临时变量
 
   
 
   
if ( RI ) {                                //接收中断
 
   
 
   
 
   
RI=0;                          //标志位清零
 
   
 
   
}
 
   
 
   
if( TI ){                                                               //发送中断
 
   
 
   
 
   
TI=0;
 
   
 
   
 
   
if ( ring_buffer_read ( &dat ) ){         //如果缓冲区有数据
 
   
 
   
 
   
 
   
SBUF = dat;                                  //则发送它
 
   
 
   
 
   
}else{
 
   
 
   
 
   
 
   
is_data_null = 0;                         //否则,标记为空
 
   
 
   
 
   
}
 
   
 
   
}
 
   
}
 
   
    这样,就可以使用中断方式进行串口打印输出了。该方法可以很简单移植到其他单片机上。当然,接收部分用中断方式更加常见,建议也使用环形缓冲或者乒乓缓冲的方式接收数据,后面专门介绍环形缓冲和乒乓缓冲的方法,这里暂不做介绍。 
   
     串口是单片机开发、嵌入式开发中不可或缺的调试和通讯工具,本文介绍的技巧思路很容易移植到其他平台上,用上它,可以调高开发效率,希望我的经验思路能够帮助到你。
粽子糖果 发表于12-06 14:01 浏览65535次
分享到:

已有0条评论

暂时还没有回复哟,快来抢沙发吧

添加一条新评论

只有登录用户才能评论,请先登录注册哦!

话题作者

粽子糖果
粽子糖果(总统)
金币:41631个|学分:51991个
立即注册
畅学电子网,带你进入电子开发学习世界
专业电子工程技术学习交流社区,加入畅学一起充电加油吧!

x

畅学电子网订阅号