09-TIM高级应用:PWM与输入捕获.md 4.8 KB


tags: [source-summary] type: source source: "尚硅谷嵌入式技术之STM32单片机(进阶篇)V1.0.1 — 第1章:PWM + 配套代码20~27" author: "尚硅谷研究院" date: 2026-07-15

created: 2026-07-15

TIM高级应用:PWM与输入捕获

用生活理解:PWM 就像快速开关灯——如果你每秒开关 1000 次,眼睛就感觉灯光变暗了。开的时间比例(占空比)越大就越亮。呼吸灯就是占空比从 0% 逐渐变到 100% 再回来,像人呼吸一样平滑。


PWM 原理

PWM = Pulse Width Modulation(脉冲宽度调制),通过调节脉冲的宽度(占空比)来控制平均电压。

基本参数

参数 公式 示例(50%占空比, 1KHz)
频率 Freq = CK_PSC / (PSC+1) / (ARR+1) 72MHz/72/1000 = 1KHz
占空比 Duty = CCR / (ARR+1) × 100% 500/1000 = 50%
分辨率 Resolution = 1 / (ARR+1) × 100% 1/1000 = 0.1%
  • PSC(预分频器):决定计数时钟频率
  • ARR(自动重装载值):决定 PWM 周期
  • CCR(捕获/比较值):决定 PWM 占空比

输出比较模式

模式 说明 用途
PWM 模式 1 向上计数时 CNT<CCR 输出有效电平 常用
PWM 模式 2 向上计数时 CNT<CCR 输出无效电平 互补

通常有效电平 = 高电平(由 CCERP 决定极性)。

PWM 波形生成过程

CNT 计数: 0__1__2__...__CCR__...__ARR__0__1__...
输出(模1): 高          低             高
              ← 占空比 → ← 剩余 →
              ←—————— 周期(ARR+1) ——————→

实验:呼吸灯

软件设计(寄存器版)

文件:stm32_base/20_tim_led_breathe_register/Hardware/TIM5/tim5.c

#include "tim5.h"

// TIM5 初始化:配置PWM输出到PA0(LED1)
void TIM5_Init(void)
{
    // 1. 时钟
    RCC->APB1ENR |= RCC_APB1ENR_TIM5EN;   // TIM5时钟

    // 2. 配置PA0为复用功能推挽输出
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
    GPIOA->CRL &= ~GPIO_CRL_CNF0;         // CNF=10(复用推挽)
    GPIOA->CRL |= GPIO_CRL_CNF0_1;
    GPIOA->CRL |= GPIO_CRL_MODE0;          // MODE=11(50MHz)
    // TIM5_CH1 输出到 PA0(通过AFIO重映射)

    // 3. 配置TIM5时基
    TIM5->PSC = 72 - 1;                    // 72MHz/72 = 1MHz
    TIM5->ARR = 1000 - 1;                  // 1MHz/1000 = 1KHz PWM

    // 4. 配置输出比较模式
    TIM5->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2;  // PWM模式1
    TIM5->CCMR1 |= TIM_CCMR1_OC1PE;        // 预装载使能
    TIM5->CCER |= TIM_CCER_CC1E;           // CH1输出使能

    // 5. 初始占空比0
    TIM5->CCR1 = 0;
}

void TIM5_Start(void)
{
    TIM5->CR1 |= TIM_CR1_CEN;              // 启动定时器
}

// 设置占空比(0~99)
void TIM5_SetDutyCycle(uint8_t duty)
{
    TIM5->CCR1 = duty * 10;                // CCR1 = 0~990
}

文件:stm32_base/20_tim_led_breathe_register/User/main.c

#include "tim5.h"

int main(void)
{
    TIM5_Init();
    TIM5_Start();

    uint8_t duty = 0;
    uint8_t dir = 0;    // 0=增加, 1=减小
    uint8_t step = 1;

    while (1)
    {
        if (dir == 0) {
            duty += step;
            if (duty >= 99) dir = 1;   // 到最大转向减小
        } else {
            duty -= step;
            if (duty <= 0)  dir = 0;   // 到最小转向增加
        }
        TIM5_SetDutyCycle(duty);        // 设置新占空比
        Delay_ms(10);                   // 每10ms改变一次
    }
}

实验:输入捕获测频率

TIM 的输入捕获可以测量外部信号的脉宽或频率。

配置流程

GPIO输入 → TIM_CHx引脚 → 输入滤波器 → 边沿检测 → 捕获CCR

测频率原理

  1. 配置 CHx 捕获上升沿
  2. 第一次捕获到上升沿 → 记录 CCR1 值
  3. 第二次捕获到上升沿 → 记录 CCR2 值
  4. 频率 = CK_CNT / (CCR2 - CCR1)

参考:参考手册 §14.3(输入捕获模式)


核心速查表

功能 配置方法
PWM模式1 CCMR1.OC1M = 110(PWM模式1)
PWM使能输出 CCER.CC1E = 1
预装载使能 CCMR1.OC1PE = 1
ARPE使能 CR1.ARPE = 1(ARR影子寄存器)
极性反转 CCER.CC1P = 1(低电平有效)
更新占空比 CCR1 值(0~ARR)

常见问题与避坑

  1. PWM 无输出 → 检查 GPIO 模式(复用推挽)、TIM CH 输出是否使能(CCER.CCxE)
  2. 占空比 0 时仍有微弱电平 → 检查 CCR1=0 是否真为低电平(取决于极性配置)
  3. PWM 频率不对 → APB1 定时器时钟 = APB1×2(如果 APB1 预分频≠1)
  4. 输入捕获值不准确 → 检查输入滤波器和边沿极性配置
  5. CCR 更新不及时 → 检查 ARPE 影子寄存器是否使能(建议使能,防止中途改变ARR/CCR引起波形异常)