1、USART 简介
通用同步异步收发器(Universal Synchronous Asynchronous Receiver and Transmitter)是一个串行通信设备,可以灵活地与外部设备进行全双工数据交换。
有别于 USART 还有一个UART(Universal Asynchronous Receiver and Transmitter),它是在 USART 基础上裁剪掉了同步通信功能,只有异步通信。简单区分同步和异步就是看通信时需不需要对外提供时钟输出,我们平时用的串口通信基本都是 UART。
2、USART 功能框图
1. ①功能引脚
TX:发送数据输出引脚。
RX:接收数据输入引脚。
SW_RX:数据接收引脚,只用于单线和智能卡模式,属于内部引脚,没有具体外部引脚。
nRTS:请求以发送(Request To Send),n 表示低电平有效。如果使能 RTS 流控制,当USART 接收器准备好接收新数据时就会将 nRTS 变成低电平;当接收寄存器已满时,nRTS 将被设置为高电平。该引脚只适用于硬件流控制。
nCTS:清除以发送(Clear To Send),n 表示低电平有效。如果使能 CTS 流控制,发送器在发送下一帧数据之前会检测 nCTS 引脚,如果为低电平,表示可以发送数据,如果为高电平则在发送完当前数据帧之后停止发送。该引脚只适用于硬件流控制。
SCLK:发送器时钟输出引脚。这个引脚仅适用于同步模式。
2. ②数据寄存器
USART 数据寄存器(USART_DR)只有低 9 位有效,并且第 9 位数据是否有效要取决于USART 控制寄存器 1(USART_CR1)的 M 位设置,当 M 位为 0 时表示 8 位数据字长,当 M位为 1 表示 9 位数据字长,我们一般使用 8 位数据字长。
USART_DR 包含了已发送的数据或者接收到的数据。USART_DR 实际是包含了两个寄存器,一个专门用于发送的可写 TDR,一个专门用于接收的可读 RDR。
当进行发送操作时,往 USART_DR 写入数据会自动存储在 TDR 内;当进行读取操作时,向 USART_DR读取数据会自动提取 RDR 数据。
3. ③控制器
4. ④小数波特率生成
其中,fPLCK 为 USART 时钟, USARTDIV 是一个存放在波特率寄存器(USART_BRR)的 一个 无符 号定 点数。 其中 DIV_Mantissa[11:0] 位 定义 USARTDIV 的 整数 部分 ,DIV_Fraction[3:0]位定义 USARTDIV 的小数部分。
5. 校验控制
使能了奇偶校验控制后,每个字符帧的格式将变成:起始位+数据帧+校验位+停止位
6. 中断控制
3、USART 初始化结构体详解
USART 初始化结构体
1 typedef struct {
2 uint32_t USART_BaudRate; // 波特率
3 uint16_t USART_WordLength; // 字长
4 uint16_t USART_StopBits; // 停止位
5 uint16_t USART_Parity; // 校验位
6 uint16_t USART_Mode; // USART 模式
7 uint16_t USART_HardwareFlowControl; // 硬件流控制
8 } USART_InitTypeDef;
-
USART_BaudRate:波特率设置。一般设置为 2400、9600、19200、115200。标准库函数会根据设定值计算得到 USARTDIV 值,从而设置 USART_BRR 寄存器值。
-
USART_WordLength:数据帧字长,可选 8 位或 9 位。它设定 USART_CR1 寄存器的 M 位的值。如果没有使能奇偶校验控制,一般使用 8 数据位;如果使能了奇偶校验则一般设置为 9 数据位。
-
USART_StopBits:停止位设置,可选 0.5 个、1 个、1.5 个和 2 个停止位,它设定USART_CR2 寄存器的 STOP[1:0]位的值,一般我们选择 1 个停止位。
-
USART_Parity : 奇 偶 校 验 控 制 选 择 , 可 选 USART_Parity_No( 无校验 ) 、USART_Parity_Even( 偶校验 ) 以 及 USART_Parity_Odd( 奇 校 验 ) , 它 设 定USART_CR1 寄存器的 PCE 位和 PS 位的值。
-
USART_Mode:USART 模式选择,有 USART_Mode_Rx 和 USART_Mode_Tx,
允许使用逻辑或运算选择两个,它设定 USART_CR1 寄存器的 RE 位和 TE 位。 -
USART_HardwareFlowControl:硬件流控制选择,只有在硬件流控制模式才有效,可选有⑴使能 RTS、⑵使能 CTS、⑶同时使能 RTS 和 CTS、⑷不使能硬件流。
1. 编程要点
- 使能 RX 和 TX 引脚 GPIO 时钟和 USART 时钟;
- 初始化 GPIO,并将 GPIO 复用到 USART 上;
- 配置 USART 参数;
- 配置中断控制器(NVIC)并使能 USART 接收中断;
- 使能 USART;
- 在 USART 接收中断服务函数实现数据接收和发送。
GPIO 和 USART 宏定义
1 /**
2 * 串口宏定义,不同的串口挂载的总线和 IO 不一样,移植时需要修改这几个宏
3 */
4
5 // 串口 1-USART1
6 #define DEBUG_USARTx USART1
7 #define DEBUG_USART_CLK RCC_APB2Periph_USART1
8 #define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
9 #define DEBUG_USART_BAUDRATE 115200
10
11 // USART GPIO 引脚宏定义
12 #define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
13 #define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
14
15 #define DEBUG_USART_TX_GPIO_PORT GPIOA
16 #define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_9
17 #define DEBUG_USART_RX_GPIO_PORT GPIOA
18 #define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10
19
20 #define DEBUG_USART_IRQ USART1_IRQn
21 #define DEBUG_USART_IRQHandler USART1_IRQHandler
嵌套向量中断控制器 NVIC 配置
1 static void NVIC_Configuration(void)
2 {
3 NVIC_InitTypeDef NVIC_InitStructure;
4
5 /* 嵌套向量中断控制器组选择 */
6 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
7
8 /* 配置 USART 为中断源 */
9 NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
10 /* 抢断优先级为 1 */
11 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
12 /* 子优先级为 1 */
13 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
14 /* 使能中断 */
15 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
16 /* 初始化配置 NVIC */
17 NVIC_Init(&NVIC_InitStructure);
18 }
19
USART 初始化配置
1 void USART_Config(void)
2 {
3 GPIO_InitTypeDef GPIO_InitStructure;
4 USART_InitTypeDef USART_InitStructure;
5
6 // 打开串口 GPIO 的时钟
7 DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
8
9 // 打开串口外设的时钟
10 DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);
11
12 // 将 USART Tx 的 GPIO 配置为推挽复用模式
13 GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
14 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
15 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
16 GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
17
18 // 将 USART Rx 的 GPIO 配置为浮空输入模式
19 GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
20 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
21 GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
22
23 // 配置串口的工作参数
24 // 配置波特率
25 USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
26 // 配置 针数据字长
27 USART_InitStructure.USART_WordLength = USART_WordLength_8b;
28 // 配置停止位
29 USART_InitStructure.USART_StopBits = USART_StopBits_1;
30 // 配置校验位
31 USART_InitStructure.USART_Parity = USART_Parity_No ;
32 // 配置硬件流控制
33 USART_InitStructure.USART_HardwareFlowControl =
34 USART_HardwareFlowControl_None;
35 // 配置工作模式,收发一起
36 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
37 // 完成串口的初始化配置
38 USART_Init(DEBUG_USARTx, &USART_InitStructure);
39
40 // 串口中断优先级配置
41 NVIC_Configuration();
42
43 // 使能串口接收中断
44 USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);
45
46 // 使能串口
47 USART_Cmd(DEBUG_USARTx, ENABLE);
48 }
字符发送
1 /***************** 发送一个字符 **********************/
2 void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
3 {
4 /* 发送一个字节数据到 USART */
5 USART_SendData(pUSARTx,ch);
6
7 /* 等待发送数据寄存器为空 */
8 while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
9 }
10
11 /***************** 发送字符串 **********************/
12 void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
13 {
14 while(*str != '\0')
15 {
16 Usart_SendByte( pUSARTx, *str);
17 str++;
18 }
19
20 /* 等待发送完成 */
21 while (USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET) {
22 }
23 }
USART 中断服务函数
1 void DEBUG_USART_IRQHandler(void)
2 {
3 uint8_t ucTemp;
4 if (USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET) {
5 ucTemp = USART_ReceiveData( DEBUG_USARTx );
6 USART_SendData(USARTx,ucTemp);
7 }
8 }
主函数
1 int main(void)
2 {
3 /*初始化 USART 配置模式为 115200 8-N-1,中断接收*/
4 USART_Config();
5
6 Usart_SendString( DEBUG_USARTx,"这是一个串口中断接收回显demo\n");