UART的使用
友情链接:
借鉴1:https://blog.csdn.net/qq_43743762/article/details/105895303
借鉴2:https://www.cnblogs.com/huangdengtao/p/12103149.html
借鉴3:https://blog.csdn.net/qq_38181811/article/details/87923306
UART串口原理
a. UART介绍
通用异步接收器和发送器(Universal Asynchronous Receiver and Transmitter) 简称UART。通常是嵌入式设备中默认都会配置的通信接口。这是因为,很多嵌入式设备没有显示屏,无法获得嵌入式设备实时数据信息,通过UART串口和超级终端相连,打印嵌入式设备输出信息。并且在对嵌入式系统进行跟踪和调试时,UART串口了是必要的通信手段。比如:网络路由器,交换机等都要通过串口来进行配置。UART串口还是许多硬件数据输出的主要接口,如GPS接收器就是通过UART串口输出GPS接收数据的。
UART是以异步方式实现通信的,,UART传输的双方要统一波特率。其采样速度由波特率决定,波特率产生器的工作频率可以由PCLK(外围设备频率),FCLK/n(CPU工作频率的分频),UEXTCLK(外部输入时钟)三个时钟作为输入频率,波特率设置寄存器是可编程的,用户可以设置其波特率决定发送和接收的频率。发送器和接收器包含了64Byte的FIFO和数据移位器。UART通信是面向字节流的,待发送数据写到FIFO之后,被拷贝到数据移位器(1字节大小)里,数据通过发送数据管脚TXDn发出。同样道理,接收数据通过RXDn管脚来接收数据(1字节大小)到接收移位器,然后将其拷贝到FIFO接收缓冲区里。
UART数据收发
(1)数据发送
发送的数据帧可编程的,它的一个帧长度是用户指定的,它包括一个开始位,5 ~ 8个数据位,一个可选的
奇偶校验位和1~2个停止位,数据帧格式可以通过设置ULCONn寄存器来设置。发送器也可以产生一个终
止信号,它是由一个全部为0的数据帧组成。在当前发送数据被完全传输完以后,该模块发送一个终止信
号。在终止信号发送后,它可以继续通过FIFO(FIFO)或发送保持寄存器(NON-FIFO)发送数据。
(2)数据接收
同样接收端的数据也是可编程的,接收器可以侦测到溢出错误奇偶校验错误,帧错误和终止条件,每个错
误都可以设置一个错误标志。
l 溢出错误是指在旧数据被读取到之前,新数据覆盖了旧数据
l 奇偶校验错误是指接收器侦测到了接收数据校验结果失败,接收数据无效
l 帧错误是指接收到的数据没有一个有效的停止位,无法判定数据帧结束
l 终止条件是指RxDn接收到保持逻辑0状态持续长于一个数据帧的传输时间
b. UART数据帧
帧数据通常包含开始位、数据位、校验位、停止位。
- 开始位:UART空闲时,TxD数据线是高电平的(因此需要给相应引脚上拉引脚),将要发送数据时,TxD数据线会以拉低电平作为起始信号,所以“0”电平就相当于开始位。
- 数据位:数据位包含了要发送的信息,数据位的大小可以通过配置寄存器来确定,通常是8bit。
- 校验位:为了保证数据传输的准确性,有时会在数据位后面加上一个校验位,分为奇、偶校验,校验规则:数据位+校验位中为1的个数是奇数或者偶数。一般不用。
- 停止位:会给出一段持续的高电平作为停止信号,持续时间可以通过配置寄存器来设置,一般设置停止位的持续时间为1位长度。
- 波特率:每秒发送的bit(位)
- 最常用的数据帧格式为:8n1(意为:8位数据位,不使用校验位,停止位长度为一位)
UART的配置
UART引脚的配置
//TxD0:GPH2 RxD0:GPH3
volatile unsigned int* GPHCON = (volatile unsigned int*)0x56000070;
volatile unsigned int* GPHDAT = (volatile unsigned int*)0x56000074;
volatile unsigned int *GPHUP = (volatile unsigned int*)0x56000078;
/*设置输出模式*/
*GPHCON&=~((3<<4)|(3<<6));
*GPHCON&=((2<<4)|(2<<6));
/*使能内部上拉即上拉电阻——设为0*/
*GPHUP&=~((1<<2)|(1<<3));
波特率的配置
我们需要根据这个公式设置波特率,所以我们应该要知道UART CLOCK
时钟源,以及buad rate
波特率。这里的时钟源选择PCLK
,buad rate选择115200
从而设置波特率
设置串口数据帧格式
设置数据位,奇偶位,停止位什么的
设置控制寄存器
在控制寄存器中,我们最关键选择设置只有三个。时钟源[11:10]为PCLK
,发送接收模式[3:2],[1:0]为中断模式
设置FIFO
- 首先,发射器和接收器各包含64字节(不是64位,是64字节)的fifo和数据移位器。
如果是fifo,初始化uart之后,是先将数据写入FIFO,然后复制到传输移位器在传输之前。然后由传输数据pin (TxDn)将数据移出。同时,接收数据为从接收数据pin (RxDn)进行移位,然后从移位器复制到FIFO。 - 使用的是非fifo模式的话,其实也是用了FIFO中的一个字节的空间,作为先存进去的地方而已,不存在直接放进传输移位器的做法(如果是这样做的话,就是需要通过程序一位一位放进去了)。
- 接收到的数据是放到接收缓存器URXHn中,要发送数据时,是把数据放入发送缓存器UTXHn中。由于UART是通过字节方式传输数据的,因此要区分是大端模式还是小端模式,也就是说这两个寄存器在这两种模式下,读取出来的结果是不同的(有默认的情况,不修改就好了)。
状态寄存器
这个是状态寄存器,我们判断数据是否发送出去或者接受到,我们就必须使用它进行判断
缓冲寄存器,用来收发数据
我们设置这个,用来发送数据或者接受数据,
注意:
L是指尾端(endian)模式是小尾端模式
B是指尾端(endian)模式是大尾端模式
编写UART关键代码
void uart_init(){
/****************设置uart,TX,RX引脚*****************/
//TxD0:GPH2 RxD0:GPH3
volatile unsigned int* GPHCON = (volatile unsigned int*)0x56000070;
volatile unsigned int* GPHDAT = (volatile unsigned int*)0x56000074;
volatile unsigned int *GPHUP = (volatile unsigned int*)0x56000078;
/*设置输出模式*/
*GPHCON&=~((3<<4)|(3<<6));
*GPHCON&=((2<<4)|(2<<6));
/*使能内部上拉即上拉电阻——设为0*/
*GPHUP&=~((1<<2)|(1<<3));
/****************设置数据帧格式*****************/
volatile unsigned int* ULCON0 = (volatile unsigned int*)0x50000000;
*ULCON0 = 0x03;//无校验位,1位停止位、8位数据位
/****************设置控制寄存器*****************/
volatile unsigned int* UCON0= (volatile unsigned int*)0x50000004;
*UCON0 = 0x05;//PCLK时钟源,Normal模式,收发模式为interrupt中断请求
/****************设置FIFO寄存器*****************/
volatile unsigned int* FIFO= (volatile unsigned int*)0x50000008;
*FIFO = 0; //不适用FIFO寄存器,默认为0,可以不设置这一步
/****************设置调制解调器寄存器*****************/
volatile unsigned int* UMCON0= (volatile unsigned int*)0x5000000C;
*UMCON0 = 0;
/****************设置波特率*****************/
//这里选择的是PCLK时钟源 = 50MHZ,
//UBRDIV0 = (50000000/(115200x16))-1 = 26.126 ≈ 26
volatile unsigned int* UBRDIV0= (volatile unsigned int*)0x500000028;
*UBRDIV0 = 26
/****************设置状态寄存器*****************/
volatile unsigned int* UTRSTAT0 = (volatile unsigned int*)0x500000010;
/****************设置传输缓冲寄存器,发送数据*****************/
volatile unsigned char* UTXH0= (volatile unsigned int*)0x500000020;
/****************设置接收缓冲寄存器,接收数据*****************/
volatile unsigned char* URXH0= (volatile unsigned int*)0x500000024;
}
/****************发送数据*****************/
int putchar(int c){
while(!(*UTRSTAT0 & (1<<2))); //若是UTRSTAT0 不为1,则也就是为0,时则表明上次的数据还没发送完成,循环等待
*UTXH0 = c;//发送一个字符C
}
/****************接收数据*****************/
int getchar(){
while(!(*UTRSTAT0 & (1<<0))); //若是UTRSTAT0 不为1,则也就是为0,时则表明上次的数据还没发送完成,循环等待
return *URXH0;//接受一个字符C
}
/****************发送字符串*****************/
void putString(const char * s)
{
while(*s){
putchar(*s);
s++;
}
}
}
# 源码位置
>github后补E:\ARM-Code-test-file\uart-test