PWM 与比较匹配中断
比较匹配(Compare Match)是 PWM、输出比较、输入捕获共用的底层机制。本页以比较匹配为轴,串起 PWM 原理、互补输出与死区、中心对齐双比较点,以及可观测现象与跨平台移植。
PWM 原理
固定频率、变占空比的方波,用占空比编码模拟量(功率、亮度、位置)。
| 参数 | 公式 | 说明 |
|---|---|---|
| 频率 | PSC 预分频,ARR 自动重载 | |
| 占空比 | 边沿对齐(向上计数) | |
| 分辨率 | 位 | ARR=65535 → 16 位 |
| 等效均值 | 加低通滤波即 DAC |
PWM 模式(TIM_OCMode):模式 1 为 CNT < CCR → 有效电平,模式 2 反相。计数方式分边沿对齐(0→ARR 归零)与中心对齐(0→ARR→0),后者谐波更小、适合对称驱动。
比较匹配机制(CMP)
自由运行的计数器 CNT 与比较寄存器 CMP/CCR 相等时,硬件产生比较匹配事件,可触发中断或翻转输出。
计数器值 CNT
│
▼
┌──────────────────────────────────────────┐
│ 0 ──────────────── CMP ──────── ARR │
│ ↑ │
│ 比较匹配,触发中断/翻转输出 │
└──────────────────────────────────────────┘
- ARR(Auto-Reload Register):周期,CNT 到 ARR 归零(或反向)。
- CCR/CMP(Capture/Compare Register):比较值,到达即触发事件/中断,每通道独立。
- 输出比较:比较匹配时按配置翻转/置位/清零引脚,这就是 PWM 电平翻转点。
互补 PWM 与死区
高级定时器(TIM1/TIM8)每通道提供 CHx 与 CHxN 两个互补输出,用于半桥/全桥/逆变器驱动。
互补:半桥上下两管(高侧 Q1 / 低侧 Q2)轮流导通。若切换瞬间两管同时导通 → 直通短路(shoot-through),电源对地大电流,烧管/跳闸。互补输出保证逻辑上同一时刻只有一管为有效电平。
死区:MOSFET 关断有延时,即使互补逻辑正确,切换瞬间仍可能短暂交叠导通。因此在一管导通前,强制插入一段两管都关断的时间,即死区(Dead Time)。
CHx ────────┐ ┌──────── 高侧
└────────┘
CHxN ────┐ ┌──────────── 低侧(反相)
└────────┘
│←死区→│ 切换瞬间两管都关断
死区时间由 BDTR.DTG 位域设置,粒度取决于 CR1.CKD 时钟分频;极性由 CCER.CCxP/CCxNP 决定,配合高低侧驱动芯片(如 IR2104)选择。
| 死区 | 后果 |
|---|---|
| 太小 / 无 | 上下管交叠导通 → 直通电流尖峰、发热、炸管 |
| 太大 | 有效占空比被吃掉 → 输出电压/转矩下降、波形畸变(死区效应)、谐波噪声 |
典型取 0.5~2 µs,按功率管关断时间 + 驱动电路延时留裕量。
中心对齐双 CMP 中断
四开关 Buck-Boost 等功率变换器采用**中心对齐(上下计数)**模式,每通道两个比较寄存器:
struct PWMDutyVariable
{
bool buckBoostMode = false;
float dutyA = 0.0f;
float dutyB = 0.0f;
uint16_t ACMP1 = 8000; // 通道A — 上升沿阶段触发
uint16_t ACMP3 = 8000; // 通道A — 下降沿阶段触发
uint16_t BCMP1 = 8000; // 通道B — 上升沿阶段触发
uint16_t BCMP3 = 8000; // 通道B — 下降沿阶段触发
};- CNT 从 0 升到 ARR 再降回 0,构成一个完整 PWM 周期。
- CMP1:上升过程命中 → 前半周期事件(高电平开始前)。
- CMP3:下降过程命中 → 后半周期事件(高电平结束后)。
- 每周期共触发 2 次 CMP 中断(上升 + 下降各一次)。
设 ARR = 8000(对应 100% 周期)、占空比 :
对称模式 CMP1 == CMP3;非对称模式两者不同,可产生相移或不对称波形。
| 中断点 | 触发时机 | 典型操作 |
|---|---|---|
| CMP1(上升沿) | 高电平开始前 | 更新下周期占空比、触发 ADC 采样 |
| CMP3(下降沿) | 高电平结束后 | 读 ADC 结果、跑控制算法 |
| OVF(ARR 顶点) | 计数器到峰 | 同步多路 PWM、周期保护检测 |
必须在 OVF 或 CMP 中断内更新 CMP,避免计数器运行中途写入导致毛刺:
void PWM_OVF_IRQHandler(void)
{
float dutyA = ControlLoop_GetDutyA();
float dutyB = ControlLoop_GetDutyB();
uint16_t cmpA = (uint16_t)(ARR * (1.0f - dutyA));
uint16_t cmpB = (uint16_t)(ARR * (1.0f - dutyB));
PWM_SetCMP(CH_A, CMP1, cmpA);
PWM_SetCMP(CH_A, CMP3, cmpA);
PWM_SetCMP(CH_B, CMP1, cmpB);
PWM_SetCMP(CH_B, CMP3, cmpB);
}可观测现象
| 现象 | 观测手段 | 对应原因 |
|---|---|---|
| CHx/CHxN 反相、边沿间有平台 | 示波器双通道 | 死区在起作用 |
| 死区处波形抖动/毛刺 | 示波器放大 | 驱动芯片延时、开关噪声 |
| 电流尖峰、发热、炸管 | 电流探头/热像 | 死区过小或无死区 → 直通 |
| 输出电压/转矩上不去 | 万用表/测功 | 死区过大,有效占空比损失 |
| 输出畸变、低频纹波 | 示波器 FFT | 死区效应引入谐波 |
| 每周期 2 次中断 | 逻辑分析仪/示波器 | 中心对齐双比较点 |