嵌入式学习 | STM32 裸板驱动开发(Day04)超详细复习笔记(早测复盘|独立看门狗 IWDG|USART 异步串口通信|串口综合作业 + RS232/RS485 深度对比)
前言
本篇是 STM32 裸机开发系列第四天完整复盘笔记,承接 Day02 GPIO 输入输出、Day03 SysTick 系统定时器与 BitBand 位带操作内容。内容分为四大模块:当日早测核心考点复盘、独立看门狗 IWDG 底层原理与密钥寄存器详解、USART 串口通信完整理论与时序解析、串口驱动实操封装与课堂作业,最后拓展工业常用 RS232、RS485 电平标准对比。
早测采用口述原理形式,要求完整梳理前三天三大核心外设完整驱动逻辑,考察底层原理理解,不局限于单纯代码背诵:
1. LED 外设驱动原理
- 硬件基础:LED 绑定 GPIO 引脚,配置为推挽输出模式,通过修改 ODR 输出寄存器电平控制亮灭;
- 两种操作方式:标准库 GPIO_Write、底层寄存器直接赋值、BitBand 位带简化单引脚操作;
- 配套延时:摒弃精度差的 for 空循环,使用 SysTick 硬件定时器实现精准毫秒 / 秒级延时,组合实现流水灯效果。
2. 按键 KEY 输入驱动原理
- GPIO 配置:按键引脚配置浮空输入 / 上拉输入,常态高电平,按下拉低;
- 读取逻辑:读取 IDR 输入寄存器对应 bit 位电平,判断按键触发;
- 配套延时:SysTick 延时消抖,解决机械按键高低电平抖动导致的误触发。
3. SysTick 系统定时器原理
- 内核外设:Cortex-M3 内核自带 24 位递减定时器,独立于片上外设;
- 定时公式:定时时长 = 重装载计数值 / 定时器工作频率,实验分频后 9MHz;
- 两种开发方式:标准库封装函数、直接操作 CSR/RVR/CVR 三大寄存器;
- 优缺点:计时精准、无阻塞优化空间;单次最大定时 1s,长延时需循环叠加;标准库无关闭定时器 API,寄存器操作自由度更高。
二、独立看门狗 IWDG(Independent Watchdog)
2.1 看门狗设计初衷
嵌入式设备长期运行时,极易出现程序跑飞、死循环、硬件干扰卡死、数组越界死机等软件故障。一旦程序卡死,设备将失去控制,无法自动恢复。 独立看门狗是硬件级防护模块:独立内部低速时钟,不受主晶振失效影响;计数器持续递减,程序正常运行时定期喂狗重置计数;若超时未喂狗,计数器归零后硬件自动触发单片机系统复位,设备重启恢复正常工作状态,提升产品稳定性。
2.2 IWDG 定时核心公式
和 SysTick 定时计算逻辑完全统一,方便记忆: 定时时长重装载计数值工作频率
时钟参数说明
- 时钟来源:内部 RC 低速时钟 LSI,查阅《stm32f103RB.pdf》时钟树章节;
- 固定基准频率:40KHz;
- 关键优势:LSI 独立于 HSE 高速外部晶振、HSI 内部高速时钟,即使主时钟损坏、程序死机,IWDG 依旧正常运行,不会失效。
2.3 IWDG 核心密钥寄存器 KR(Key Register)
IWDG 拥有写保护机制,预分频寄存器 PR、重装载寄存器 RLR 默认锁定,无法修改;所有配置、启停、喂狗操作均通过向 KR 写入固定密钥实现,三组密钥功能不可混淆:
| 写入十六进制密钥 | 硬件执行功能 | 使用场景 |
|---|---|---|
| 0xCCCC | 启动独立看门狗,计数器开始从 RLR 值递减 | 初始化最后一步,开启看门狗计时 |
| 0xAAAA | 喂狗刷新计数器,将 RLR 重装载值重新加载到计数寄存器 | 主循环定时调用,防止看门狗溢出复位 |
| 0x5555 | 解除 PR、RLR 寄存器写保护,允许修改分频系数、定时计数值 | 初始化阶段配置定时参数前必须调用 |
操作固定流程
- 写入 0x5555 解除写保护 → 2. 配置 PR 预分频、RLR 重装载值 → 3. 写入 0xCCCC 开启看门狗 → 4. 主循环定期写入 0xAAAA 喂狗。
2.4 IWDG 补充易错点拓展
- 看门狗一旦开启无法软件关闭,只能通过硬件复位彻底关闭;
- 喂狗间隔必须小于看门狗总定时时长,否则会触发意外复位;
- 适合工业设备、无人值守设备,调试阶段可注释看门狗初始化,避免频繁复位打断调试。
三、USART 通用同步异步收发器(串口通信)
3.1 串口基础概述
STM32F103 系列内置 3 路硬件 USART 外设(USART1/USART2/USART3),是嵌入式开发最通用的设备间通信接口,常用于单片机与电脑串口助手、GPS 模块、蓝牙模块、传感器之间数据交互。
USART 三大核心特性详解
- 串行传输 单根数据线分时传输数据,一个字节内 8 位数据按 bit 顺序逐位发送;对比并行通信多根数据线同时传输,串行布线简单、成本低,是设备间远距离通信主流方案。
- 全双工通信 独立两根信号线:TX 发送引脚、RX 接收引脚,收发通道完全分离,设备可同时发送 + 接收数据,互不阻塞;半双工仅一根数据线,同一时间只能收或发。
- 异步通信 无独立时钟同步信号线,收发双方依靠预先约定的波特率匹配采样时序;同步通信(SPI/I2S)额外搭载时钟线,由主机输出时钟同步从机。
3.2 单帧串口完整通信时序(标准 8N1 格式:8 数据位、无校验、1 停止位)
一帧完整数据传输顺序固定:空闲位 → 起始位 → 数据位 → 校验位 (可选) → 停止位,时序逻辑是串口收发解析底层核心:
- 空闲位 总线默认持续高电平,无数据传输时长期保持,代表总线空闲状态。
- 起始位 发送数据瞬间拉低总线,持续 1 个波特率周期,作为接收方数据接收触发标志;接收端检测到下降沿后,开始逐 bit 采样数据。
- 数据位 传输有效业务数据,工程默认配置 8bit,刚好对应 1 字节 char/u8 变量;总线高电平代表 bit=1,低电平代表 bit=0,低位优先传输。
- 校验位(可选,可关闭) 用于简单数据校验,排查传输过程电磁干扰导致的 bit 翻转错误,分为两种模式:
- 奇校验:数据位所有 bit 中 1 的总个数 + 校验位 1 的个数 = 奇数;
- 偶校验:数据位所有 bit 中 1 的总个数 + 校验位 1 的个数 = 偶数; 若数据传输出错,接收端校验不匹配,可标记数据无效丢弃。
- 停止位 数据、校验位传输完成后,拉高总线维持 1~2 个波特率周期,标记单帧数据传输结束,总线回到空闲电平等待下一帧数据。
3.3 串口通信强制匹配条件:波特率
- 定义:每秒传输二进制 bit 的总数量,单位 bit/s;
- 通信硬性要求:发送端、接收端波特率必须完全一致,否则采样错位,接收数据全部乱码;
- 工程常用标准波特率:9600、38400、115200,单片机调试优先使用 115200,传输速度更快。
3.4 USART1 硬件驱动完整开发流程
1. 硬件引脚分配与模式配置
USART1 挂载在 GPIOA 端口,TX/RX 引脚模式固定不可混用:
| 引脚编号 | 功能定义 | GPIO 工作模式 | 补充说明 |
|---|---|---|---|
| PA9 | TX 数据发送引脚 | 复用推挽输出 | 向外输出串口数据 |
| PA10 | RX 数据接收引脚 | 浮空输入 | 读取外部设备发送电平 |
2. 初始化函数 usart1_init() 分步拆解
- 外设时钟使能 RCC 寄存器同时开启 GPIOA 端口时钟、USART1 外设时钟;STM32 所有外设默认时钟关闭,不开启时钟寄存器无响应,外设无法工作。
- GPIO 引脚模式初始化 配置 PA9 为复用推挽输出,PA10 为浮空输入,关闭上下拉电阻。
- USART 帧参数配置 配置寄存器设置一帧格式:数据位长度、停止位数量、校验位开关与校验模式;计算并配置分频寄存器,匹配目标波特率。
- 外设使能 开启 USART1 总开关,同时使能发送、接收通道,串口正式进入工作状态。
3. 底层基础收发封装函数
- 单字节发送函数
void usart1_send_byte(uint8_t data);逻辑:写入数据到发送寄存器,循环等待发送完成标志位置 1,代表单字节发送完毕后退出函数,避免数据丢失。 - 单字节阻塞接收函数
uint8_t usart1_recv_byte(void);逻辑:循环检测接收标志位,等待外部设备发送数据;标志置 1 后读取接收寄存器,返回单字节数据,无数据时程序阻塞等待。
四、串口课堂作业 + 拓展问答深度解析
4.1 基础功能开发作业
作业 1:串口发送字符串函数
函数声明
void usart1_send_string(const char *p);
完整实现代码
void usart1_send_string(const char *p)
{
// 循环遍历字符串,直到读取到字符串结束符'\0'
while (*p != '\0')
{
usart1_send_byte(*p);
p++;
}
}
原理说明
C 语言字符串以\0作为结束标志,逐个取出字符调用单字节发送函数,实现整段文字打印;调试时常用usart1_send_string("hello stm32\r\n");打印日志。
作业 2:串口发送自定义结构体(温湿度数据示例)
- 结构体定义
typedef unsigned char u8;
typedef struct data_st {
u8 temp; // 温度变量
u8 humi; // 湿度变量
char str[32];// 自定义文本缓存
} data_st;
- 实现核心工具:
snprintf()作用:格式化数字、字符串到字符数组缓存,将结构体中数值转为可读文本,再调用字符串发送函数输出。 - 完整示例代码
// 定义结构体变量
data_st sensor_data = {26, 58, "sensor data test"};
// 定义打印缓存
char print_buf[64];
// 格式化结构体数据到缓存
snprintf(print_buf, sizeof(print_buf), "temp:%d℃, humi:%d%%, msg:%s\r\n",
sensor_data.temp, sensor_data.humi, sensor_data.str);
// 串口打印
usart1_send_string(print_buf);
4.2 拓展思考题完整解答
问题 1:为什么串口单帧有效数据默认最多 8bit?
- 硬件层面:8bit 恰好对应单片机标准 1 字节存储单元,所有变量、寄存器最小存储单位均为字节,数据读写、存储逻辑统一;
- 通信适配层面:行业通用标准,电脑、各类传感器、蓝牙模块全部默认 8bit 数据位,兼容性最强;
- 误差控制层面:单帧数据长度固定,接收端解析逻辑简单,减少分段解析出错概率,大幅提升通信准确度;若使用 9bit 及以上,通用串口助手无法适配,仅特殊工业协议使用。
问题 2:原生 UART 通信距离很短,如何实现几百米远距离数据传输?
UART 仅定义芯片内部电平收发逻辑,传输距离由外部电平转换标准决定,分为 RS232、RS485 两种工业标准,二者传输能力差距极大:
(1)RS232(电脑 DB9 调试串口)
- 信号传输方式:单端电平传输,信号电压相对公共 GND 地线判定高低电平;
- 电平标准:高电平 - 12V、低电平 + 12V,和单片机 3.3V TTL 电平不兼容,需要电平转换芯片;
- 极限传输距离:标准推荐 15 米;波特率越高,传输距离越短,115200 高速下仅 3~5 米;
- 拓扑限制:仅支持点对点 1 对 1 通信,一条总线只能连接两个设备;
- 抗干扰能力:极差,工业电机、继电器电磁干扰极易造成数据乱码;
- 适用场景:电脑与开发板近距离调试、实验室短距离通信,无法实现几百米传输。
(2)RS485(工业远距离总线标准)
- 信号传输方式:差分双线传输,依靠 A、B 两根信号线电压差值判断高低电平,不依赖地线;
- 抗干扰优势:空间电磁干扰会同时叠加在 A、B 两根线上,差值不变,完美抵消干扰;
- 极限传输距离:标准最大 1200 米,轻松满足几百米长距离通信需求;
- 拓扑拓展:总线型拓扑,单条总线最多挂载 32 个通信节点,支持多设备组网;
- 通信模式:半双工,同一时间只能单方向收发;
- 适用场景:工厂传感器、远程采集设备、楼宇远距离数据传输。
快速记忆区分技巧
RS232:短距离、点对点、电脑调试专用; RS485:千米级、差分抗干扰、多节点、工业远距离通信。
4.3 RS232 与 RS485 完整对比表格
| 对比维度 | RS232 | RS485 |
|---|---|---|
| 信号传输机制 | 单端电平,相对地线判断电平 | A/B 差分双线,依靠电压差值判定信号 |
| 最大传输距离 | 约 15 米,高速波特率距离大幅缩短 | 标准最长 1200 米 |
| 总线支持节点 | 仅点对点,1 对 1 两个设备 | 总线组网,最多 32 个设备节点 |
| 抗电磁干扰能力 | 弱,工业环境极易乱码 | 极强,适合复杂电磁工业现场 |
| 通信模式 | 全双工 | 半双工 |
| 典型使用场景 | PC 串口调试、室内近距离设备通信 | 工业传感器、远程长距离数据采集 |
速记口诀
232 短、单点、调试用;485 长、差分、工业多设备。
五、本章整体知识点总结
- IWDG 独立看门狗 独立 40KHz LSI 时钟,硬件级死机复位方案;依靠 KR 三组密钥控制启停、喂狗、解除寄存器写保护;定时计算公式与 SysTick 完全通用,适合无人值守设备提升稳定性。
- USART 串口核心理论 串行、全双工、异步三大特性;一帧数据分为空闲位、起始位、8bit 数据位、可选校验位、停止位;收发双方波特率必须完全匹配,否则数据乱码。
- USART1 驱动开发逻辑 开启 GPIOA 与 USART1 时钟 → 配置 TX/RX 引脚模式 → 设置帧格式与波特率 → 使能串口外设 → 封装单字节、字符串、结构体格式化发送函数。
- 远距离通信拓展 原生 TTL-UART 搭配 RS232 仅支持短距离调试;项目需要几百米远距离通信时,必须外接 485 电平转换芯片,使用差分信号传输。
补充工程拓展代码(原文缺失内容补齐)
1. IWDG 简易初始化框架
void IWDG_Init(void)
{
IWDG->KR = 0x5555; // 解除写保护
IWDG->PR = 0x03; // 预分频64
IWDG->RLR = 1250; // 设置重装载值
IWDG->KR = 0xCCCC; // 开启看门狗
}
// 喂狗函数
void IWDG_FeedDog(void)
{
IWDG->KR = 0xAAAA;
}
2. 串口完整打印封装(支持数字打印)
void usart1_send_num(uint32_t num)
{
char buf[20];
snprintf(buf, sizeof(buf), "%d", num);
usart1_send_string(buf);
}更多推荐
所有评论(0)