做嵌入式的基本上都清楚,板子基本上跑起来了,第一个肯定要配置的是串口,便于我们后面调试信息的输出,和一些系统参数的输出,让我们有更直观看见程序的运行。
—————————————————————————————————————————————
硬件平台:TQ2440 (S3C2440A)
开发环境:ADS1.2
时 间:2010-12-12
—————————————————————————————————————————————
1:硬件电路:
底板电路 核心板上的连接管脚
由于TQ2440的板子上只引出了一个串口,也就是用的UART0作为COM1,所以我吗只需要配置相关的引脚为串口功能即可。
接着参考2440的说明文档:
所以把GPH相关的GPH0-3都配置为第二功能UART功能。即可以上至完成了管脚的配置,接着对UART的功能进行配置。
A:UART寄存器:
从2440的数据手册上我们可以知道他的寄存器的地址都是连接着的,所以我们直接用结构体来表示,因为他有3个串口,所以,我们这里就可以用3个不同的结构体指针来操作不同的寄存器。代码如下:
1: #define IO_CON_BASE 0x560000002: #define IO_DAT_BASE 0x560000043:
4: #define UART0_BASE 0x50000000 // UART0 Base Address5: #define UART1_BASE 0x50004000 // UART1 Base Address6: #define UART2_BASE 0x50008000 // UART2 Base Address7:
8: #define REG8(x) (*((volatile unsigned char *)(x)))9: #define REG16(x) (*((volatile unsigned short *)(x)))10: #define REG32(x) (*((volatile unsigned long *)(x)))11:
12: typedef volatile unsigned char reg8;13: typedef volatile unsigned short reg16;14: typedef volatile unsigned long reg32;15:
16: /*17: GPIO_CFG_SET说明: group--表示是那组IO(注意没有GPA)18: index--表示这组中的那个引脚19: type --表示是配置为输入还是输出等其他功能20: */21: #define GPIO_CFG_SET(group,index,type) do{\22: (*(volatile unsigned int*)(IO_CON_BASE+group*0x10))&=~(0x3<<index<<1);\23: (*(volatile unsigned int*)(IO_CON_BASE+group*0x10))|=(type<<index<<1);\24: }while(0)25:
26: /*27: GPIO_DAT_SET说明: group--表示是那组IO(注意没有GPA)28: index--表示这组中的那个引脚29: val --表示对此引脚写入的数据30: */31: #define GPIO_DAT_SET(group,index,val) do{\32: (*(volatile unsigned int*)(IO_DAT_BASE+group*0x10))&=~(0x1<<index);\33: (*(volatile unsigned int*)(IO_DAT_BASE+group*0x10))|=(val<<index);\34: }while(0)35: /*36: 因为GPA的控制寄存器,每个引脚只只占用一位,所以为了能统一这里,就没有把37: GPA加进来,而后面的GPB-GPJ的控制寄存器每个引脚对应2位38: */39: enum{GPB=1,GPC,GPD,GPE,GPF,GPG,GPH,GPI,GPJ};40: /*41: 从GPB开始由于用两位表示此引脚的功能所以有四种可能42: 0代表INPUT,1代表OUTPUT,2代表第三功能,3代表第四功能43: */44: enum{INPUT=0,OUTPUT,THI_FUNC,FOR_FUNC};45: /*46: 定义高低电平47: */48: enum{LOW=0,HIG};49:
50: // UART Registers51: typedef struct {52: reg32 ULCON; // UART Line Control 由于控制数据格式,常用的为N-8-1模式53: reg32 UCON; // UART Control 控制UART的工作状态,例如DMA,中断等54: reg32 UFCON; // UART FIFO Control 控制UART的FIFO,这里没有用到55: reg32 UMCON; // UART MODEM Control 在MODEM模式下的控制寄存器,这里没有用到56: reg32 UTRSTAT; // UART Tx/Rx Status UART发送和接受状态寄存器57: reg32 UERSTAT; // UART Error Status UART错误状态寄存器58: reg32 UFSTAT; // UART FIFO Status UART---FIFO状态寄存器59: reg32 UMSTAT; // UART MODEM Status UART---MODEM状态寄存器60: reg8 UTXH; // UART Tx Hold UART发送数据寄存器 ##注意这里是一个char类型的61: reg8 pad0[3];
62: reg8 URXH; // UART RX Buffer UART接受数据寄存器 ##注意这里是一个char类型的63: reg8 pad1[3];
64: reg32 UBRDIV; // UART Baud Rate Divisor UART的波特率产生器的分频率65: } regUART;
66:
67: #define pUART0 ((regUART *)UART0_BASE)68: #define pUART1 ((regUART *)UART1_BASE)69: #define pUART2 ((regUART *)UART2_BASE)
2:2440的UART的配置
上面已经把相关的寄存器介绍的很清楚了,所以这里的配置就直接给出代码了,因为可以直接参考数据手册得到:
1: void uart_init(void)
2: {
3: //设置GPH[0..3]为uart0的输出引脚
4: GPIO_CFG_SET(GPH,0,THI_FUNC);
5: GPIO_CFG_SET(GPH,1,THI_FUNC);
6: GPIO_CFG_SET(GPH,2,THI_FUNC);
7: GPIO_CFG_SET(GPH,3,THI_FUNC);
8:
9: pUART0->ULCON= 0x03; //N-8-1
10: pUART0->UCON= 0x245; //中断和查询模式
11: pUART0->UFCON= 0x0; //No Use
12: pUART0->UMCON= 0x0; //No Use
13: pUART0->UBRDIV= 26; //当前板子的速度是FCLK:400M,HCLK=100M,PCLK=50M,UATR=115200
14: }
这样串口就能工作起来的了,自己在把链接串口工具配置成相同的波特率就能正常工作了。
3: 相关代码的实现
接下来就是串口发送和接受数据的一些功能函数的实现了,下面也只实现了一些简单的函数:
输出部分:
1: void u_printf(char *fmt,...) //格式化输出
2: {
3: va_list ap;
4: char str[100];
5: va_start(ap,fmt);
6: vsprintf(str,fmt,ap);
7: send_str(str);
8: va_end(ap);
9: }
10: void send_str(char *p_str) //发送一个字符串
11: {
12: while(*p_str!='\0')
13: {
14: if(*p_str=='\n')
15: {
16: send_char('\r');
17: }
18:
19: send_char(*p_str);
20: p_str++;
21: }
22: }
23: void send_char(char cc) //发送一个字符
24: {
25: while(!(pUART0->UTRSTAT& 0x2));
26: pUART0->UTXH=cc;
27: }
输入部分:
1: char get_char(void) //接受一个字符
2: {
3: char cc;
4: while(!(pUART0->UTRSTAT& 0x1));
5: cc=pUART0->URXH;
6: return cc;
7: }
8:
9: void get_str(char *str) //接受一个字符串
10: {
11: /*
12: str_bak是为了存储str地址的,是为了在没有输入的情况下
13: 输入退格,造成程序的崩溃
14: */
15: char *str_bak=str,cc;
16: do{
17: cc = get_char();
18: if(cc=='\b')
19: {
20: if( (int)str_bak < (int)str)
21: {
22: //u_printf("\b \b");
23: send_char('\b');
24: send_char('\b');
25: str--;
26: }
27: }
28: else
29: {
30: *str++ = cc;
31: send_char(cc);
32: }
33: }
34: while(cc!='\r');
35:
36: *str = '\0';
37: send_char('\n');
38: }
4:彩色输出的实现
在公司的调试东西有时候打印的东西太多了,是在没办法找,所以最后实现了这个彩色打印的方法,便于迅速找到自己想得到的打印消息,从而提高工作效率。其彩色打印的原理为:
以下内容来自网上:
+-----------------------------------------------------------------------------------------------+
在 ANSI 兼容终端(例如 xterm、rxvt、konsole 等)里, 可以用彩色显示文本而不仅仅是黑白。
下面的语句就输出高亮的黑色背景的绿色字。
printf("\033[1;40;32m%s\033[0m", Hello,world!\n);
\033 声明了转义序列的开始,然后是 [ 开始定义颜色。后面的 1 定义了高亮显示字符。然后是背景颜色,这里面是40,表示黑色背景。接着是前景颜色,这里面是32,表示绿色。我们用 \033[0m 关闭转义序列, \033[0m 是终端默认颜色。
通过上面的介绍,就知道了如何输出彩色字符了。
下面是对于彩色字符颜色的一些定义:
前景 背景 颜色
---------------------------------------
30 40 黑色
31 41 紅色
32 42 綠色
33 43 黃色
34 44 藍色
35 45 紫紅色
36 46 青藍色
37 47 白色
代码 意义
-------------------------
0 终端默认设置
1 高亮显示
4 使用下划线
5 闪烁
7 反白显示
8 不可见
通过串口收发或显示字符时,我们使用的通常是字符的ASCII码。对于非控制字符,也即键入命令时我们可能使用到的命令字符,在控制台中我们使用了ASCII码值从0x20~0x7e之间的字符。对于控制字符,在常用字符ASCII码对照表中我们可以找到Enter键、Backspace(退格)键以及ESC键的ASCII码,但是却没有上下左右方向键以及Home、End键对应的ASCII码,通过对键盘输入字符的串口收发测试发现,如果在测试时按下了方向键则串口在每次按键后会连续发送出3字节数据,前两字节所有方向键的数据相同,分别是0x1b,0x5b,第3字节对应不同的按键,上下右左方向键分别对应的值为:0x41、0x42、0x43、0x44,Home和End键对应的值为0x48和0x4b。故要检测键盘是否键入了方向键,需要向串口连续读取三字节的数据,同理,要控制光标向左、向右移动或Home、End也需要连续一次向串口发送3字节数据。
+-----------------------------------------------------------------------------------------------+
所以我们只需要通过串口发送相应的指令就OK了,我为了方便将其封装为宏定义的格式:
1: //######################Add by Dreamxi 彩色打印信息##################start
2: //使用格式
3: //cpfcpf(ALLOW_PUT,RED,("+----------------This is Dreamxi Uart cpf test --------------+"));
4: // | | |-------------------------------------------------------------|
5: // 是否允许打印 | |
6: // | |
7: // 打印颜色 |
8: // 打印内容
9: #define ALLOW_PUT 1
10: /*
11: 前景 背景 颜色
12: ---------------------------------------
13: 30 40 黑色
14: 31 41 紅色
15: 32 42 綠色
16: 33 43 黃色
17: 34 44 藍色
18: 35 45 紫紅色
19: 36 46 青藍色
20: 37 47 白色
21: */
22: /* 红 绿 蓝 白 黄 紫红 青蓝 */
23: enum {RED=0,GRE,BLU,WHI,YEL,ZH,GB};
24:
25: #define cpf(DEBUG_MSG,COR,...) do{\
26: if(DEBUG_MSG==1)\
27: {\
28: if(COR==RED)\
29: {\
30: u_printf("\033[1;31;40m");\
31: u_printf(__VA_ARGS__);\
32: }\
33: else if(COR==GRE)\
34: {\
35: u_printf("\033[1;32;40m");\
36: u_printf(__VA_ARGS__);\
37: }\
38: else if(COR==BLU)\
39: {\
40: u_printf("\033[1;34;40m");\
41: u_printf(__VA_ARGS__);\
42: }\
43: else if(COR==WHI)\
44: {\
45: u_printf("\033[1;37;40m");\
46: u_printf(__VA_ARGS__);\
47: }\
48: else if(COR==YEL)\
49: {\
50: u_printf("\033[1;33;40m");\
51: u_printf(__VA_ARGS__);\
52: }\
53: else if(COR==ZH)\
54: {\
55: u_printf("\033[1;35;40m");\
56: u_printf(__VA_ARGS__);\
57: }\
58: else if(COR==GB)\
59: {\
60: u_printf("\033[1;36;40m");\
61: u_printf(__VA_ARGS__);\
62: }\
63: u_printf("\033[0m\r\n");\
64: }\
65: }while(0)
66: //######################Add by Dreamxi 彩色打印信息##################end
使用方法:
1: cpf(ALLOW_PUT,RED,("+----------------This is Dreamxi Uart cpf test --------------+"));
2: cpf(ALLOW_PUT,GRE,("+----------------This is Dreamxi Uart cpf test --------------+"));
3: cpf(ALLOW_PUT,BLU,("+----------------This is Dreamxi Uart cpf test --------------+"));
4: cpf(ALLOW_PUT,WHI,("+----------------This is Dreamxi Uart cpf test --------------+"));
5: cpf(ALLOW_PUT,YEL,("+----------------This is Dreamxi Uart cpf test --------------+"));
6: cpf(ALLOW_PUT,ZH,("+----------------This is Dreamxi Uart cpf test --------------+"));
7: cpf(ALLOW_PUT,GB,("+----------------This is Dreamxi Uart cpf test --------------+"));
最后实现的效果图: