UART控制器原理 串口通信协议
什么是串口通讯
串口通讯是一种通过串行(一位接着一位地)传输数据的通信方式。在嵌入式系统中,串口通讯通常是通过UART控制器实现的。
串口通讯是一种在设备之间传输数据的常见方式,特别是在嵌入式系统、传感器、单片机和一些外围设备之间。
硬件连接
串口硬件连接非常简单,只需要Tx、Rx和GND 3条线,接线时两个设备的Tx与Rx要交叉连接,GND直接可以直接连接。

波特率
串口的波特率表示在1秒钟内,两个串口设备之间能传输多少个码元,在串口通信中,波特率等于比特率。
比特率=波特率*单个调制状态(码元)对应的二进制位数
串口通讯中常用的波特率有2400、4800、9600、115200。

波特率的计算

数据帧格式
•一帧完整的串口数据帧由开始位、传输数据、校验位和停止位组成。
•开始位是以低电平开始,停止位总是以高电平结束。

数据位
STM32F407串口控制器可发送8位或9位的数据,一般在串口通讯时常用8位数据位模式进行数据收发,9位数据位通常是为了使用校验位。

奇偶校验
•常用的串口的校验位分为奇校验和偶校验两种:
•奇校验是保证一帧数据中高电平的个数为奇数个
•偶校验是保证一帧数据中高电平的个数为偶数个

奇偶校验
如果在传输中启用了校验位,那么数据位将被占用1位用作校验位。
例如将控制器配置为8位数据位,那么实际能传输的有效数据位为7位,有一位被用做了校验位。

停止位
帧格式中停止位除了1位停止位,还可以配置为0.5位1.5位或2位停止位。

数据收发流程与状态
串口收发流程
•发送流程
•将串口数据写入内存
•程序将内存中的数据填入串口控制器的TDR寄存器
•TDR寄存器中的数据自动传入发送移位寄存器,由移位寄存器将数据从TX引脚发生出去
•接收流程
•当RX引脚上有数据时,会依次流入接收移位寄存器
•接收移位寄存器接收完成后将数据写入RDR寄存器
•程序读取RDR寄存器的数据写入内存中使用
常用状态
•串口控制器常用状态有:
•发送数据寄存器为空(TXE)
•发送移位寄存器为空(TC)
•接收检测到空闲线路(IDLE)
•接收数据寄存器不为空(RXNE)
•接收溢出错误(ORE)
•奇偶校验错误(PE)

串口中断
•串口状态与中断对应关系
| 中断事件 | 事件标志 | 中断使能位 |
|---|---|---|
| 发送数据寄存器为空 | TXE | TXEIE |
| 发送完成 | TC | TCIE |
| 准备好读取接收到的数据 | RXNE | RXNEIE |
| 奇偶校验错误 | PE | PEIE |
| 检测到空闲线路 | IDLE | IDLEIE |
DMA自搬运
通过串口DMA可以实现在不需要CPU干涉情况下,自动将串口接收到的数据写入内存指定位置,或者自动将内存中指定位置的数据通过串口发送出去。
•将串口控制器中DMA发送功能开启后,可以使能DMA模式进行发送。当TXE标志置1时,可将数据从内存中自动加载到发送寄存器。
•将串口控制器中DMA接收功能开启后,可以使能DMA模式进行接收。当RXNE标志置1时,可将接收寄存器中的数据自动加载到内存。
硬件流控
•串口硬件流控是一种通过物理信号线控制数据传输的机制,用于协调两个设备间的数据流动,以防止数据丢失或溢出。
•硬流控主要涉及两个信号线:RTS和CTS。
•RTS信号是一个输出信号,用于指示本设备是否准备好接收数据。
•CTS信号是一个输入信号,用于判断是否可以向对方设备发送数据。

RTS流控制
如果使能RTS流控制(RTSE=1),只要USART接收器准备好接收新数据,便会将nRTS变为有效(连接到低电平)。
当接收寄存器已满时,会将nRTS变为无效,表明发送过程会在当前帧结束后停止。

CTS流控制
如果使能CTS流控制(CTSE=1),则发送器会在发送下一帧前检查nCTS。
如果nCTS有效(连接到低电平),则会发送下一数据;否则不会进行发送。
如果在发送过程中nCTS变为无效,则当前发送完成之后,发送器停止。

UART控制器HAL库接口 UART寄存器映射
UART控制器基址
| 控制器 | 基址 | 所属总线 |
|---|---|---|
| USART1 | 0x40011000 | APB2 |
| USART2 | 0x40004400 | APB1 |
| USART3 | 0x40004800 | APB1 |
| UART4 | 0x40004C00 | APB1 |
| UART5 | 0x40005000 | APB1 |
| USART6 | 0x40011400 | APB2 |
| UART7 | 0x40007800 | APB1 |
| UART8 | 0x40007C00 | APB1 |
寄存器映射
| 寄存器名称 | 寄存器描述 | 偏移地址 |
|---|---|---|
| USART_SR | 状态寄存器 | 0x00 |
| USART_DR | 数据寄存器 | 0x04 |
| USART_BRR | 波特率寄存器 | 0x08 |
| USART_CR1 | 控制寄存器1 | 0x0C |
| USART_CR2 | 控制寄存器2 | 0x10 |
| USART_CR3 | 控制寄存器3 | 0x14 |
HAL库接口
UART串口初始化配置结构体
cpp
typedef struct {
uint32_t BaudRate; /* 波特率 */
uint32_t WordLength; /* 数据宽度 */
uint32_t StopBits; /* 停止位宽度 */
uint32_t Parity; /* 校验位模式 */
uint32_t Mode; /* 是否启用接收或发送模式 */
uint32_t HwFlowCtl; /* 是否启用硬件流控 */
} UART_InitTypeDef;
HAL_UART_Init函数
| 项目 | 内容 |
|---|---|
| 函数功能 | 初始化 UART 控制器 |
| 函数原型 | HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart) |
| 函数参数 | huart:UART 句柄 |
| 函数返回值 | 是否初始化成功(HAL_StatusTypeDef 类型) |
HAL_UART_Transmit函数
| 项目 | 内容 |
|---|---|
| 函数功能 | 使用轮询方式发送数据 |
| 函数原型 | HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size, uint32_t Timeout) |
| 函数参数 | • huart :UART 句柄 • pData :要发送数据的首地址 • Size :要发送的字节数 • Timeout :超时时间 |
| 函数返回值 | 数据发送是否成功(HAL_StatusTypeDef 枚举值) |
HAL_UART_Receive函数
| 项目 | 内容 |
|---|---|
| 函数功能 | 使用轮询方式接收数据 |
| 函数原型 | HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout) |
| 函数参数 | • huart :UART 句柄 • pData :要存放数据的首地址 • Size :要接收的字节数 • Timeout :超时时间 |
| 函数返回值 | 数据接收是否成功(HAL_StatusTypeDef 枚举值) |
HAL_UART_Transmit_IT函数
| 项目 | 内容 |
|---|---|
| 函数功能 | 使用中断方式发送数据 |
| 函数原型 | HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size) |
| 函数参数 | • huart :UART 句柄 • pData :要发送数据的首地址 • Size :要发送的字节数 |
| 函数返回值 | 数据发送是否成功(HAL_StatusTypeDef 枚举值) |
HAL_UART_Receive_IT函数
| 项目 | 内容 |
|---|---|
| 函数功能 | 使用中断方式接收数据 |
| 函数原型 | HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size) |
| 函数参数 | • huart :UART 句柄 • pData :要存放数据的首地址 • Size :要接收的字节数 |
| 函数返回值 | 数据接收是否成功(HAL_StatusTypeDef 枚举值) |
HAL_UART_Transmit_DMA函数
| 项目 | 内容 |
|---|---|
| 函数功能 | 使用 DMA 方式发送数据 |
| 函数原型 | HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size) |
| 函数参数 | • huart :UART 句柄 • pData :要发送数据的首地址 • Size :要发送的字节数 |
| 函数返回值 | 数据发送是否成功(HAL_StatusTypeDef 枚举值) |
HAL_UART_Receive_DMA函数
| 项目 | 内容 |
|---|---|
| 函数功能 | 使用 DMA 方式接收数据 |
| 函数原型 | HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size) |
| 函数参数 | • huart :UART 句柄 • pData :要存放数据的首地址 • Size :要接收的字节数 |
| 函数返回值 | 数据接收是否成功(HAL_StatusTypeDef 枚举值) |
UART控制器应用 USB串口通讯
TTL电平标准
在TTL标准规定在0~0.4V这个范围时为逻辑0,在2.4V~5V这个范围时为逻辑1。

TTL转USB实验
由于STM32单片机串口管脚发出的都是TTL电平,想要接入PC还需要在STM32单片机串口电路上增加一个TTL电平转USB信号的转换芯片。

RS232串口
串口电平标准
•两个设备间的串口通讯根据传输距离、现场环境等因素需要选择不同的物理电平标准。
•常用的标准有TTL标准、RS232标准、RS485标准。

TTL电平转RS232电平
由于STM32单片机串口管脚发出的都是TTL电平,想要使用RS232还需要在STM32单片机串口电路上增加一个电平转换芯片

当1个大于2.4V的TTL电平经过MAX232后被转化为-3~-15V的RS232电平。
当1个小于0.8V的TTL电平经过MAX232后被转化为3V~15V的RS232电平。

RS232电平范围
RS232最大的好处就是抗干扰能力有了很大的提升。

DB9接口
RS232通讯线缆连接时常用DB9接头,来将两个设备间的线缆进行连接。

土壤温湿度采集
TTL电平转RS485电平
同样由于STM32单片机串口管脚发出的都是TTL电平,所以使用RS485通讯时同样也需要一个将TTL电平转换为RS485电平的芯片。

RS485电平标准
在RS485中是用A线电压与B线电压的差值来确定逻辑1和逻辑0的。
•用A线电压减去B线电压,如果在+2~+6v的范围内则都属于逻辑1
•用A线电压减去B线电压,如果在-2~-6v的范围内则都属于逻辑0
