一、UART原理
UART(Universal Asynchronous Receiver/Transmitter) 通用异步收发器,是一种串行、异步、全双工的通信协议。
工作原理是将传输数据的每个二进制位一位接一位地传输。在UART通信协议中信号线上的状态为高电平时代表‘1’,信号线上的状态为低电平时代表‘0’。
需要通讯的两个uart设备遵循相同的协议(指定相同的传输速率,空闲位、起始位、校验位、结束位)。数据传送速率用波特率来表示,即每秒钟传送的二进制位数,单位bps(bit/s),常见的波特率9600bps、115200bps等等。
数据格式如下图:
空闲位: UART协议规定,当总线处于空闲状态时信号线的状态为‘1’即高电平,表示当前线路上没有数据传输。
起始位: 每开始一次通信时发送方先发出一个逻辑”0”的信号(低电平有效),表示传输字符的开始。
数据位: 数据位可以是5、6、7、8,9位等,构成一个字符(一般都是8位)。先发送最低位,后发送最高位,使用低电平表示‘0’ / 高电平表示‘1’ 完成数据位的传输。
奇偶校验位: 数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性。 串口校验分为: 无校验(no parity)奇校验(odd parity)偶校验(even parity)
停止位: 一个字符数据的结束标志。可以是1位、1.5位、2位的高电平。
二、UART相关寄存器信息
UART的配置通常使用以下寄存器:
BAUD 波特率寄存器,STAT 状态寄存器, CTRL 控制寄存器,DATA 数据寄存器
1、BAUD
主要配置内容[SBR]波特率分频,其余位使用默认值,过采样比率16,停止位1位
公式:波特率 = [BAUD CLOCK] / [(OSR+1)*SBR] (OSR+1)过采样比率 默认值16
SBR = BAUD CLOCK / (16*波特率)
2、STAT
要清除发送标志位TDRE,将数据写入到DATA寄存器;
要清除接收标志位RDRF,从DATA寄存器读取数据
3、CTRL
4、DATA
接收数据区为[9:0],有效数据设置为8位,实际使用了[7:0]。
实际上发送和接收,是通过发送移位寄存器和接收移位寄存器进行处理的。
但我们只通过收发UART数据寄存器来获取数据, 因为UART数据寄存器同发送移位寄存器/接收移位寄存器之间,由MCU自动完成。
三、UART的配置步骤
【初始化UART】
1、对UART的TX / RX引脚的功能复用配置;
2、时钟树配置,选择UART的时钟源;
3、作为寄存器的写入前提条件,需要关闭发送和接收使能;
4、配置UART的波特率信息,1停止位, 8个数据位, 无奇偶校验;
5、开启UART的发送和接收使能;
【发送】
循环读取STAT[TDRE]位的数据,判断当前发送缓存区寄存器是否为空;
增设循环超时次数,防止程序死循环;
【接收】
循环读取STAT[RDRF]位的数据,判断当前接收缓存区寄存器是否为空;
增设循环超时次数,防止程序死循环;
1、初始化UART
(1)对UART的TX / RX引脚的功能复用配置
PORTA->PCR[3] &=PORT_PCR_MUX_MASK; //清PTA3的引脚复用
PORTA->PCR[3] |=PORT_PCR_MUX(6); //设置PTA3的引脚复用为串口发送
(2)时钟树配置,选择UART的时钟源
//选择时钟源之前需先关闭时钟门
PCC->PCCn[PCC_LPUART0_INDEX] &= ~PCC_PCCn_CGC_MASK;
PCC->PCCn[PCC_LPUART0_INDEX] &= ~PCC_PCCn_PCS_MASK;
//选择时钟源SOSCDIV2_CLK并开启时钟门 //SPLLDIV2
PCC->PCCn[PCC_LPUART0_INDEX] |= PCC_PCCn_PCS(1); //16MHz
PCC->PCCn[PCC_LPUART0_INDEX] |= PCC_PCCn_CGC_MASK;
(3)作为寄存器的写入前提条件,需要关闭发送和接收使能
//关闭发送和接收使能
LPUART_PTR[uartNo]->CTRL &= ~LPUART_CTRL_TE_MASK;
LPUART_PTR[uartNo]->CTRL &= ~LPUART_CTRL_RE_MASK;
(4)配置BAUD寄存器
//配置串口的波特率
LPUART_PTR[uartNo]->BAUD &= ~LPUART_BAUD_SBR_MASK;
sbr = (16000000)/(baud_rate*16); //16为OSR的默认值
LPUART_PTR[uartNo]->BAUD |= LPUART_BAUD_SBR(sbr);
//若配置波特率为9600,1停止位
// SBR=104 (0x68): 波特率模数除数 = 16M/9600/16 = 104
// OSR=15: 采样率 = 15+1=16
// SBNS=0: 1个停止位
// BOTHEDGE=0: 接收端使用波特率时钟上升沿采样输入数据
// M10=0: 接收和发送使用7位到9位的数据字符
// RESYNCDIS=0: 支持在接收数据字期间重新同步
// LBKDIE, RXEDGIE=0: 禁用LIN中断,RX收入边缘中断
(5)开启UART的发送和接收使能
//打开发送和接收使能
LPUART_PTR[uartNo]->CTRL |= LPUART_CTRL_TE_MASK;
LPUART_PTR[uartNo]->CTRL |= LPUART_CTRL_RE_MASK;
// RE=1,TE=1: 使能接收及发送
// PE=0: 无奇偶校验
// M7,M,R8T9,R9T8=0: 8个数据位
// DOZEEN=0: 睡眠模式下LPUART正常启用
// ORIE,NEIE,FEIE,PEIE,TIE,TCIE,ILIE,MA1IE,MA2IE,RIE=0: 中断未使能
// TXINV=0: 传输数据不是反向的
// IDLCFG=0: 1个空闲字符
// ILT=0: 空闲字符位计数在开始位之后开始
2、发送
uint8_t uart_send1(uint8_t uartNo, uint8_t ch)
{
int count = 0;
//判断传入串口号参数是否有误,有误直接退出
if(!uart_is_uartNo(uartNo))
{
return 0;
}
//等待发送缓冲区为空
while((LPUART_PTR[uartNo]->STAT &LPUART_STAT_TDRE_MASK)
!= LPUART_STAT_TDRE_MASK && count++<0xFFFF);
//判断是否为超时
if(count>=0xFFFF)return 0;
//至此,可成功发送数据
LPUART_PTR[uartNo]->DATA = ch;
return 1;
}
3、接收
uint8_t uart_re1(uint8_t uartNo, uint8_t *fp)
{
int count=0;
//判断传入串口号参数是否有误,有误直接退出
if(!uart_is_uartNo(uartNo))
{
*fp=0;
return 0;
}
//等待接收数据
while((LPUART_PTR[uartNo]->STAT &LPUART_STAT_RDRF_MASK)
!= LPUART_STAT_RDRF_MASK && count++<0xFFFF);
if(count>=0xFFFF)
{
*fp = 0;
return 0;
}
*fp=1;
return (LPUART_PTR[uartNo]->DATA);
}
参考来源:苏州大学嵌入式学习社区 (suda.edu.cn)
苏州大学嵌入式学习社区/教学与培训/教学资料/汽车电子S32K/SD-S32K-CD(V0.9.1)-20181006.rar