单片机应用简单技巧-串口
在单片机应用中,UART串口是个应用简单、广泛的工具。串口可以方便地在单片机之间、单片机与计算机直接进行通信,作为上位机和下位机之间的通信桥梁。下面介绍一些实用的串口应用技巧。
一、如何用串口实现printf输出和scanf输入。
在刚学C语言时,我们常用printf标准打印输出函数输出信息,用scanf来获取用户输入,在单片机上同样可以实现这个功能。需要借助串口终端工具,例如windows的超级终端,或者SecureCRT终端软件。还需要用USB转RS232工具连接电脑和UART串口(注意要电平匹配,单片机是TTL电平,九针RS232串口需要转换成TTL电平后方可与单片机直接连接)。
接下来在单片机程序上,需要配置好串口实现串口输出函数(例如:unsigned char uart_send_byte(unsigned char dat);),要实现printf、scanf功能,则必须有响应的库支持,在keil、iar等集成开发环境都集成了相关库。下面只要我们重写printf依赖的putchar函数和scnaf依赖的getkey函数即可。在任意源(.c)文件里,添加一下内容:
#include<stdio.h>
char putchar (char dat )
{
uart_send_byte ( dat );
return dat;
}
char getkey(void) /* 51单片机为例 */
{
while ( !RI ); //等待有数据到来
return SBUF; //返回串口接收的数值
}
在某些编译环境下,putchar的函数原型是int putchar (int);则相应的更改为:
int putchar (int dat )
{
uart_send_byte ( dat );
return dat;
}
如此,便可以在单片机的C程序中使用printf函数和scanf函数了,配合串口终端软件,可以进行调试和交互,值得注意的是,如果想输出换行,在VC环境下只需要printf ( “n” )即可,但是在单片机下需要printf ( “rn” )才行。
二、采用中断提高串口效率。
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; //否则,标记为空
}
}
}
这样,就可以使用中断方式进行串口打印输出了。该方法可以很简单移植到其他单片机上。当然,接收部分用中断方式更加常见,建议也使用环形缓冲或者乒乓缓冲的方式接收数据,后面专门介绍环形缓冲和乒乓缓冲的方法,这里暂不做介绍。
串口是单片机开发、嵌入式开发中不可或缺的调试工具,本文介绍的技巧思路很容易移植到其他平台上,用上它,可以调高开发效率,希望我的经验思路能够帮助到你,