4. PWM输出与呼吸灯

任务目标

使用STM32定时器的PWM模式,通过调节占空比控制LED亮度,实现呼吸灯效果(亮度从暗到亮再回到暗的周期性变化)。

硬件与依赖

  • STM32F103系列开发板(以C8T6为例)
  • 板载LED连接在PC13(或PB1,根据实际板卡调整)
  • 使用定时器TIM3的通道2(PA7)输出PWM,或使用TIM2通道1(PA0)——本案例以TIM3_CH2(PA7)为例
  • 标准外设库(SPL)或HAL库均可,本实现使用寄存器方式,无需额外库依赖

核心实现

呼吸灯的关键在于PWM频率(约1kHz以上避免闪烁)和占空比按正弦或三角波规律变化。以下代码使用TIM3_CH2输出PWM,主循环中通过软件延时改变比较寄存器值,实现约2秒周期的呼吸效果。

// PWM呼吸灯 - STM32F103寄存器版
#include "stm32f10x.h"

void TIM3_PWM_Init(void) {
    // 1. 使能时钟:GPIOA和TIM3
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
    RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
    
    // 2. PA7配置为复用推挽输出,50MHz
    GPIOA->CRL &= ~(0xF << 28);   // 清除CNF7和MODE7
    GPIOA->CRL |= (0xB << 28);    // CNF=10(复用推挽), MODE=11(50MHz)
    
    // 3. TIM3时钟 = 72MHz,分频72 → 1MHz计数频率
    TIM3->PSC = 72 - 1;           // 预分频
    TIM3->ARR = 1000 - 1;         // 自动重载,PWM频率 = 1MHz/1000 = 1kHz
    
    // 4. 通道2配置为PWM模式1,输出比较
    TIM3->CCMR1 |= TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2;  // PWM模式1 (110)
    TIM3->CCMR1 |= TIM_CCMR1_OC2PE;                      // 输出比较预装载使能
    TIM3->CCER |= TIM_CCER_CC2E;                         // 使能通道2输出
    
    // 5. 初始占空比0%
    TIM3->CCR2 = 0;
    
    // 6. 使能自动重载预装载,启动定时器
    TIM3->CR1 |= TIM_CR1_ARPE;
    TIM3->CR1 |= TIM_CR1_CEN;
}

// 简易延时(约1ms @72MHz,不精确但足够呼吸灯使用)
void Delay_ms(uint32_t ms) {
    for (uint32_t i = 0; i < ms * 4000; i++) {
        __NOP();
    }
}

int main(void) {
    TIM3_PWM_Init();
    
    uint16_t duty = 0;
    int8_t direction = 1;  // 1=变亮, -1=变暗
    
    while (1) {
        TIM3->CCR2 = duty;   // 更新占空比
        
        // 三角波变化:0→1000→0,步进5,每步延时2ms → 周期约0.8s
        duty += direction * 5;
        if (duty >= 1000) {
            duty = 1000;
            direction = -1;
        } else if (duty == 0) {
            direction = 1;
        }
        
        Delay_ms(2);
    }
}

编译与烧录

  1. 使用Keil MDK或STM32CubeIDE创建空工程,芯片选择STM32F103C8。
  2. 将上述代码复制到main.c中,替换默认生成的main函数。
  3. 编译工程,通过ST-Link或串口ISP烧录生成的hex文件。

验证方法

  • 硬件连接:将PA7引脚通过限流电阻(约100Ω)连接LED阳极,阴极接地。若使用板载LED(如PC13),需修改代码将PWM输出到对应引脚,或直接外接LED到PA7。
  • 观察现象:上电后LED亮度应从暗逐渐变亮,再逐渐变暗,循环往复,周期约0.8秒。
  • 示波器验证(可选):将示波器探头接PA7,应看到频率约1kHz、占空比周期性变化的方波信号。
  • 判定通过:LED呈现平滑的呼吸效果,无肉眼可见闪烁,亮度变化连续。

关键说明

  • PWM频率由 72MHz / (PSC+1) / (ARR+1) 决定,本配置为1kHz,高于人眼闪烁感知阈值。
  • 呼吸周期由步进值和延时共同决定:1000/5 * 2ms * 2 = 800ms。调整步进或延时即可改变呼吸速度。
  • 若LED接在PA7但亮度变化不明显,检查限流电阻是否过大(建议100~330Ω),或确认TIM3_CH2复用映射是否正确(默认PA7无需重映射)。
PWM呼吸灯信号示意 t 占空比 占空比包络(三角波) PWM脉冲宽度随包络变化 暗 亮 暗