前言

本篇是 STM32 裸机开发系列第四天完整复盘笔记,承接 Day02 GPIO 输入输出、Day03 SysTick 系统定时器与 BitBand 位带操作内容。内容分为四大模块:当日早测核心考点复盘、独立看门狗 IWDG 底层原理与密钥寄存器详解、USART 串口通信完整理论与时序解析、串口驱动实操封装与课堂作业,最后拓展工业常用 RS232、RS485 电平标准对比。

早测采用口述原理形式,要求完整梳理前三天三大核心外设完整驱动逻辑,考察底层原理理解,不局限于单纯代码背诵:

1. LED 外设驱动原理

  1. 硬件基础:LED 绑定 GPIO 引脚,配置为推挽输出模式,通过修改 ODR 输出寄存器电平控制亮灭;
  2. 两种操作方式:标准库 GPIO_Write、底层寄存器直接赋值、BitBand 位带简化单引脚操作;
  3. 配套延时:摒弃精度差的 for 空循环,使用 SysTick 硬件定时器实现精准毫秒 / 秒级延时,组合实现流水灯效果。

2. 按键 KEY 输入驱动原理

  1. GPIO 配置:按键引脚配置浮空输入 / 上拉输入,常态高电平,按下拉低;
  2. 读取逻辑:读取 IDR 输入寄存器对应 bit 位电平,判断按键触发;
  3. 配套延时:SysTick 延时消抖,解决机械按键高低电平抖动导致的误触发。

3. SysTick 系统定时器原理

  1. 内核外设:Cortex-M3 内核自带 24 位递减定时器,独立于片上外设;
  2. 定时公式:定时时长 = 重装载计数值 / 定时器工作频率,实验分频后 9MHz;
  3. 两种开发方式:标准库封装函数、直接操作 CSR/RVR/CVR 三大寄存器;
  4. 优缺点:计时精准、无阻塞优化空间;单次最大定时 1s,长延时需循环叠加;标准库无关闭定时器 API,寄存器操作自由度更高。

二、独立看门狗 IWDG(Independent Watchdog)

2.1 看门狗设计初衷

嵌入式设备长期运行时,极易出现程序跑飞、死循环、硬件干扰卡死、数组越界死机等软件故障。一旦程序卡死,设备将失去控制,无法自动恢复。 独立看门狗是硬件级防护模块:独立内部低速时钟,不受主晶振失效影响;计数器持续递减,程序正常运行时定期喂狗重置计数;若超时未喂狗,计数器归零后硬件自动触发单片机系统复位,设备重启恢复正常工作状态,提升产品稳定性。

2.2 IWDG 定时核心公式

和 SysTick 定时计算逻辑完全统一,方便记忆: 定时时长重装载计数值工作频率

时钟参数说明

  1. 时钟来源:内部 RC 低速时钟 LSI,查阅《stm32f103RB.pdf》时钟树章节;
  2. 固定基准频率:40KHz
  3. 关键优势:LSI 独立于 HSE 高速外部晶振、HSI 内部高速时钟,即使主时钟损坏、程序死机,IWDG 依旧正常运行,不会失效。

2.3 IWDG 核心密钥寄存器 KR(Key Register)

IWDG 拥有写保护机制,预分频寄存器 PR、重装载寄存器 RLR 默认锁定,无法修改;所有配置、启停、喂狗操作均通过向 KR 写入固定密钥实现,三组密钥功能不可混淆:

写入十六进制密钥 硬件执行功能 使用场景
0xCCCC 启动独立看门狗,计数器开始从 RLR 值递减 初始化最后一步,开启看门狗计时
0xAAAA 喂狗刷新计数器,将 RLR 重装载值重新加载到计数寄存器 主循环定时调用,防止看门狗溢出复位
0x5555 解除 PR、RLR 寄存器写保护,允许修改分频系数、定时计数值 初始化阶段配置定时参数前必须调用

操作固定流程

  1. 写入 0x5555 解除写保护 → 2. 配置 PR 预分频、RLR 重装载值 → 3. 写入 0xCCCC 开启看门狗 → 4. 主循环定期写入 0xAAAA 喂狗。

2.4 IWDG 补充易错点拓展

  1. 看门狗一旦开启无法软件关闭,只能通过硬件复位彻底关闭;
  2. 喂狗间隔必须小于看门狗总定时时长,否则会触发意外复位;
  3. 适合工业设备、无人值守设备,调试阶段可注释看门狗初始化,避免频繁复位打断调试。

三、USART 通用同步异步收发器(串口通信)

3.1 串口基础概述

STM32F103 系列内置 3 路硬件 USART 外设(USART1/USART2/USART3),是嵌入式开发最通用的设备间通信接口,常用于单片机与电脑串口助手、GPS 模块、蓝牙模块、传感器之间数据交互。

USART 三大核心特性详解

  1. 串行传输 单根数据线分时传输数据,一个字节内 8 位数据按 bit 顺序逐位发送;对比并行通信多根数据线同时传输,串行布线简单、成本低,是设备间远距离通信主流方案。
  2. 全双工通信 独立两根信号线:TX 发送引脚、RX 接收引脚,收发通道完全分离,设备可同时发送 + 接收数据,互不阻塞;半双工仅一根数据线,同一时间只能收或发。
  3. 异步通信 无独立时钟同步信号线,收发双方依靠预先约定的波特率匹配采样时序;同步通信(SPI/I2S)额外搭载时钟线,由主机输出时钟同步从机。

3.2 单帧串口完整通信时序(标准 8N1 格式:8 数据位、无校验、1 停止位)

一帧完整数据传输顺序固定:空闲位 → 起始位 → 数据位 → 校验位 (可选) → 停止位,时序逻辑是串口收发解析底层核心:

  1. 空闲位 总线默认持续高电平,无数据传输时长期保持,代表总线空闲状态。
  2. 起始位 发送数据瞬间拉低总线,持续 1 个波特率周期,作为接收方数据接收触发标志;接收端检测到下降沿后,开始逐 bit 采样数据。
  3. 数据位 传输有效业务数据,工程默认配置 8bit,刚好对应 1 字节 char/u8 变量;总线高电平代表 bit=1,低电平代表 bit=0,低位优先传输。
  4. 校验位(可选,可关闭) 用于简单数据校验,排查传输过程电磁干扰导致的 bit 翻转错误,分为两种模式:
  • 奇校验:数据位所有 bit 中 1 的总个数 + 校验位 1 的个数 = 奇数;
  • 偶校验:数据位所有 bit 中 1 的总个数 + 校验位 1 的个数 = 偶数; 若数据传输出错,接收端校验不匹配,可标记数据无效丢弃。
  1. 停止位 数据、校验位传输完成后,拉高总线维持 1~2 个波特率周期,标记单帧数据传输结束,总线回到空闲电平等待下一帧数据。

3.3 串口通信强制匹配条件:波特率

  1. 定义:每秒传输二进制 bit 的总数量,单位 bit/s;
  2. 通信硬性要求:发送端、接收端波特率必须完全一致,否则采样错位,接收数据全部乱码;
  3. 工程常用标准波特率:9600、38400、115200,单片机调试优先使用 115200,传输速度更快。

3.4 USART1 硬件驱动完整开发流程

1. 硬件引脚分配与模式配置

USART1 挂载在 GPIOA 端口,TX/RX 引脚模式固定不可混用:

引脚编号 功能定义 GPIO 工作模式 补充说明
PA9 TX 数据发送引脚 复用推挽输出 向外输出串口数据
PA10 RX 数据接收引脚 浮空输入 读取外部设备发送电平

2. 初始化函数 usart1_init() 分步拆解

  1. 外设时钟使能 RCC 寄存器同时开启 GPIOA 端口时钟、USART1 外设时钟;STM32 所有外设默认时钟关闭,不开启时钟寄存器无响应,外设无法工作。
  2. GPIO 引脚模式初始化 配置 PA9 为复用推挽输出,PA10 为浮空输入,关闭上下拉电阻。
  3. USART 帧参数配置 配置寄存器设置一帧格式:数据位长度、停止位数量、校验位开关与校验模式;计算并配置分频寄存器,匹配目标波特率。
  4. 外设使能 开启 USART1 总开关,同时使能发送、接收通道,串口正式进入工作状态。

3. 底层基础收发封装函数

  1. 单字节发送函数 void usart1_send_byte(uint8_t data); 逻辑:写入数据到发送寄存器,循环等待发送完成标志位置 1,代表单字节发送完毕后退出函数,避免数据丢失。
  2. 单字节阻塞接收函数 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:串口发送自定义结构体(温湿度数据示例)

  1. 结构体定义
typedef unsigned char u8;
typedef struct data_st {
    u8 temp;    // 温度变量
    u8 humi;    // 湿度变量
    char str[32];// 自定义文本缓存
} data_st;
  1. 实现核心工具:snprintf() 作用:格式化数字、字符串到字符数组缓存,将结构体中数值转为可读文本,再调用字符串发送函数输出。
  2. 完整示例代码
// 定义结构体变量
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?

  1. 硬件层面:8bit 恰好对应单片机标准 1 字节存储单元,所有变量、寄存器最小存储单位均为字节,数据读写、存储逻辑统一;
  2. 通信适配层面:行业通用标准,电脑、各类传感器、蓝牙模块全部默认 8bit 数据位,兼容性最强;
  3. 误差控制层面:单帧数据长度固定,接收端解析逻辑简单,减少分段解析出错概率,大幅提升通信准确度;若使用 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 长、差分、工业多设备。


五、本章整体知识点总结

  1. IWDG 独立看门狗 独立 40KHz LSI 时钟,硬件级死机复位方案;依靠 KR 三组密钥控制启停、喂狗、解除寄存器写保护;定时计算公式与 SysTick 完全通用,适合无人值守设备提升稳定性。
  2. USART 串口核心理论 串行、全双工、异步三大特性;一帧数据分为空闲位、起始位、8bit 数据位、可选校验位、停止位;收发双方波特率必须完全匹配,否则数据乱码。
  3. USART1 驱动开发逻辑 开启 GPIOA 与 USART1 时钟 → 配置 TX/RX 引脚模式 → 设置帧格式与波特率 → 使能串口外设 → 封装单字节、字符串、结构体格式化发送函数。
  4. 远距离通信拓展 原生 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);
}
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐