STM32系列 USART通信
0 前言
UART:通用异步收发传输器,是一种通用串行数据线,用于异步通信,双向通信,可以实现全双工传输和接收。
USART:通用同步/异步串行收发器,是一个全双工通用同步/异步串行收发模块。
USART收发模块分为三个部分:时钟发生器、数据发送器和接收器。
时钟发生器由同步逻辑电路(在同步从模式下由外部时钟输入驱动)和波特率发生器组成。发送时钟引脚XCK仅用于同步发送模式下。
发送器部分由一个单独的写入缓冲器(发送UDR)、一个串行移位寄存器、校验位发生器和用于处理不同帧结构的控制逻辑电路构成。使用吸入缓冲器,实现了连续发送多帧数据无延时的通信。
接收器最主要的是时钟和数据接收单元。数据接收单元用作异步数据的接收。除了接收单元,接收器还包括校验位校验器、控制逻辑、移位寄存器和两级接收缓冲器(接收UDR)。接收器支持与发送器相同的帧结构,同时支持帧错误、数据溢出和校验错误的检测。
UART和USART的区别:
从名字上看,USART在UART基础上增加了同步功能,即USART是UART的增加型,使用USART在异步通信时,与UART没什么区别,但是用在同步通信时,区别就明显了,同步通信需要时钟来触发数据传输,也就是说USART相对于UART能提供主动时钟。
1 简介
通用同步异步收发器(USART)能够灵活的与外部设备进行全双工数据交换,满足外部设备对工业标准NRZ异步串行数据格式的要求。通过小数波特率发生器提供了多种波特率。支持同步单向通信和半双工担心通信;还支持LIN(局域互连网络)、智能卡协议与IrDA(红外线数据协会)SIR ENDEC规范,以及调制解调器操作(CTS/RTS)。而且还支持多处理器通信。通过配置多个缓冲区使用DMA可实现高速数据通信。
2 主要特性
- 全双工异步通信
- NRZ标准格式(标记/空格)
- 可配置为16倍过采样或8倍过采样,因而为速度容差与时钟容差的灵活配置提供了可能
- 小数波特率发生器系统
- 通用可编程收发波特率 - 数据字长度可编程(8位或9位)
- 停止位可配置
- 支持1或2个停止位 - LIN主模式同步停止符号发送功能和LIN从模式停止符号检测功能
- 对USART进行LIN硬件配置时可发生13位停止符合和检测10/11位停止符号 - 用于同步发送的发送器时钟输出
- IrDA SIR编码解码器
- 正常模式下,支持3/16位持续时间 - 智能卡仿真功能
- 智能卡接口支持符合ISO 7816-3标准中定义的异步协议智能卡
- 智能卡工作模式下,支持0.5或1.5个停止位 - 单线半双工通信
- 使用DMA(直接存储器访问)实现可配置的多缓冲区通信
- 使用DMA在预留的SRAM缓冲区中收/发字节 - 发送器和接收器具有单独使能位
- 传输检测标志:
- 接收缓冲区已满
- 发送缓冲区为空
- 传输结束标志 - 奇偶校验控制:
- 发送奇偶校验位
- 检查接收的数据字节的奇偶性 - 四个错误检测标志:
- 溢出错误
- 噪声检测
- 帧错误
- 奇偶检验错误 - 十个具有标志位的中断源:
- CTS变化
- LIN停止符号检测
- 发送数据寄存器为空
- 发送完成
- 接收数据寄存器已满
- 接收到线路空闲
- 溢出错误
- 帧错误
- 噪声错误
- 奇偶检验错误 - 多处理器通信
- - 从静模式唤醒(通过线路空闲检测或地址标记检测)
- 两个接收器唤醒模式:地址位(MSB,第9位),线路空闲
3 功能说明
接口通过三个引脚从外部设备连接到其他设备。任何USART双向通信均需要至少两个引脚:接收数据输入引脚(RX)和发送数据输出引脚(TX)
RX:就是串行数据输入引脚。过采样技术可区分有效输入数据和噪声,从而用于恢复数据
TX:如果关闭发送器,该输出引脚模式由其I/O端口配置决定。如果使能了发送器但没有待发送的数据,则TX引脚处于高电平。在单线和智能卡模式下,该I/O用于发送和接收数据(USART电平下,随后在SW_RX上接收数据)
正常USART模式下,通过这些引脚以帧的形式发送和接收串行数据:
- 发送或接收前保持空闲线路
- 起始位
- 数据(字长8位或9位),最低有效位在前
- 用于指示帧传输已完成的0.5个、1个、1.5个、2个停止位
- 该接口使用小数波特率发生器 - 带12位尾数和4位小数
- 状态寄存器(USART_SR)
- 数据寄存器(USART_DR)
- 波特率寄存器(USART_BRR) - 12位尾数和4位小数
- 智能卡模式下的保存时间寄存器(USART_GTPR)
在同步模式下连接时需要一下引脚:
SCLK:发送器时钟输出,用于输出发送器数据时钟,一遍按照SPI主模式进行同步发送(起始位和结束位上无时钟脉冲,可通过软件向最后一位数据位发送时钟脉冲)。RX上可同步接收并行数据。可用于控制带移位寄存器的外设(如LCD驱动器)。时钟相位和极性可通过软件编程。在智能卡模式下,SCLK可向智能卡提供时钟
在硬件流控制模式下需要以下引脚:
nCTS:“清除以发送”用于在当前传输结束时阻止数据发送(高电平时)
nRTS:“请求以发送”用于指示USART已准备好接收数据(低电平时)
4 使用DMA进行通信
USART能够使用DMA进行连续通信,接收缓冲区和发送缓冲区的DMA请求时独立的
- 使用DMA进行发送
将USART_CR3寄存器中的DMAT位置1可以使能DMA模式进行发送。当TXE位置1时,可将数据从SRAM区加载到USART_DR寄存器。要映射一个DMA通道以进行USART发送,按以下步骤操作(x表示通道编号):
- 在DMA控制寄存器中写入USART_DR寄存器地址,将其配置为传输的目标地址。每次发生TXE事件后,数据都会从存储器移动到此地址。
- 在DMA控制寄存器中写入存储器地址,将其配置为传输的源地址。每次发生TXE后,数据都会从这个存储区域加载到USART_DR寄存器中。
- 在DMA控制寄存器中配置要传输的总字节数。
- 在DMA寄存器中配置通道的优先级
- 根据应用的需求,在完成一半或全部传输后产生DMA中断
- 向SR寄存器中的TC位写入0,将其清零
- 在DMA寄存器中激活该通道
当达到在DMA控制器中设置的数据传输量时,DMA控制器会在DMA通道中的中断向量生上产生一个中断。
在发送模式下,DMA对所有要发送的数据执行了写操作(DMA_ISR寄存器中的TCIF标志置1)后,可以对TC标志进行监视,以确保USART通信已完成。在禁止USART或进入停止模式前必须执行此步骤,以避免损坏最后一次发送。软件必须等待直到TC=1。TC标志在所有数据发送期间都必须保持清零状态,然后在最后一帧发送结束后由硬件置1。
使用DMA进行发送
-
使用DMA进行接收
将USART_CR3寄存器中的DMAR位置1可以使能DMA模式进行接收。接收数据字节时,数据会从USART_DR寄存器加载到SRAM区域中。要映射一个DMA通道以进行USART接收,按以下步骤操作: -
在DMA控制器中写入USART_DR寄存器地址,将其配置为传输的源地址。每次发生RXNE事件后,数据都会以此地址移动到存储器
-
在DMA控制寄存器中写入存储器地址,将其配置为传输的目标地址。每次发生RXNE事件后,数据都会从USART_DR寄存器加载到此存储区
-
在DMA控制寄存器中配置要传输的总字节数
-
在DMA控制寄存器中配置通道优先级
-
根据应用的需求,在完成一半或全部传输后产生中断
-
在DMA控制寄存器中激活该通道
当达到在DMA控制器中设置的数据传输量时,DMA控制器会在DMA通道的中断向量上产生一个中断。在中断子程序中,USART_CR3寄存器中的DMAR位应有软件清零。
如果DMA用于接收,则不要使能RXNEIE位。 -
使用DMA进行接收
在多缓冲区通信中,如果发生任何错误,都会在当前字节后放置错误标志。如果中断使能置1,则会产生中断。在单字节接收过程中,与RXNE一同置位的帧错误、上溢错误和噪声标志具有单独的错误标志中断使能位(USART_CR3寄存器中的EIE位);如果该位置1,则会因其中任何一个错误而在当前字节后产生中断。
5 USART中断
中断事件 | 事件标志 | 使能控制位 |
---|---|---|
发送数据寄存器为空 | TXE | TXEIE |
CTS标志 | CTS | CTSIE |
发送完成 | TC | TCIE |
准备好读取接收到的数据 | RXNE | RXNEIE |
检测到上溢错误 | ORE | RXNEIE |
检测到空闲线路 | IDLE | IDLEIE |
奇偶校验错误 | PE | PEIE |
断路标志 | LBD | LBDIE |
多缓冲区通信中的噪声标志、上溢错误和帧错误 | NF或ORE或FE | EIE |
USART中断事件被连接到相同的中断向量 |
- 发送期间:发送完成、清楚以发送或发送数据寄存器为空中断
- 接收期间:空闲线路检测、上溢错误、接收数据寄存器不为空、奇偶校验错误、LIN断路检测、噪声标志(仅限多缓冲区通信)和帧错误(仅限多缓冲区通信)
如果相应的使能控制位置1,则这些事件会发生中断
6 代码实现
USART初始化
void USART_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //GPIO时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //USART时钟使能
GPIO_PinAFConfig(GPIO_DEBUG, GPIO_PinSource9, GPIO_AF_USART1); //GPIO复用
GPIO_PinAFConfig(GPIO_DEBUG, GPIO_PinSource10, GPIO_AF_USART1);//GPIO复用
GPIO_InitStructure.GPIO_Pin = GPIO_PIN_TX | GPIO_PIN_RX;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //设置为复用推免输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIO_DEBUG, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 115200; //设置波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1; //1个停止位
USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验位
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//收发模式
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
USART_ITConfig(USART1, USART_IT_IDLE, DISABLE);
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //使能USART接收中断
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); //使能检测到空闲线路中断
USART_Cmd(USART1, ENABLE); //使能USART
}
USART发送数据
调用USART_SendData函数进行数据发送
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
USARTx:选择USART或者UART设备
Data:传输的数据
USART_SendData()只能一个字节一个字节的发送
USART接收数据
可以通过轮询,中断和DMA的发送接收数据
void USART1_IRQHandler(void)
{
uint32_t temp;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
{
RecvBuf[recvcnt] = USART_ReceiveData(USART1); //接收数据,放入接收buff
recvcnt++;
USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清除接收中断
}
if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)
{
//清除空闲中断
temp = USART1->SR;
temp = USART1->DR;
idle_flag = 1;
}
}
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
USARTx:选择USART或者UART设备
STM32的IDLE的中断在串口无数据接收的情况下,是不会一直产生的,产生的条件是,当清除IDLE标志位后,必须有接收到第一个数据后,才开始触发,一断接收的数据断流,没有接收到数据,即产生IDLE中断。IDLE位不会再次被置高直到RXNE位被置起(即又检测到一次空闲总线)。RXNE接收中断可以不用开启,减少进中断的次数
串口总线空闲检测这一特性,尤其是对收到的数据是不定长时更有效果
如果数据量比较大的时候,我们可以考虑使用DMA进行数据的传输