一、原理解析
UART(Universal Asynchronous Receiver/Transmitter,通用异步接收/发送装置)用于异步通信,可以实现全双工发送和接收。它不仅可以实现不同嵌入式系统之间的通信,还可以实现与PC之间的通信。
数据传输流程如下:
(1)平时数据线处于空闲状态(1状态);
(2)当要发送数据时,UART改变TxD数据线的状态(变为0状态)并维持1位的时间,这样接收方检测到开始位后,在等待1.5位的时间就开始一位一位地检测数据线的状态得到所传输的数据;
(3)UART一帧中可以有5、6、7或8位的数据,发送方一位一位地改变数据线的状态将他们发送出去,首先发送最低位;
(4)如果使用校验功能,UART在发送完数据后,还要发送1位校验位。有两种校验方法:奇校验、偶校验——数据位连同校验位中,1的数据等于奇数或偶数;
(5)最后,发送停止位,数据线恢复到空闲状态(1状态)。停止位的长度有3种:1位、1.5位、2位。
下图演示了UART使用7个数据位、偶校验、2个停止位的格式传输字符‘A’(二进制值为0b1000001)时,TTL/COM逻辑电平对应的波形。
s3c2440提供了三个UART端口,它们都可以通过查询、中断和DMA方式传输数据,而且每个UART都分别有一个64个字节的接收FIFO和一个64个字节的发送FIFO。如下图所示:每个UART包含一个波特率发生器、发送器、接收器和一个控制单元。波特率发生器可以由PCLK、FCLK/n或UEXTCLK(外部输入时钟)时钟驱动。UART通过使用系统时钟可以支持最高115.2Kbps的比特率。如果是使用外部器件提供UEXTCLK的UART,则UART可以运行在更高的速度。发送器和接收器各包含一个64字节的FIFO和数据移位器。要发送数据时,先将数据写入到FIFO接着在发送前复制到发送移位器中,随后将数据从发送数据引脚(TXDn)移出;接收数据时,从接收数据引脚(RXDn)移入接收移位器,接着从移位器复制到FIFO。
二、寄存器配置代码
1、配置串口引脚(GPHCON)及内部上拉(GPHUP)
注:在串口开始前的空闲状态处于高电平,开始位为低电平,需要进行内部上拉保证空闲状态为高电平。
2、设置波特率及选择时钟源
3、设置数据格式
4、程序
uart.h
1 #ifndef _UART_H // 如果某个文件第一次包含这个头文件,_UART_H这个宏没有定义时
2 #define _UART_H // 定义_UART_H这个宏
3
4 void uart0_init(void);
5 int putchar(int c);
6 int getchar(void);
7 int puts(const char *s);
8
9 #endif
uart.c
#include "s3c2440_soc.h"
/* 115200,8n1 */
void uart0_init()
{
/* 设置引脚用于串口 */
/* GPH2,3用于TxD0, RxD0 */
GPHCON &= ~((3<<4) | (3<<6)); //寄存器4-7位清0
GPHCON |= ((2<<4) | (2<<6)); //4-7位1010,其余位为1
GPHUP &= ~((1<<2) | (1<<3)); /* 使能内部上拉为高电平,低电平开始位 */
/* 设置波特率 */
/* UBRDIVn = (int)( UART clock / ( buad rate x 16) ) –1
* UART clock = 50M
* UBRDIVn = (int)( 50000000 / ( 115200 x 16) ) –1 = 26
*/
UCON0 = 0x00000005; /* PCLK,中断/查询模式 */
UBRDIV0 = 26;
/* 设置数据格式 */
ULCON0 = 0x00000003; /* 8n1: 8个数据位, 无较验位, 1个停止位 */
/* */
}
int putchar(int c)
{
/* UTRSTAT0 */
/* UTXH0 */
while (!(UTRSTAT0 & (1<<2))); //当发送缓冲寄存器和发送移位器不是空的时候,循环等待
UTXH0 = (unsigned char)c; //反之,当上一个发送完了,再向发送缓冲寄存器写入字符(这里是按单个字节发送)
}
int getchar(void)
{
while (!(UTRSTAT0 & (1<<0))); //当接收缓冲寄存器是空的时候,循环等待
return URXH0; //当接收缓冲寄存器非空的时候,返回接收缓冲寄存器得到的值
}
int puts(const char *s)
{
while (*s)
{
putchar(*s);
s++;
}
}
main.c
1 #include "s3c2440_soc.h"
2 #include "uart.h"
3 int main(void)
4 { unsigned char c;
5 uart0_init();
6 puts("Hello,world!\n\r");
7 while(1)
8 {
9 c=getchar(); // 从PC键盘上得到输入字符(串 )
10 if (c == '\r') // 换行处理 ,不论输入\n或者\r,都会换行并使光标到行首
11 {
12 putchar('\n');
13 }
14 if (c == '\n')
15 {
16 putchar('\r');
17 }
18 putchar(c); // 输出得到的字符(串 )到PC,PC屏幕会显示串口传过来的字符(串 )
19 }
20 return 0;
21 }
makefile
all:
arm-linux-gcc -c -o led.o led.c
arm-linux-gcc -c -o uart.o uart.c
arm-linux-gcc -c -o main.o main.c
arm-linux-gcc -c -o start.o start.S
arm-linux-ld -Ttext 0 start.o led.o uart.o main.o -o uart.elf
arm-linux-objcopy -O binary -S uart.elf uart.bin
arm-linux-objdump -D uart.elf > uart.dis
clean:
rm *.bin *.o *.elf *.dis
三、printf函数实现
部分图片参考http://www.cnblogs.com/Wayne123/p/9818225.html的博客
本文章是基于韦东山JZ2440开发版的学习笔记,日后会不断更新与完善。