USART--串口
1.串口用途
硬件中数据传递的一种方式,而且是一种常用方式。后续的开发中就那个,wifi,蓝牙,zigbee,都可以按照串口方式进行数据传递和设备控制。
数据按照【串行数据传递格式】。
2.串行和并行
并行:类似于高速公路,可以同时双向形式多车辆。
串行:类似于一个管道,只允许一个车辆的通过。
3.单工,半双工和全双工
串行情况下,数据传递的工作模式
- 单工:设备分发送端和接收端,有且只允许从发送端到接收端进行数据传递
- 半双工:每台设备既是发送端又是接收端,但是在通信的过程中,设备在同一个周期内,尽可以充当一个角色。例如:同一时间内,A可以发送到B但是B不允许发送给A
- 全双工:同一时间内可以允许A->B和B->A
4.同步和异步
同步:类似于同传技术,操作同传,视觉同传
数据同步传递,因为不可逾越的数据传输延迟问题,存在一定的数据丢失和期望数据同步滞后性。
异步:类似于学舞蹈,老师完成一个动作之后,学员进行模仿。
A发送完 B进行解析,可以满足数据安全性和完整性。
5.USART技术分析
5.1USART主要特征
5.2USART框图重点分析
1、发送器控制是通过寄存器CR1控制,涉及到的寄存位有TE,PS,SBK
2、接收器控制是通过寄存器CR1控制,涉及到的寄存位有RE,PCE
3、数据寄存器USARTx_DR是根据MCU读操作和写操作行为区分数据走向。例如
- USARTx_DR = 10; MCU 写操作,数据会存储到 TDR 寄存器中,USART 外设自行控制,数据转移到【发送移位寄存器】,通过发送器进行数据发送
- u8 data = USARTx_DR; MCU 读操作,USART 外设会将存在 RDR 寄存器中的数据,提供MCU 使用。数据是在 MCU 执行读操作之前,已经通过 RX 引脚读取到 DR 寄存器内部,通过接收器控制完成。
USART 中断控制对应寄存器为 CR1,涉及到中断标志控制为有 TXEIE TCIE RXNEIEIDLEIE。IE ==> Interrupt Enable
5.3NRZ数据格式
5.4USART波特率配置和分析
USART波特率是对应当前数据的发送速度,波特率越高对应发送速度越高,反之速度降低,波特率越高,传递距离越短。
波特率是指每秒传递数据的【位数】,非字节数。字节数需要根据当前发送数据帧的组成进行计算例如 发送数据帧对应 8N1(8 个数据位,没有校验位,1 个停止位,包括 1 个起始位) 模式,10 个二进制位发送一个字节数据。波特率为 9600,每秒传递字节数为 960 字节。实际开发中,MCU处理数据速度,单位数据容量和传递时间要求,每秒 960 字节数据足够开发使用。
5.5USART 开发相关寄存器分析
5.5.1USART_CR1 寄存器配置
当前寄存器需要配置的内容
- 位13 【UE : 1】 开启USART
- 位12 【M : 0】 1 一个起始位,8 个数据位,N个停止位
- PCE 和 PS 不配置,不开启校验
- 位 3 【TE : 1】开启 USART 发送使能
- 位 2 【RE : 1】开始 USART 接收使能
5.5.2USART_CR2寄存器配置
根据文档分析,默认情况下,当前USART数据发送停止位就是【1位】,简单来说就是不需要进行配置,但是为了保证数据帧配置的完整性,以及对应【8N1】数据规则要求。必须进行明确的操作
所以要配置位13:12【STOP:00】,明确为一个停止位
5.5.3USATR_BRR 波特率控制寄存器
根据波特率计算方式,将波特率寄存器数据进行计算和提供。
5.5.4RCC_APB2ENR开启USART1时钟使能
5.5USART1对应GPIO配置
根据原理图分析
-
USART1 片上外设对应的 MCU 引脚接收端 RX 位 PA10
-
PA10 作为 MCU 读取 USART 数据引脚,因为片上外设 USART 具备很强驱动能力,可以提供稳定明确的高低电平。不需要 MCU 提供基础的参考电平
-
PA10 ==> RX ==> 【浮空输入模式 Floating Input】
-
-
USART1 片上外设对应的 MCU 引脚发送端 TX 位 PA9
-
PA9 需要满足提供高电平和低电平信号输出的能力,同时当前输出高电平和低电平是由片上外设 USART 具体,MCU 对应的引脚仅提供高电平和低电平信号输出能力。MCU不直接参与高低电平控制。
-
-
PA9 ==> TX ==> 【复用推挽输出模式 Alternate Function Push - Pull Output】
-
选择复用或者通用取决于当前信号对外数据的控制是由 MCU 决定,还是由片上外设决定
-
片上外设决定【复用模式】
-
MCU 决定【通用模式】
-
6.USART配置代码实现
#include "usart1.h"
void USART1_Init(u32 brr)
{
// 1. 配置 USART1 对应引脚 GPIO 工作模式
// 1.1 开启 GPIOA 时钟
RCC->APB2ENR |= GPIOA_RCC_APB2_CLOCK_ENABLE;
// 1.2 GPIO 引脚功能配置
// PA9 ==> TX 【复用推挽输出模式】
GPIOA->CRH &= ~(0x0F << 4);
GPIOA->CRH |= (Alternate_Function_Push_Pull_Output_Mode << 4);
// PA10 ==> RX 【浮空输入模式】
GPIOA->CRH &= ~(0x0F << 8);
GPIOA->CRH |= (Floating_Input_Mode << 8);
// 2. 配置 USART1 串口相关功能
// 2.1 USART1 时钟使能
RCC->APB2ENR |= USART1_RCC_APB2_CLOCK_ENABLE;
/*
2.2 USART1 配置
A. 开启 USART1 功能 UE (USART Enable),
以及发送开启TE(Transmit Enable)和接收开启 RE (Receive Enable)
B. USART1 配置数 NZR 数据格式为 8N1
8 位数据位
0 位校验位
1 位停止位
1 位起始位
C. USART1 发送和接收 BRR 波特率配置。
*/
// USART1 发送和接收使能
USART1->CR1 |= (0x01 << 3); // USART1 CR1 TE 寄存器位开启
USART1->CR1 |= (0x01 << 2); // USART1 CR1 RE 寄存器位开启
// USART1 【8N1 配置】
// USART1 CR1 M 寄存器位明确为 0,限制 8 位数据位,1 位起始位,N 停止位
USART1->CR1 &= ~(0x01 << 12);
// USART1 CR1 PCE 和 PS 寄存器位明确为 0,不开启校验操作。
USART1->CR1 &= ~(0x03 << 9);
// USART1 CR2 STOP 寄存器为明确为 0,1 个停止位。
USART1->CR2 &= ~(0x03 << 12);
// USART1 发送和接收 BRR 波特率配置。
// 利用参数波特率计算 USART_DIV 数据
float usart_div = 72000000 / (16 * brr);
// 计算器波特率寄存器整数位内容
u32 div_mantissa = (u32)usart_div;
// 计算器波特率寄存器小数位内容
u32 div_fraction = (u32)((usart_div - div_mantissa) * 16);
// 存储 div_mantissa 和 div_fraction 到 USART1 BRR 寄存器中
USART1->BRR |= (div_mantissa << 4) | div_fraction;
// USART1 UE 寄存器为配置,开启 USART1 工作
// 【注意】开启 USRAT1 需要在所有配置完成之后,如果先开启 USART1
// 相关配置无法完成。类似于 出发前准备好所有内容。
USART1->CR1 |= (0x01 << 13);
}
7.MCU通过USART1发送和接收数据
7.1USART1_DR数据寄存器
USART_DR寄存器是由TDR 和 RDR 两个部分组成。操作哪一个寄存器取决于当前MCU对于DR寄存的行为。
7.2USART1_SR串口状态寄存器
在SR寄存器中,状态信息包括USART中断状态,USART数据流转状态,USART工作状态信息。
利用 SR 状态寄存器
-
TC 用于判断数据是否发送完成
-
TC 为 1 表示数据已发送完成
-
清除操作【读取 USART_SR, 之后写数据到 USART_DR】
-
-
RXNE 用于判断当前是否存在数据可读取
-
RXNE 为 1 表示有数据进入到 USART1 中
-
清除操作【读取 USART_DR】
-
7.3数据发送实现
/**
* @brief USART1 发送一个字节数据到接收端
*
* @param byte 当前需要通过 USART1 发送的字节数据。
*/
void USART1_SendByte(u8 byte);
/**
* @brief USART1 发送目标数据缓冲区内容
*
* @param buffer 发送数据缓冲区首地址
* @param count 发送数据的字节个数
*/
void USART1_SendBuffer(u8 *buffer, u16 count);
/**
* @brief USART1 发送字符串数据到接收端
*
* @param str 当前发送的字符串数据,建议仅发送 ASCII 字符串。
*/
void USART1_SendString(const char * str);
void USART1_SendByte(u8 byte)
{
/*
当前 while 循环是用于过滤判断串口是否完成上一次的数据发送
如果数据发送未完成,USART1->SR 寄存器 TC 位【位 6】 为 0,
& 操作结果为 0。while 循环始终执行。
有且只有数据发送完成,USART1->SR 寄存器 TC 位位
【位 6】为 1,while 循环结束,可以进入下一次数据发送环节。
【清除 TC 标志位操作】
需要 读 USART_SR 写入数据到 USART_DR
1. while 循环每一次执行,都需要通过【读取】USART1->SR 内容
进行数据判断。【已进行 USART_SR 寄存器读取操作】
2. while 循环终止,TC 位为 1,代码进入到 USART1->DR = byte
行为,【完成 USART_DR 写入数据操作】
【TC 数据发送完成标志位状态已清除】
*/
while (0 == (USART1->SR & (0x01 << 6)));
/*
USART1->DR = byte; 对于 USART1 而言是 MCU 写入数据到 DR 寄存器中
对应 USART1 行为【数据发送操作】
USART1 会将 DR 中的数据搬运到 TDR 数据发送寄存器,之后根据 USART1
的相关配置,自动完成 TDR 数据转运到移位寄存器,通过发送器控制,完
成 USART 数据发送。
*/
USART1->DR = byte;
}
void USART1_SendBuffer(u8 *buffer, u16 count)
{
while (count--)
{
USART1_SendByte(*buffer);
buffer += 1;
}
}
void USART1_SendString(const char * str)
{
while (*str)
{
USART1_SendByte((u8)(*str));
str += 1;
}
}