跳到主要内容

【PWM】彩色呼吸灯

下载例程代码下载代码

注意

请一定按照 例程使用方法 🔗 导入例程,否则下载的可能不是例程而是其他工程。

PWM 简介

PWM 波形

PWM 波形是一种方波信号,是高/低电平不断切换的结果,其波形如图所示,这是 3 种占空比不同的波形:

PWM波形

PWM 的几个关键参数为:

  • 频率(Frequency):即高低电平切换的速度,切换的速度越快则频率越高,1000Hz 的 PWM 波意味着 1 秒钟有 1000 个脉冲

  • 占空比(Duty Cycle):即每个周期内,高电平所占的宽度

    • 例如图中 50% duty cycle,即高/低电平的时间各占 50%

    • 图中的75% duty cycle高电平占 75%,低电平占 25%

    • 图中的25% duty cycle高电平占 25%,低电平占 75%

PWM 实现呼吸灯

如果使用 PWM 信号控制 LED 的亮/灭,那么占空比越高,灯点亮的时间就越长

因此,当 PWM频率足够高,以至于人眼无法分辨时,PWM 的占空比就可以控制 LED 灯的亮度

也就是说,占空比越高,LED 看起来越亮

此例程使用 PWM 来驱动学习板上的 RGB LED,实现呼吸灯效果

如何使用例程

下载程序,即可看到效果

程序效果

  • 烧录例程后,可以看到 RGB 灯渐变效果
  • 修改一下例程可以实现不同颜色、不同速度的呼吸灯效果
演示

例程讲解

下面介绍了如何自己实现该例程的功能

1、工程配置

  • 开启外部晶振:在 Pinout&Configuration -> System Core -> RCC 页面,将 High Speed Clock (HSE) 配置为 Crystal/Ceramic Resonator
配置时钟源
  • 配置时钟频率:在 Clock Configuration 页面,将 PLL Source 选择为 HSE,将 System Clock Mux 选择为 PLLCLK,然后在 HCLK (MHz) 输入 72 并回车,将 HCLK 频率配置为 72 MHz
时钟配置
  • 分配引脚:在 Pinout&Configuration 页面,将 PA6、PA7、PB0 分别配置为 TIM3_CH1、TIM3_CH2、TIM3_CH3

  • 配置 TIM3:在 Pinout&Configuration -> Timers -> TIM3

    • 勾选 Internal Clock,开启 TIM3 的内部时钟源

    • Configuration -> Mode,将 Channel1、Channel2、Channel3 分别配置为 PWM Generation CH1、2、3

    • Configuration -> Parameter Settings -> Counter Settings,将 Prescaler 配置为 72-1,将 Counter Period 配置为 100-1,使 PWM 频率为 10kHz

      PWM 频率 = 72MHz ÷ 72 ÷ 100 = 10 kHz

2、代码

  • 启动 PWM 输出

    //启动3个通道的PWM输出
    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);
    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3);
  • 在 while 循环中逐渐改变占空比

    • __HAL_TIM_SET_COMPARE 可以设置 PWM 的占空比,范围 0 - 99

      注意:占空比必须小于前面配置的Counter Period,例程中配置为 100-1,即占空比可调范围是 0 - 99

    • 先从 0 逐渐增加到 99,亮度逐渐提高

    • 再从 99 逐渐减小到 0,亮度逐渐降低

    while (1) {
    // PWM通道CH1-3分别对应三个颜色,下面示例三个颜色一起呼吸灯
    // 0-99为占空比,0为最小亮度,99为最大亮度
    // 每7ms调整一次占空比,从0逐渐增加到99
    for (int period = 0; period < 100; period++) {
    __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, period);
    __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, period);
    __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, period);
    HAL_Delay(7);
    }
    // 从99逐渐减小到0
    for (int period = 99; period >= 0; period--) {
    __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, period);
    __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, period);
    __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, period);
    HAL_Delay(7);
    }
    HAL_Delay(100);
    }