概述
在嵌入式系统中串口可以说是用得最多的工具了,无论是串口通讯还是终端调试,串口的始终必不可少的。在很多时候我们学习单片机和keil时,已经window应用程序是老师都教我们单步调试,断点检查,或者直接一些调试工具比如jlink ,jtag之列的工具。但越来越多的程序开发过于庞大,这种方法都不能很好地跟踪代码的运行。这时候要是有一个能像操作系统一样直接使用printf函数就好了,通过打印信息跟踪代码非常方便。
下面是我曾经在msp430单片机上实现过的一个串口标准输入输出代码。
一、在嵌入式系统里除了实现功能之外,可移植性应该是另一个最应该考虑的哪怕他的功能很简单,所以先列出文件目录。
driver_uart.c //硬件相关的函数
driver_uart.h
serial.c //串口抽象后相关的函数
serial.h
对于driver_uart.c/h 主要存放着包括串口硬件模式的配置,波特率的配置寄存器配置文件的实现。
// file driver_uart.c 硬件相关的函数就不实现了
// file driver_uart.h
struct uart_param
{
unsigned char uart_numble; //串口号
unsigned int bourd_rate; //波特率
unsinged char word_length; //传输字长
unsinged char stop_bit; //停止位
unsinged char uart_mode; //串口模式
BOOL odd_even_check; //奇偶校验
};
unsinged char uart_init(struct uart_param * ); //uart初始化
unsinged char uart_send_byte(unsigned char ); //发送一个字节
unsinged char uatr_get_byte(void); //获取一个字节
char * uart_send_string(char *,int num); //发送字符串
BOOL uart_start(void); //启动uart
BOOL uart_stop(void); //关闭uart
注意uart 驱动层是对串口最底层的操作,他本身不会对发送接受的字符传进行任何处理,所以在和其他设备使用串口通讯时应该使用这层的驱动程序。
二、在serial.h将uart进一步抽象出来,方便移植这里提供一些通用的接口给应用层使用,但这层只是为了串口显示或者支持ascii从机设备显示的可以仿照移植,在做串口通信时不能使用,因为他对发送和接收的字符进行了处理。
// file serial.h
typedef struct serial_type
{
struct uart_param *serial_param; //uart硬件相关的参数
unsinged char (* serial_init)(struct uart_param * ); //串口初始化
unsinged char (* serial_putchar)(unsigned char ); //串口发一个字节
unsinged char (* serial_getchar)(void); //串口接收一个字节
BOOL (* serial _start)(void); //串口启动
BOOL (* serial _stop)(void); //串口关闭
}SerialType;
BOOL serial0_init(void);
void serial0_puts(char *);
char serial0_getchar(void);
printf(char*,....);
scanf(char*);
关键的功能在serila.c中实现
//fileserial.c #include"driver_uart.h" #include<string.h> struct uart_parm serial0_parm { serial_numble = 0; baud_rate = 115200; word_length = 8 ; stop_bit = 1; uart_mode = RX | TX ; odd_even_check = 0; }; //设置uart0 的硬件参数 SerialType serial0 { serial_param = &serial0_parm; serial_init = serial0_init ; serial_putcar = serial0_putchar ; serial_getchar = serial0_getchar ; serial_puts = serial0_puts ; serial_gets = serial0_gets ; serial_start = uart_start ; serial_stop = uart_stop ; } /** **@parm : the char **@function : put an char to uart and echo **@return : char **/ char serial0_putchar(char ch) { if(ch=='n') { uart_send_byte('r'); } uart_send_byte(ch); return ch; } /** **@parm : none **@function : serial 0 get an char from uart **@return : **/ char serial0_getchar(void) { char ch=uart_get_byte(); //从uart获得字符 if(ch != 'n') { uart_send_byte(ch); //回显得到的字符 } uart_send_byte('r'); //回车 uart_send_byte('n'); //换行 return ch; }
/** **@parm : the string buffer point **@function : get an string from uart 0 and echo **@return : the string buffer point **/ char* serial0_gets(char*) { char *str1=str; char ch; while( (ch = uart_get_byte())!='r') //接收到键盘的0x0D { if(c=='b') //判断是否为退格 { if((int)str1 <(int)str) { uart_send_string("b b"); //先退格再输出空格清除之前的位 再退格光标复位 str--; } } else { *str++=c; uart_send_byte(c); //回显 } } *str++='