STM32F103 学习笔记-21-串口通信(第4节)-串口发送和接收代码讲解(中)
STM32F103 学习笔记 - USART串口通信实战编程
整理和优化了格式,使结构更清晰、重点更突出,便于学习和查阅。
一、USART串口通信基础概念与硬件原理
1.1 什么是USART串口通信(概念)
-
中英文对照:通用同步/异步收发器(Universal Synchronous/Asynchronous Receiver/Transmitter, USART)
-
生活化类比:串口通信是STM32与电脑、外设(如WiFi模块)之间“聊天”的核心方式,就像两个人通过电话线打电话——需要物理连接的“电话线”(硬件电路),也需要约定好“说话的语速、每句话的字数”(通信协议),双方才能听懂彼此的内容。
-
核心作用:实现STM32与上位机(电脑)、外部设备的双向数据传输,是嵌入式开发中最基础、最常用的通信方式。
1.2 串口通信的硬件原理(原理)
STM32的串口输出为TTL电平(高电平3.3V,低电平0V),而电脑的USB接口是数字总线信号,二者无法直接通信,必须通过“电平转换翻译官”实现信号匹配:
-
核心转换芯片:CH340G(USB转USART电平转换芯片),负责把电脑USB信号转换成STM32能识别的TTL电平,反之亦然。
-
交叉连接原则:就像打电话时“你说的话要传到对方耳朵,对方说的话传到你耳朵”,STM32的TX(发送)引脚必须接CH340的RX(接收)引脚,STM32的RX(接收)引脚必须接CH340的TX(发送)引脚,这是串口通信的硬件核心规则。
-
时钟总线基础:STM32的USART外设挂载在不同的总线(APB1/APB2)上(ARM Cortex-M3内核的总线架构),USART1挂载APB2总线,USART2/3、UART4/5挂载APB1总线——总线相当于STM32内部的“电路主干道”,不同总线的时钟配置规则不同,是后续软件配置的关键前提。
1.3 串口硬件连接与跳帽配置(配置步骤+实践)
1.3.1 CH340驱动安装(硬件前提)
电脑必须先安装CH340芯片驱动,否则无法识别开发板的串口设备:
-
驱动位置:开发板配套光盘「开发软件/USB转串口驱动-CH340」目录;
-
安装要求:以管理员身份运行安装程序(Windows系统权限限制,类比“必须有钥匙才能开门”);
-
验证方法:安装后用USB线连接开发板的“USB TO UART”接口,打开电脑「设备管理器-端口」,若显示“USB串行设备(COMx)”,说明驱动安装成功。
1.3.2 开发板串口跳帽配置
开发板通过跳帽实现串口硬件连接的灵活切换,默认配置满足基础使用,自定义场景需调整。
|
配置场景 |
操作步骤 |
核心目的 |
|---|---|---|
|
使用USART1(默认) |
跳帽保持接通 |
直接使用PA9(TX)/PA10(RX)与CH340通信,无需改硬件 |
|
释放PA9/PA10引脚 |
拔掉USART1跳帽 |
引脚可复用为普通GPIO,或连接其他外设 |
|
使用其他串口(如USART2) |
拔掉USART1跳帽,用杜邦线将CH340的TX/RX交叉连接到USART2的PA2(TX)/PA3(RX) |
适配多串口应用场景 |
1.3.3 串口引脚与总线映射表
|
串口编号 |
总线挂载 |
发送引脚(TX) |
接收引脚(RX) |
核心注意事项 |
|---|---|---|---|---|
|
USART1 |
APB2 |
PA9 |
PA10 |
默认连接CH340,时钟使能用 |
|
USART2 |
APB1 |
PA2 |
PA3 |
时钟使能用 |
|
USART3 |
APB1 |
PB10 |
PB11 |
默认连ESP8266,需拔跳帽复用 |
|
UART4 |
APB1 |
PC10 |
PC11 |
无默认外设连接,可直接杜邦线映射 |
|
UART5 |
APB1 |
PC12 |
PD2 |
无默认外设连接,可直接杜邦线映射 |
二、USART串口通信软件配置(核心)
2.1 工程结构搭建(配置步骤)
2.1.1 新建驱动文件
在KEIL工程的USER目录下新建bsp_usart.c和bsp_usart.h,分工如下(C语言知识点):
-
bsp_usart.h:存放宏定义、函数声明(类比“产品说明书”,告诉其他文件有哪些功能可用); -
bsp_usart.c:存放函数实现(类比“产品生产线”,具体实现功能)。
2.1.2 头文件防重复包含(C语言知识点)
在bsp_usart.h开头添加条件编译框架,避免多次包含导致编译错误:
#ifndef __BSP_USART_H // 如果未定义该宏
#define __BSP_USART_H // 定义宏,标记已包含
#include "stm32f10x.h" // 引入STM32核心头文件
// 后续添加宏定义、函数声明
#endif // 结束条件编译
2.1.3 KEIL工程配置
-
将
bsp_usart.c添加到USER分组; -
打开KEIL「魔术棒-C/C++」,添加
bsp_usart.h所在的头文件目录(确保编译器能找到头文件)。
2.2 串口软件配置核心步骤(原理+配置步骤)
串口配置需遵循“时钟→GPIO→USART参数→中断→使能”的顺序,每一步都对应硬件寄存器的配置。
|
配置步骤 |
核心原理 |
生活化类比 |
|---|---|---|
|
1. 使能GPIO和USART时钟 |
STM32外设必须先开启时钟才能工作(Cortex-M3内核的时钟树规则) |
给电器插电源,没电源无法工作 |
|
2. 配置GPIO引脚模式 |
TX引脚需主动输出电平(复用推挽输出),RX引脚被动接收电平(浮空输入) |
TX是“说话的嘴”(主动输出),RX是“听声音的耳朵”(被动接收) |
|
3. 配置USART通信参数 |
波特率、数据位等必须与上位机一致,否则通信乱码 |
两个人聊天必须说同一种语言,否则听不懂 |
|
4. 配置NVIC中断优先级 |
串口接收中断需要指定优先级,避免与其他中断冲突 |
公司接电话,紧急电话(高优先级)先处理 |
|
5. 使能串口接收中断 |
开启“收到数据就提醒”的功能 |
手机开启“新消息提醒”,有消息就弹窗 |
|
6. 使能USART外设 |
打开串口的总开关 |
打开手机的通话功能,才能接打电话 |
2.3 核心代码实例与解析(代码实例+关键点解析)
2.3.1 宏定义(C语言知识点:简化代码,方便移植)
在bsp_usart.h中定义串口相关宏,修改串口时只需改宏定义,无需修改所有代码:
// USART1核心宏定义
#define DEBUG_USARTx USART1
#define DEBUG_USART_CLK RCC_APB2Periph_USART1
#define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// GPIO引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOA
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_9
#define DEBUG_USART_RX_GPIO_PORT GPIOA
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10
// 中断相关宏定义
#define DEBUG_USART_IRQ USART1_IRQn
#define DEBUG_USART_IRQHandler USART1_IRQHandler
2.3.2 GPIO初始化函数(解析寄存器+结构体)
在bsp_usart.c中实现GPIO配置,逐行解析核心逻辑:
static void USART_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure; // 定义GPIO配置结构体(C语言:结构体打包配置参数)
// 1. 开启GPIO时钟(给GPIO“通电”)
DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
// 2. 开启USART时钟(给串口“通电”)
DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);
// 3. 配置TX引脚(PA9)为复用推挽输出
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出:引脚作为USART功能,而非普通GPIO
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 引脚输出速率50MHz
GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure); // 把配置写入寄存器(传入结构体指针)
// 4. 配置RX引脚(PA10)为浮空输入
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 浮空输入:电平由外部设备决定,无需上下拉
GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
}
关键点解析:
-
GPIO_Mode_AF_PP(复用推挽输出):TX引脚需要主动输出USART的电平信号,复用模式表示引脚归USART外设管理,而非普通GPIO; -
GPIO_Mode_IN_FLOATING(浮空输入):RX引脚接收CH340的电平信号,浮空模式能准确识别外部电平变化,避免上下拉电阻干扰。
2.3.3 USART参数配置函数(解析通信协议)
static void USART_Mode_Config(void)
{
USART_InitTypeDef USART_InitStructure; // USART配置结构体
// 1. 配置核心通信参数(必须与上位机一致)
USART_InitStructure.USART_BaudRate = DEBUG_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_HardwareFlowControl = USART_HardwareFlowControl_None; // 无硬件流控(仅用TX/RX/GND)
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 同时使能收/发模式
// 2. 将配置写入USART寄存器
USART_Init(DEBUG_USARTx, &USART_InitStructure);
// 3. 使能接收中断:RXNE(接收数据寄存器非空)中断
USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);
// 4. 使能USART外设(打开总开关)
USART_Cmd(DEBUG_USARTx, ENABLE);
}
关键点解析:
-
波特率:工业常用115200(高速)、9600(低速),上位机与STM32必须一致,否则出现乱码;
-
USART_IT_RXNE:接收数据寄存器非空中断,当串口收到1字节数据时,寄存器被填充,触发中断,STM32会暂停当前工作,优先处理接收的数据。
2.3.4 NVIC中断配置函数(解析中断优先级)
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure; // NVIC配置结构体
// 1. 配置中断优先级分组:2位抢占优先级,2位子优先级(Cortex-M3内核规则)
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
// 2. 配置USART1中断源
NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ; // 指定中断通道(USART1)
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 抢占优先级1(高优先级可打断低优先级)
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 子优先级1(同抢占优先级时的执行顺序)
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能该中断通道
// 3. 写入NVIC配置
NVIC_Init(&NVIC_InitStructure);
}
生活化类比:
-
抢占优先级:火警电话(高优先级)能打断快递电话(低优先级),先处理火警;
-
子优先级:两个火警电话(同抢占优先级),先处理子优先级低的。
2.3.5 串口初始化封装函数
将GPIO、NVIC、USART配置封装为统一函数,方便main函数调用:
void USART_Config(void)
{
USART_GPIO_Config();
NVIC_Configuration();
USART_Mode_Config();
}
在bsp_usart.h中声明该函数:
void USART_Config(void); // 串口初始化函数声明
2.3.6 单字节发送函数(解析寄存器标志位)
// 串口发送单字节函数(C语言:形参pUSARTx支持多串口复用)
void Usart_SendByte(USART_TypeDef * pUSARTx, uint8_t ch)
{
// 1. 向USART数据寄存器写入待发送字节
USART_SendData(pUSARTx, ch);
// 2. 等待TXE标志位(发送数据寄存器为空)置位(volatile关键字:防止编译器优化,必须读取实时值)
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
在bsp_usart.h中声明:
void Usart_SendByte(USART_TypeDef * pUSARTx, uint8_t ch); // 单字节发送函数声明
关键点解析:
-
TXE标志位:当数据从“发送数据寄存器”转移到“移位寄存器”时,TXE置1,表示可以发送下1字节; -
循环等待:确保1字节发送完成后再发送下1字节,避免数据丢失(类比“等对方听完一句话,再说下一句”)。
2.4 main函数测试代码(实践)
#include "stm32f10x.h"
#include "bsp_usart.h"
int main(void)
{
// 1. 初始化串口:115200 8-N-1(8位数据位、无校验位、1位停止位)
USART_Config();
// 2. 向上位机发送单字节字符'a'
Usart_SendByte(DEBUG_USARTx, 'a');
// 3. 主循环空转,等待接收中断
while(1)
{
}
}
三、硬件验证与调试技巧(实践)
3.1 串口调试助手配置
使用野火串口调试助手,配置参数必须与STM32一致。
|
配置项 |
取值 |
核心说明 |
|---|---|---|
|
端口号 |
设备管理器中显示的COMx |
如COM3、COM4,需与开发板对应 |
|
波特率 |
115200 |
与代码中 |
|
数据位 |
8 |
与 |
|
停止位 |
1 |
与 |
|
校验位 |
None |
与 |
3.2 现象验证
-
编译代码并烧录到开发板;
-
按下复位键,串口调试助手接收区显示字符
a,说明单字节发送功能正常; -
若发送十进制
100,调试助手默认显示字符d(ASCII码),勾选“十六进制显示”可看到0x64(十进制100的十六进制)。
3.3 常见问题与解决方法
|
问题现象 |
可能原因 |
解决方法 |
|---|---|---|
|
设备管理器无COM口 |
CH340驱动未安装/USB线接触不良/跳帽未接 |
重装驱动(管理员权限)/更换USB线/检查跳帽 |
|
通信乱码 |
波特率不一致/时钟配置错误/GPIO模式错误 |
核对调试助手与代码的波特率/检查时钟使能函数/确认TX为复用推挽输出 |
|
接收不到数据 |
接收中断未使能/RX引脚接反/跳帽未接 |
检查 |
3.4 调试进阶技巧
-
逻辑分析仪:连接TX/RX引脚,查看电平变化,验证数据是否正确发送;
-
printf重定向:后续可将C标准库
printf函数重定向到串口,实现格式化输出(如printf("串口初始化成功!\r\n");),方便调试; -
中断调试:在中断服务函数中添加调试代码,验证接收中断是否触发。
四、小结与思考
4.1 小结
-
USART串口通信的核心是“硬件电平匹配(CH340)+ 通信参数一致 + 中断配置正确”;
-
软件配置需遵循“时钟→GPIO→USART参数→NVIC中断→使能外设”的顺序;
-
关键C语言知识点:结构体(打包配置参数)、宏定义(简化移植)、指针(函数传参)、volatile(防止寄存器优化);
-
调试核心:先确保硬件连接正确,再核对通信参数,最后排查中断与寄存器配置。
4.2 自问自答
1. 为什么使用void Usart_SendByte(USART_TypeDef* pUSARTx, uint8_t data)这个函数?
这个函数是对STM32标准库底层函数的封装,核心目的是:
-
复用性与通用化:参数
pUSARTx支持任意串口(USART1/2/3等),一套代码可驱动所有串口发送字节,无需为每个串口写重复逻辑 -
简化开发:底层
USART_SendData()仅负责把数据写入寄存器,但不等待发送完成;封装后自动加入while (USART_GetFlagStatus(..., USART_FLAG_TXE) == RESET),确保数据真正发送到硬件缓冲区,避免丢字节 -
降低耦合:上层代码无需关注“如何写寄存器、如何等状态”,只需调用
Usart_SendByte(USART1, 0x55)即可完成字节发送,便于维护 -
类型适配:
USART_SendData()的Data参数是uint16_t(适配9位数据位场景),而封装为uint8_t更贴合“8位数据位”的通用场景,语义更清晰
2. 为什么把USART_TypeDef* pUSARTx换成DEBUG_USARTx?
DEBUG_USARTx是宏定义(通常在bsp_usart.h中定义,如#define DEBUG_USARTx USART1),替换的核心价值:
-
可读性提升:
DEBUG_USARTx直观表示“调试专用串口”,比直接写USART1更易理解代码意图 -
可维护性:若需更换调试串口(如从USART1改为USART2),仅需修改宏定义,无需逐行修改所有函数调用
-
防出错:避免手动写
USARTx时输错(如把USART1写成USART3),宏定义是“唯一入口” -
场景适配:调试串口是固定的,用宏固化后,上层代码无需关注“具体是哪个串口”,聚焦业务逻辑
3. 为什么编写Usart_SendByte()要参照USART_Cmd()?USART_TypeDef* USARTx指的是什么?
(1)参照USART_Cmd()的原因
USART_Cmd()是STM32标准库中“串口外设控制”的范式函数,编写Usart_SendByte()参照它的核心逻辑:
-
遵循标准库的参数设计规范:
USART_TypeDef*是操作串口的统一参数类型,保证代码与标准库兼容 -
遵循“外设操作传指针”的设计思想:STM32所有外设驱动函数(如
GPIO_Init()/USART_Init())均以“外设结构体指针”为第一个参数,保持代码风格统一 -
底层逻辑对齐:
USART_Cmd()通过指针操作串口寄存器(如USARTx->CR1),Usart_SendByte()同理通过指针访问目标串口的发送寄存器/状态寄存器,避免脱离库的设计逻辑导致错误
(2)USART_TypeDef* USARTx的含义
-
USART_TypeDef是STM32标准库定义的串口寄存器结构体(在stm32f10x.h中),结构体成员与串口的硬件寄存器一一对应(如CR1对应控制寄存器1、SR对应状态寄存器、DR对应数据寄存器) -
USART_TypeDef* USARTx是指向该结构体的指针,其值为某串口的“寄存器基地址”(如USART1_BASE = 0x40013800) -
操作
USARTx->DR等价于直接操作该串口的硬件数据寄存器,指针是“访问特定串口寄存器”的唯一入口
4. USART_Cmd()中“使能/失能串口”是什么意思?
USART_Cmd(USARTx, ENABLE/DISABLE)的本质是操作串口控制寄存器1(USART_CR1)的UE位(串口使能位,代码中CR1_UE_Set = 0x2000):
-
使能串口(ENABLE):将
UE位置1,让串口外设从“休眠态”进入“工作态”——串口硬件开始响应收发请求、中断、时钟等,可正常执行收发操作 -
失能串口(DISABLE):将
UE位清0,关闭串口所有功能——停止收发、禁用中断、硬件不消耗时钟,核心目的是节省功耗(如低功耗场景下关闭未使用的串口)
简单说:“使能串口”是给串口“上电干活”,“失能串口”是让串口“断电休息”
5. 为什么使能串口要传入指针?
核心是STM32的外设设计和代码通用化:
-
STM32的每个串口(USART1/2/3/UART4/5)都有独立的寄存器块(物理地址不同),但所有串口的寄存器布局完全相同(均符合
USART_TypeDef结构体) -
传入指针
USARTx,本质是告诉函数“要操作哪个串口的寄存器”(指针指向该串口的寄存器基地址) -
若不传入指针,需为每个串口写单独的使能函数(如
USART1_Cmd()/USART2_Cmd()),代码冗余且难以维护;通过指针可实现“一个USART_Cmd()函数控制所有串口”,符合嵌入式代码“极简复用”的设计原则
6. 为什么串口通常只配置为8位数据位?
8位数据位是行业通用标准,核心原因:
-
字符编码适配:ASCII码(最常用的字符编码)仅需7位表示,加1位校验位(或无校验)刚好占8位,满足绝大多数文本/指令传输需求
-
硬件兼容性:几乎所有串口外设(传感器、模块、上位机串口助手)默认配置为“8N1”(8位数据位、无校验、1位停止位),无需额外适配
-
数据处理效率:计算机最小数据单元是“字节(8位)”,8位数据位可直接映射为1个字节,无需拆分/拼接(如9位数据位需拆分为2个字节处理,效率低)
-
硬件限制:STM32串口虽支持9位数据位,但仅用于极特殊场景(如多机通信的“地址帧/数据帧”区分),日常开发无需求
7. 为什么要参照void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)?
USART_SendData()是STM32标准库提供的底层寄存器操作函数,参照它的核心原因:
-
避免直接操作寄存器:直接写
USARTx->DR = data虽可行,但易因寄存器位偏移写错(如误写其他位);标准库函数封装了寄存器操作逻辑,降低出错风险 -
功能依赖:
Usart_SendByte()的核心是“发送字节”,必须基于USART_SendData()将数据写入串口的发送数据寄存器(USART_DR),这是硬件层面的唯一发送方式 -
参数对齐:
USART_TypeDef*是操作串口的标准参数类型,参照后保证代码与标准库的兼容性 -
适配硬件设计:
USART_SendData()的Data为uint16_t,是为了适配9位数据位场景(低9位有效);封装为uint8_t后,既兼容8位场景,又保留对标准库的适配性
8. 硬件流控制是什么意思,有什么作用?
(1)硬件流控制的定义
硬件流控制是通过专用硬件引脚(而非软件指令)协调串口收发双方的传输节奏,STM32支持的硬件流控引脚为:
-
RTS(Request To Send):本设备 → 对方,表示“我可以接收数据,请发送” -
CTS(Clear To Send):对方 → 本设备,表示“你可以发送数据,我已准备好”
(2)核心作用
-
防止数据丢失:当接收方缓冲区满时,通过
RTS引脚拉低告知发送方“暂停发送”;缓冲区有空后再拉高,恢复发送,避免数据溢出丢失 -
适配高速/大量数据:软件流控(如XON/XOFF)依赖字符交互,有延迟;硬件流控基于电平信号,响应速度毫秒级,适合高速传输
-
提升稳定性:工业场景(强干扰、长距离)下,硬件电平信号比软件指令更抗干扰,传输更稳定
注:日常调试中常用
USART_HardwareFlowControl_None(无流控),因为硬件流控需要额外焊接RTS/CTS引脚,增加硬件复杂度;仅在高速/高可靠性场景下启用
9. 为什么要参照FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG)?
USART_GetFlagStatus()是标准库封装的串口状态检测函数,参照它的核心原因:
-
标准化状态检测:串口的所有状态(发送空、接收满、发送完成等)都存储在
USART_SR(状态寄存器)中,直接读寄存器易因“位掩码记错”出错(如TXE是第7位,误写成第6位);标准库封装后,只需传入宏定义(如USART_FLAG_TXE)即可精准检测 -
实现“等待发送完成”:
Usart_SendByte()中while (USART_GetFlagStatus(..., USART_FLAG_TXE) == RESET)是核心逻辑——等待发送寄存器为空,确保数据真正写入硬件缓冲区,避免因“寄存器未空就写新数据”导致丢字节 -
通用化适配:该函数支持检测所有串口状态位(TXE/RXNE/TC等),参照后可快速扩展功能(如接收字节、检测发送完成),无需重复写寄存器读取逻辑
-
可读性提升:
USART_FLAG_TXE语义明确(发送寄存器空),比直接写USARTx->SR & 0x0080更易理解
10. 为什么串口只指定了需要检查的标志位,就能实现状态检测?
核心原理是串口状态寄存器(USART_SR)的位映射设计:
-
串口的所有状态(发送空、接收满、发送完成等)都通过
USART_SR寄存器的不同位标识(如TXE对应第7位,RXNE对应第5位) -
标准库中,每个“标志位宏”(如
USART_FLAG_TXE)本质是USART_SR的位掩码(如#define USART_FLAG_TXE ((uint16_t)0x0080)) -
USART_GetFlagStatus()的内部逻辑:FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG) { return (USARTx->SR & USART_FLAG) ? SET : RESET; }即读取
USART_SR的值,与传入的USART_FLAG(位掩码)做“按位与”:若结果非0,说明该状态位置1(对应状态发生);否则未发生 -
总结:“标志位”是
USART_SR寄存器的“位索引”,指定标志位就相当于告诉函数“要检查SR寄存器的哪一位”,因此只需传标志位即可实现精准的状态检测
4.3 思考
-
如何基于单字节发送函数,实现字符串、数组的发送功能?
-
如何重定向
printf/scanf函数到串口,实现格式化输入输出? -
如何编写USART接收中断服务函数,实现上位机数据的接收与回显?
-
若需使用USART2,代码中需要修改哪些宏定义和函数?(提示:总线改为APB1,引脚改为PA2/PA3,时钟使能函数改为
RCC_APB1PeriphClockCmd) -
如何通过串口指令控制板载RGB灯的亮灭?(提示:在中断服务函数中解析接收的指令,控制GPIO电平)
更多推荐


所有评论(0)