UART简介:
UART(Universal Asynchronous Receiver and Transmitter)通用异步收发器(异步串行通信口),是一种通用的数据通信协议,它包括了RS232、RS499、RS423、RS422和RS485等接口标准规范和总线标准规范,即UART是异步串行通信口的总称。而RS232、RS499、RS423、RS422和RS485等,是对应各种异步串行通信口的接口标准和总线标准,它规定了通信口的电气特性、传输速率、连接特性和接口的机械特性等内容,这些东东都是物理层的概念。通信协议,是属于通信网络中的数据链路层的概念。
一、数据传输流程:
1)平时数据线处于“空闲”状态(1状态)
2)当腰发送数据时,UART改变TxD数据线状态(0状态)并维持一位的时间,这样接收方检测到开始位后。再等1.5位的时间就开始一位一位的检测数据线状态得到所传输的数据。
3)UART一帧中可以有5,6,7,或8位的数据,发送方一位一位的改变数据线的状态,将他们发送出去,首先发送最低位。
4)如果使用校验功能UART在发送完数据后还要发送一校验位,有两种校验方式,奇校验和偶校--数据位连同校验位中,“1”的数目等于奇数或偶数
5)最后发送停止位,数据线状态恢复到“空闲”状态(1状态)停止位的状态有三种1位,1.5位,2位。
起始位:先发出一个逻辑”0”信号,表示传输字符的开始。
数据位:可以是5~8位逻辑”0”或”1”。如ASCII码(7位),扩展BCD码(8位)。小端传输
校验位:数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验)
停止位:它是一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。
空闲位:处于逻辑“1”状态,表示当前线路上没有资料传送。
二、操作步骤:
第一步:配置引脚
通过硬件原理图可以知道使用的是MAX3232SOP芯片 使用的是TX0 和RXD0 对应的配置寄存器是GPA通过数据手册可知GPA的地址及每位所代表的意义。通过数据手册可以知道通过配置GPACON的相应管脚就可以将其设置为UART功能。
Register Address
GPACON 0x7F008000
GPA0 [3:0] 0000 = Input 0001 = Output
0010 = UART RXD[0] 0011 = Reserved
0100 = Reserved 0101 = Reserved
0110 = Reserved 0111 = External Interrupt Group 1 [0]
GPA1 [7:4] 0000 = Input 0001 = Output
0010 = UART TXD[0] 0011 = Reserved
0100 = Reserved 0101 = Reserved
0110 = Reserved 0111 = External Interrupt Group 1 [1]
故只需要将GPACON的第八位赋值成 0x00100010即可将GPA配置成UART
第二步:设置数据格式
由数据手册可知uart数据帧发送是可编程的。它由一个起始位,5~8 个数据位,一个可选的奇偶位和 1~2
个可由行控制寄存器(ULCONn )指定的停止位组成。发送器也可以产生中断条件,在传输过程中,它通过置位逻辑状态 0
来强制串行输出。当目前的发送完全传输完成后,发送中断信号。然后不断传送数据到发送 FIFO 寄存器(在非 FIFO 的模式下,发送保存寄存器。)
word length = 11,8bit的数据
Number of Stop Bit = 0;1bit的停止位
Parity Mode = 000;无校验位
Intfrared Mode =0;使用普通模式
所以ULCON0 = 0x3;
第三步:UART配置
Receive Mode = 01;使用中断模式或轮询模式、
Transmit Mode = 01;使用中断模式或轮询模式
Send Break Signal = 0;普通传输
loop-back Mode = 0;使用回环方式
Clock Selection = 0;使用PCLK作为UART的工作时钟
所以UCON =0x5;UFCON0 用来使能FIFO,UMCON0用来设置无留控
第三步:设置波特率
波特率即每秒传输的数据位数,涉及两个寄存器UBRDIV0和UDIVSLOT0
波特率设置相关公式:DIV_VAL = UBRDIVn + (num of 1’s in UDIVSLOTn)/16. Refer to UART Baud Rate Configure Registers.
PCLK = 66.5MHZ 波特率bps设置为115200。所以(66.5MHZ、(115200*16))-1 =35.08 =UBRDIVn + (num of 1’s in UDIVSLOTn)/16。故设置UBRDIV0 = 35,UDIVSLOT0 = 0x1;
第四步:编码
1 //start.S 2 // 启动代码 3 .global _start 4 5 _start: 6 7 // 把外设的基地址告诉CPU 8 ldr r0, =0x70000000 9 orr r0, r0, #0x13 10 mcr p15,0,r0,c15,c2,4 11 12 // 关看门狗 13 ldr r0, =0x7E004000 14 mov r1, #0 15 str r1, [r0] 16 17 // 设置栈 18 ldr sp, =0x0C002000 19 20 // 开启icaches 21 #ifdef CONFIG_SYS_ICACHE_OFF 22 bic r0, r0, #0x00001000 @ clear bit 12 (I) I-cache 23 #else 24 orr r0, r0, #0x00001000 @ set bit 12 (I) I-cache 25 #endif 26 mcr p15, 0, r0, c1, c0, 0 27 28 // 设置时钟 29 bl clock_init 30 31 // 调用C函数点灯 32 bl main 33 34 halt: 35 b halt 36 //Tiny6410Addr.h 37 #ifndef _Tiny6410Addr_H 38 #define _Tiny6410Addr_H 39 //GPK 40 #define GPKIO_BASE (0x7F008800) 41 #define rGPKCON0 (*((volatile unsigned long *)(GPKIO_BASE+0x00))) 42 #define rGPKDAT (*((volatile unsigned long *)(GPKIO_BASE+0x08))) 43 44 //CLOCK 45 #define APLL_LOCK (*((volatile unsigned long *)0x7E00F000)) 46 #define MPLL_LOCK (*((volatile unsigned long *)0x7E00F004)) 47 #define EPLL_LOCK (*((volatile unsigned long *)0x7E00F008)) 48 #define OTHERS (*((volatile unsigned long *)0x7E00F900)) 49 #define CLK_DIV0 (*((volatile unsigned long *)0x7E00F020)) 50 #define APLL_CON (*((volatile unsigned long *)0x7E00F00C)) 51 #define MPLL_CON (*((volatile unsigned long *)0x7F00F010)) 52 #define CLK_SRC (*((volatile unsigned long *)0x7E00F01C)) 53 54 //GPA /uart 55 #define ULCON0 (*((volatile unsigned long *)0x7F005000)) 56 #define UCON0 (*((volatile unsigned long *)0x7F005004)) 57 #define UFCON0 (*((volatile unsigned long *)0x7F005008)) 58 #define UMCON0 (*((volatile unsigned long *)0x7F00500C)) 59 #define UTRSTAT0 (*((volatile unsigned long *)0x7F005010)) 60 #define UFSTAT0 (*((volatile unsigned long *)0x7F005018)) 61 #define UTXH0 (*((volatile unsigned char *)0x7F005020)) 62 #define URXH0 (*((volatile unsigned char *)0x7F005024)) 63 #define UBRDIV0 (*((volatile unsigned short *)0x7F005028)) 64 #define UDIVSLOT0 (*((volatile unsigned short *)0x7F00502C)) 65 #define GPACON (*((volatile unsigned long *)0x7F008000)) 66 67 68 69 #endif 70 71 72 73 //uart.c 74 // 功能:初始化串口 75 #include "uart.h" 76 #include "Tiny6410Addr.h" 77 78 79 void uart_init(void) 80 { 81 /* 1. 配置引脚 */ 82 GPACON &= ~0xff; 83 GPACON |= 0x22; 84 85 /* 2. 设置数据格式等 */ 86 ULCON0 = 0x3; // 数据位:8, 无校验, 停止位: 1, 8n1 87 UCON0 = 0x5; // 时钟:PCLK,禁止中断,使能UART发送、接收 88 UFCON0 = 0x01; // FIFO ENABLE 89 UMCON0 = 0; // 无流控 90 91 /* 3. 设置波特率 */ 92 // DIV_VAL = (PCLK / (bps x 16 ) ) - 1 = (66500000/(115200x16))-1 = 35.08 93 // DIV_VAL = 35.08 = UBRDIVn + (num of 1’s in UDIVSLOTn)/16 94 UBRDIV0 = 35; 95 UDIVSLOT0 = 0x1; 96 97 } 98 99 /* 接收一个字符 */ 100 char get_char(void) 101 { 102 while ((UFSTAT0 & 0x7f) == 0); // 如果RX FIFO空,等待 103 return URXH0; // 取数据 104 } 105 106 /* 发送一个字符 */ 107 void put_char(char c) 108 { 109 while (UFSTAT0 & (1<<14)); // 如果TX FIFO满,等待 110 UTXH0 = c; // 写数据 111 } 112 113 114 //uart.h 115 char get_char(void); 116 void put_char(char c); 117 void init_uart(void); 118 119 //clock.c 120 #include "Tiny6410Addr.h" 121 // 功能:c语言初始化时钟 122 123 124 #define ARM_RATIO 0 // ARMCLK = DOUTAPLL / (ARM_RATIO + 1) = 532/(0+1) = 532 MHz 125 #define MPLL_RATIO 0 // DOUTMPLL = MOUTMPLL / (MPLL_RATIO + 1) = 532/(0+1) = 532 MHz 126 #define HCLKX2_RATIO 1 // HCLKX2 = HCLKX2IN / (HCLKX2_RATIO + 1) = 532/(1+1) = 266 MHz 127 #define HCLK_RATIO 1 // HCLK = HCLKX2 / (HCLK_RATIO + 1) = 266/(1+1) = 133 MHz 128 #define PCLK_RATIO 3 // PCLK = HCLKX2 / (PCLK_RATIO + 1) = 266/(3+1) = 66.5 MHz 129 130 131 132 #define APLL_CON_VAL ((1<<31) | (266 << 16) | (3 << 8) | (1)) 133 134 135 #define MPLL_CON_VAL ((1<<31) | (266 << 16) | (3 << 8) | (1)) 136 137 138 139 void clock_init(void) 140 { 141 /* 1. 设置各PLL的LOCK_TIME,使用默认值 */ 142 APLL_LOCK = 0xffff; // APLL_LOCK,供cpu使用 143 MPLL_LOCK = 0xffff; // MPLL_LOCK,供AHB(存储/中断/lcd等控制器)/APB(看门狗,定时器,SD等)总线上的设备使用 144 EPLL_LOCK = 0xffff; // EPLL_LOCK,供UART,IIS,IIC使用 145 146 /* 2. 设置为异步模式(Asynchronous mode) */ 147 OTHERS &= ~0xc0; //《linux installation for u-boot》3.7中:用MPLL作为HCLK和PCLK的Source是异步(ASYNC)模式,用APLL是同步(SYNC)模式 148 while ((OTHERS & 0xf00) != 0); 149 150 /* 3. 设置分频系数 */ 151 CLK_DIV0 = (ARM_RATIO) | (MPLL_RATIO << 4) | (HCLK_RATIO << 8) | (HCLKX2_RATIO << 9) | (PCLK_RATIO << 12); 152 153 /* 4. 设置PLL,放大时钟 */ 154 APLL_CON = APLL_CON_VAL; 155 MPLL_CON = MPLL_CON_VAL; 156 157 /* 5. 选择PLL的输出作为时钟源 */ 158 CLK_SRC = 0x03; 159 } 160 161 //main.c 162 #include "uart.h" 163 int main() 164 { 165 char c; 166 uart_init(); 167 while(1) 168 { 169 c= get_char(); 170 put_char(c+1); 171 } 172 173 return 0; 174 } 175 176 //Makefile 177 uart.bin : start.o clock.o main.o uart.o 178 arm-linux-ld -Ttext 0x50000000 -o uart.elf start.o clock.o main.o uart.o 179 arm-linux-objcopy -O binary uart.elf uart.bin 180 arm-linux-objdump -D uart.elf > uart.dis 181 182 %.o : %.S 183 arm-linux-gcc -g -c -O2 -o [email protected] $^ 184 185 %.o : %.c 186 arm-linux-gcc -g -c -O2 -o [email protected] $^ 187 .PHONY:clean 188 clean: 189 rm *.o *.elf *.bin *.dis