STM32CubeMX+HAL+Keil5 PWM呼吸灯

文章目录

  • [1 准备材料](#1 准备材料)
  • [2 知识讲解](#2 知识讲解)
    • [2.1 PWM 是什么](#2.1 PWM 是什么)
    • [2.2 STM32 定时器产生 PWM 需要的四个关键参数](#2.2 STM32 定时器产生 PWM 需要的四个关键参数)
    • [2.3 必记公式](#2.3 必记公式)
    • [2.4 CNT 与 CCR 比较时的输出电平规则](#2.4 CNT 与 CCR 比较时的输出电平规则)
  • [3 实验](#3 实验)

1 准备材料

2 知识讲解

2.1 PWM 是什么

PWM(脉冲宽度调制) 是一种通过快速开关信号,并用 每个周期内高电平的时间比例 来控制平均输出电压(或亮度、速度等)的技术。

  • 核心思想:开关速度快到人眼/负载反应不过来,只能感受到平均值。
  • 两个关键参数
    • 频率 :每秒开关的次数(单位 Hz)。频率越高,波动越小。
      • 频率(Hz)= 1 / 周期(秒)
      • 例如 1000 Hz → 周期 = 1/1000 秒 = 1 ms。
      • 例如 1 Hz → 周期 = 1 秒 = 1000 ms。
    • 占空比:一个周期内高电平时间占整个周期的百分比。

举个 LED 例子

频率 = 1000 Hz(每秒开关 1000 次),对应周期为1ms,占空比 = 50% → 每个周期内亮 0.5 ms、灭 0.5 ms,人眼看到半亮。

占空比越大,LED 越亮。

2.2 STM32 定时器产生 PWM 需要的四个关键参数

在 STM32 的通用定时器(如 TIM3)中,要产生 PWM 波形,需要配置 4 个数值

参数 全称 作用 补充说明
PSC Prescaler(预分频器) 控制每数一步的时间(计数时钟频率) PSC 越大,每步时间越长,频率越低
ARR Auto Reload Register(自动重装载值) 一个 PWM 周期内计数多少步 步数 = ARR+1,决定占空比分母
CCR Capture/Compare Register(捕获/比较寄存器) 决定占空比 与 CNT 比较,决定输出有效电平的步数(极性 High 时有效电平为高电平)
占空比 Duty Cycle 实际效果:高电平时间 / 周期时间 CCR / (ARR+1)

注意:ARR 和 CCR 都是寄存器 ,通过 CubeMX 设置 ARR,通过 __HAL_TIM_SET_COMPARE 设置 CCR。

2.3 必记公式

  • PWM 频率 = 定时器时钟源频率 ÷ ( 预分频器 PSC + 1) ÷ ( 自动重装载值 ARR + 1)
  • 占空比 = CCR ÷ (ARR + 1)

2.4 CNT 与 CCR 比较时的输出电平规则

在 STM32 定时器的 PWM 模式中,极性 仅仅反转有效电平的定义:

CNT为定时器计数器值

极性设置 CNT< CCR CNT ≥ CCR
High(高电平有效) 输出高电平 输出低电平
Low(低电平有效) 输出低电平 输出高电平

本次实验中使用极性 High,因此 CCR 越大,高电平时间越长,LED 越亮。


3 实验

3.1 低频 PWM 闪烁观察

目的:把 PWM 频率降低到人眼能分辨的范围(< 10 Hz),亲眼看到LED 在一个周期内"先亮后灭"(或"先灭后亮")的完整过程,从而直观理解占空比 = 亮的时间 / 周期 的含义。

本次以1Hz为例

PWM 频率 = 定时器时钟源频率 ÷ ( 预分频器 PSC + 1) ÷ ( 自动重装载值 ARR + 1)

PSC = 35999 → PSC+1 = 36000

ARR = 1999 → ARR+1 = 2000

频率 = 72,000,000 ÷ 36000 ÷ 2000 = 1 Hz

周期 = 1 秒 = 1000 毫秒

系统时钟(定时器时钟源) 72MHz 1M = 1000千
PSC 35999
ARR 1999

占空比 = CCR ÷ (ARR + 1)

__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 1000); 这个函数的作用是:设置定时器 TIM3 的通道 1 的比较值(也就是占空比的控制值)为 1000 其中占空比比例为 1000 /(ARR+1)=1000 / (1999+1)= 50%

即可以肉眼观察到led亮0.5s,灭0.5s的过程

可以尝试修改 CCR 为 500(25% 占空比)或 1500(75% 占空比),观察亮灭时间的变化。


3.2 PWM控制呼吸灯

3.2.1 为PWM选择合适引脚

第一步:查看数据手册中的引脚定义表

关键点 :在 "默认复用功能" 列中,如果某个引脚标注了 TIMx_CHy(比如 TIM3_CH1),就表示它可以作为定时器 TIM3 的通道 y 输出 PWM。

第二步:理解命名规则
  • TIMx:定时器编号,如 TIM1、TIM2、TIM3、TIM4 等。
  • CHy:通道编号,每个定时器通常有 1~4 个通道(CH1~CH4)。

例如 TIM3_CH1 表示:定时器 3 的通道 1。

第三步:确认定时器时钟来源

不同的定时器挂在不同的总线上:

  • TIM2、TIM3、TIM4 挂在 APB1 总线上
  • TIM1、TIM8 挂在 APB2 总线上

本次我们使用引脚PA6演示

3.2.2 CubeMX 配置

  1. 新建工程:打开 STM32CubeMX,选择你的 MCU 型号(如 STM32F103C8T6)

  2. 配置调试接口:进入 Pinout & Configuration 视图,点击 SYS,Debug 选择 Serial Wire(避免 JTAG 引脚冲突影响调试)

  3. 配置时钟源:点击 RCC,High Speed Clock (HSE) 选择 Crystal/Ceramic Resonator

  4. 配置时钟树:将 HCLK 设为 72MHz(STM32F103 最高主频),系统会自动计算各总线分频

  5. 配置 TIM3 PWM 输出

    • 在 Pinout 视图中找到 PA6 引脚,点击选择 TIM3_CH1
    • 点击 TIM3,勾选 Channel 1 为 PWM Generation CH1
    • Clock Source 选择 Internal Clock
    • Parameter Settings 中配置:
      • Prescaler:71(预分频值)
      • Counter Mode:Up(向上计数)
      • Counter Period:999(自动重装载值 ARR)
      • Auto-reload preload:Enable
    • PWM Generation Channel 1 中配置:
      • Mode:PWM mode 1
      • Pulse:0(初始占空比)
      • CH Polarity:High(高电平有效)

    PWM 频率计算公式:频率 = 72MHz / (Prescaler+1) / (Counter Period+1) = 72000000 / 72 / 1000 = 1000Hz

  6. 配置 GPIO :CubeMX 会自动将 PA6 设为复用推挽输出模式,无需手动调整

  7. 生成代码

    • Project Manager 中设置工程名、保存路径、Toolchain/IDE(如 MDK-ARM)
    • 勾选 "Generate peripheral initialization as a pair of '.c/.h' files"
    • 点击 GENERATE CODE

3.2.3 编写代码

在生成的工程中,找到 main.c,在 /* USER CODE BEGIN *//* USER CODE END */ 注释块之间添加代码,注意不要写在注释块外面,否则重新生成代码时会被覆盖。

c 复制代码
/* USER CODE BEGIN 0 */
uint16_t dutyCycle = 0;      // 占空比变量
uint8_t direction = 1;       // 1=渐亮, 0=渐暗
/* USER CODE END 0 */
c 复制代码
/* USER CODE BEGIN 2 */
// 启动 TIM3 通道 1 的 PWM 输出
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
/* USER CODE END 2 */
c 复制代码
/* USER CODE BEGIN 3 */
while (1)
{
    // 逐渐改变占空比,实现呼吸效果
    if (direction == 1)      // 渐亮
    {
        dutyCycle += 5;
        if (dutyCycle >= 990)  // 到达最亮后切换方向
        {
            dutyCycle = 990;
            direction = 0;
        }
    }
    else                     // 渐暗
    {
        dutyCycle -= 5;
        if (dutyCycle <= 10)   // 到达最暗后切换方向
        {
            dutyCycle = 10;
            direction = 1;
        }
    }
    
    // 设置比较寄存器值,改变占空比
    __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, dutyCycle);
    
    HAL_Delay(7);           // 控制呼吸速度
}
/* USER CODE END 3 */

代码说明:定时器的自动重装载值 ARR 设置为 999,因此 dutyCycle 取值范围为 0 到 999,对应占空比 0% 到 100%。这里设置 dutyCycle 范围为 10 到 990,保留一定的亮暗余量,避免 LED 完全熄灭或过亮。

3.2.4 硬件连接

组件 连接点
STM32 PA6 引脚 限流电阻一端
限流电阻(220Ω~1kΩ)另一端 LED 正极(阳极)
LED 负极(阴极) GND

最终效果如下:

组件 连接点
STM32 PA6 引脚 限流电阻一端
限流电阻(220Ω~1kΩ)另一端 LED 正极(阳极)
LED 负极(阴极) GND

最终效果如下:

相关推荐
Ww.xh2 小时前
STM32嵌入AI模型全流程指南
stm32
Ww.xh2 小时前
STM32嵌入AI模型实战指南
stm32
傻童:CPU3 小时前
板级支持包的构建
stm32
爱编码的小八嘎3 小时前
C语言完美演绎7-7
c语言
来日可期13143 小时前
C/C++ 反常识记录(1)—— 那些容易踩坑的语法细节
c语言·开发语言·c++
进击的小头3 小时前
第7篇:嵌入式芯片运算核心:ALU_MAC_FPU的工作原理与性能差异
单片机·嵌入式硬件
计算机安禾3 小时前
【数据结构与算法】第41篇:图论(五):拓扑排序与关键路径
c语言·数据结构·c++·算法·图论·visual studio
振南的单片机世界3 小时前
RS485组网:一问一答,多个从机不打架
单片机·嵌入式硬件
itman3013 小时前
Windows环境下编译运行C语言程序的方法及工具选择
c语言·visualstudio·mingw·编译器·windows环境