stm32重要概念
影子寄存器(Shadow Register)
STM32 影子寄存器(Shadow Register)是定时器硬件内部真正生效的寄存器,作用是确保时序参数(周期、占空比、分频)在更新时不产生毛刺、不破坏当前周期完整性,实现同步、无抖动的参数切换。
基本结构:预装载 + 影子
STM32 定时器里带 “阴影” 标记的寄存器(ARR、CCR、PSC、RCR)都由两部分组成:
- 预装载寄存器(Preload Register)
- 软件直接读写的对象(如 TIMx->ARR、TIMx->CCR1)
- 你写的值先存在这里,不一定立即生效
- 影子寄存器(Shadow Register)
- 硬件内部、用户不可直接访问
- 真正参与计数、比较、输出的寄存器
- 只有它的值决定当前定时器行为
核心作用(为什么需要影子)
- 保证当前计数周期完整,不被中途截断
- 计数器正在跑时,你改 ARR/CCR:
- 无影子:立即改硬件 → 周期突然变短 / 变长、PWM 出现毛刺、尖峰、丢脉冲
- 有影子:新值暂存预装载,等当前周期结束(更新事件 UEV)才加载到影子 → 平滑切换
- 计数器正在跑时,你改 ARR/CCR:
- 多通道参数同步更新
- 同时改多个 CCR(多通道 PWM):
- 软件不可能同一时刻写完所有寄存器
- 开启预装载 → 所有新值先缓存
- 一次更新事件 → 所有影子寄存器同时刷新 → 多通道严格同步
- 同时改多个 CCR(多通道 PWM):
- 防止运行中修改导致逻辑错乱
- 避免在计数中途突变阈值,造成:
- 意外中断 / 溢出
- 输出波形失真、电机异响、采样错位
- 时序逻辑不可预知
- 避免在计数中途突变阈值,造成:
常见带影子的寄存器(定时器)
- ARR(自动重装载):决定周期
- 控制位:TIMx_CR1.ARPE(ARR 预装载使能)
- CCR(捕获 / 比较):决定 PWM 占空比、比较阈值
- 控制位:TIMx_CCMRx.OCxPE(通道 x 预装载使能)
- PSC(预分频器):计数时钟分频
- 始终带影子,无使能位 → 必须等更新事件才生效
- RCR(重复计数器):高级定时器,更新事件分频
两种工作模式(以 ARR 为例)
模式 1:立即生效(ARPE=0)
- 预装载 ↔ 影子直通
- 写 TIMx->ARR → 立即更新影子
- 缺点:中途改值易产生波形异常、周期错乱
模式 2:预装载缓冲(ARPE=1,推荐)
- 写 TIMx->ARR → 只改预装载
- 更新事件(UEV)到来时:
- 预装载 → 影子(一次性拷贝)
- 新值从下一个周期开始生效
更新事件何时发生:
- 计数器溢出 / 下溢(计数到 0 或 ARR)
- 软件触发:TIMx->EGR = TIM_EGR_UG
典型应用场景(PWM 动态调参)
- 电机调速、LED 调光:随时改频率 / 占空比
- 无影子:改 CCR/ARR → 瞬间突变 → 波形毛刺、电机抖响
- 有影子(ARPE=1、OCxPE=1):
- 软件写新值到 TIMx->ARR / TIMx->CCR
- 等待当前周期结束(UEV)
- 影子自动更新 → 下一个周期完美切换
一句话总结
影子寄存器 = 硬件级双缓冲:让你在定时器运行时安全修改参数,保证时序干净、周期完整、多通道同步,是 PWM、电机控制、高精度定时必须理解的底层机制。
事件、中断与触发
概念关系总览
1 | 硬件信号变化(如定时器溢出、EXTI 边沿) |
三者从不同维度描述同一个物理过程:
- 触发:描述”什么条件引起了注意”
- 事件:描述”发生了什么事“
- 中断:描述”CPU 如何响应这件事“
1. 三个核心概念的区别
| 概念 | 是什么 | CPU 参与? | 典型用途 |
|---|---|---|---|
| 事件(Event) | 硬件产生的信号,用于外设间协作 | 可选,看配置 | DMA 传输、外部信号同步 |
| 中断(Interrupt) | CPU 对事件的响应机制 | 是,CPU 必须介入 | 定时器溢出、串口收到数据、外设需要处理 |
| 触发(Trigger) | 引起反应的”条件”,如边沿、电平、软件 | — | 配置外设时的触发沿选择 |
简单来说:事件是一种信号,中断是 CPU 对这个信号的响应,触发是产生信号的机制。
2. 中断(Interrupt)
2.1 什么是中断
中断是一种机制:CPU 正在执行主程序(main loop),某个外设(比如定时器)发生了一个特定事件,这个事件通知 CPU:「我需要你暂停一下,去处理一下我这边的事」。CPU 停下当前工作,跳转到对应的中断服务函数(ISR)去执行,处理完后再回到原来的位置继续执行。
2.2 中断向量表
STM32 有一个中断向量表,每个外设对应一个或多个中断入口地址。当中断发生时,硬件自动根据向量表跳转到对应的 ISR。开发者要做的就是:给每个外设的中断写一个 ISR 函数,并正确配置 NVIC(嵌套向量中断控制器)。
2.3 NVIC 优先级
STM32 用 NVIC 管理所有中断的优先级。优先级分为:
- 抢占优先级(Preemption Priority):高可以打断低的
- 子优先级(Sub Priority):当两个中断同时到达,按子优先级决定先后
数字越小优先级越高。优先级配置直接影响系统实时性,配置错误可能导致低优先级中断被长期阻塞。
2.4 常见中断源
- 定时器更新中断(TIMx_IRQn)
- 外部中断(EXTIx)
- 串口接收/发送中断(USARTx_IRQn)
- ADC 转换完成中断
- DMA 完成/错误中断
3. 事件(Event)
3.1 什么是事件
事件是硬件之间的”内部通知信号”。一个外设可以产生事件,这个事件可以:
- 触发 DMA 传输(不需要 CPU 参与)
- 触发另一个外设的操作(比如定时器输出比较匹配后触发 ADC 启动)
- 也可以触发中断(这实际上是在事件基础上加了一层 CPU 介入)
3.2 事件与中断的关键区别
事件不需要 CPU 介入,是纯硬件的协作机制。例如:
- DMA 触发:串口收到数据后产生事件,事件触发 DMA 把数据从 DR 寄存器搬到你预设的内存里,整个过程 CPU 完全不参与。
- 如果同一个场景用中断实现:串口接收中断触发,CPU 在 ISR 里一个个字节地复制数据 — 这就占用了 CPU 时间和中断嵌套开销。
3.3 EXTI 外部中断/事件线
EXTI(External Interrupt/Event Controller)是一个重要的模块,它管理的实际上是:
- 外部中断:线路上的信号变化触发 CPU 中断
- 外部事件:同一个信号变化触发 DMA 或其他外设
两者共享同一组物理线路(0-15),但通过配置区分开。配置为事件时,信号绕过 CPU,直接传递给其他外设。
3.4 事件的本质:硬件电路
事件不是软件里的”标志位”,而是芯片内部物理布好的硬件通路。
每个外设在硅片上已经布好了线:定时器溢出→内部事件线→连接到 DMA 控制器、EXTI、其他外设。这些线路在你买回来的时候就已经固定了,你只能通过配置寄存器来选择它的走向,但不能改变它的物理存在。
3.5 事件与标志位的关系
| 类型 | 有标志位吗 | 说明 |
|---|---|---|
| 外设→CPU 的事件 | 有 | TIM 的更新标志位在 SR 寄存器,软件可见 |
| 外设→DMA 的事件 | 没有 | DMA 请求信号是内部硬连线,软件看不到 |
| 外设→外设的事件 | 没有 | TIM 触发 ADC 这种内部连接,没有软件标志位 |
事件和标志位是同一事件的两面:硬件在产生事件的同时会在寄存器里设置标志位,但纯硬件传递的事件(如 DMA 请求)没有软件可见的标志位。
3.6 软件触发事件
软件触发不是去”写事件标志位”,而是去写触发寄存器:
1 | // 定时器:手动产生更新事件 |
标志位是”查”的(只读),触发寄存器是”写”的(可写)。 标志位是果,触发寄存器是因。
4. 触发(Trigger)
4.1 什么是触发
触发不是独立的概念,而是指外设检测信号的方式。每种外设在启动时都需要知道「什么情况下我才开始工作」,这个判断条件就是触发条件。
4.2 常见的触发类型
4.2.1 边沿触发(Edge Trigger)
- 上升沿触发:信号从低变高那一刻触发
- 下降沿触发:信号从高变低那一刻触发
- 双边沿触发:上升沿和下降沿都触发
典型应用:按键检测(下降沿触发表示按下)、编码器计数(双边沿都有计数值变化)。
4.2.2 电平触发(Level Trigger)
- 高电平触发:信号维持高电平期间持续工作
- 低电平触发:信号维持低电平期间持续工作
典型应用:某些通信协议需要维持一段电平来表示数据。
4.2.3 软件触发(Software Trigger)
手动通过代码触发某个动作,如:
TIMx->EGR |= TIM_EGR_UG手动产生更新事件ADC1->CR |= ADC_CR_ADSTART手动启动 ADC 转换
4.3 触发源配置示例
以定时器为例:
1 | TIMx->SMCR 寄存器控制触发源: |
以 ADC 为例:
1 | ADC1->CR |= ADC_CR_ADSTART // 软件触发开始转换 |
5. 中断与事件的典型应用场景
| 场景 | 选择中断还是事件 | 原因 |
|---|---|---|
| 串口收到数据,需要 CPU 处理 | 中断 | 数据需要 CPU 分析、决策 |
| 串口收到数据,直接 DMA 搬走 | 事件 | 纯数据搬运,CPU 不需要介入 |
| 定时器计时,到了就做固定动作 | 中断 | 到了时间点需要 CPU 操作 |
| 定时器触发 DMA,自动传输波形数据 | 事件 | 周期性搬运不需要 CPU |
| 按键按下,切换状态 | 中断 | 需要 CPU 判断和处理 |
| 两个外设需要精确同步 | 事件 | 硬件信号比中断更精确,无软件延迟 |
6. 中断处理的注意事项
6.1 ISR 编写原则
- 快进快出:ISR 执行时间要尽量短,不要在 ISR 里做复杂运算、printf、大量数据处理
- 避免重入:STM32 的 ISR 是不能被同一外设打断的(除非配置了嵌套),但可能被更高优先级打断
- 清除标志位:进入 ISR 后通常需要手动清除外设的中断标志位,否则退出后会立即再次进入
6.2 中断使能与禁能
1 | // 使能定时器中断 |
6.3 常见错误
- 在 ISR 里使用阻塞操作(如等待标志位)
- 忘记清除中断标志位导致卡死在 ISR
- 优先级配置错误导致低优先级中断饿死
- 在 main 里和 ISR 里同时操作同一个全局变量(需要关中断或加锁)
7. 总结:三者关系梳理
1 | 触发条件满足(如上升沿到来) |
关键关系:
- 触发 → 事件:触发是条件,事件是触发后的”信号本身”
- 事件 → 中断:事件可以触发中断(需配置),但也可以不触发中断
- 触发 ≠ 中断:中断只是触发的一种响应方式,不是所有触发都会导致中断
理解的核心:把整个过程想象成”报警系统”:
- 触发:报警的条件(烟雾、温度超标、敲门)
- 事件:报警发出的信号(声光、通知)
- 中断:安保人员(CPU)收到信号后的行动
实际开发中,能用事件 + DMA 解决的不用中断,让 CPU 专注核心业务。
