基于 STM32 的 PWM 呼吸灯实战:原理、代码、硬件连接一站式讲解

一、定时器理论知识

PWM介绍

1. 定义

PWM 即脉冲宽度调制(Pulse Width Modulation),是一种通过周期性地开关信号,来模拟连续变化电平的数字控制技术。它的核心是保持信号周期不变,通过改变一个周期内 “高电平” 时间(脉冲宽度)的占比,来控制输出的等效电压或功率。常用于控制电机转速、调节亮度、音频信号合成等场景。

2. 基本原理

PWM(脉冲宽度调制)是通过生成固定周期、仅含高低电平的数字脉冲信号,以调整 “高电平时间占周期的比例(即占空比)” 为核心手段,利用 “平均效应”(如人眼视觉暂留、电机惯性等)让被控设备感知到连续变化的等效电压或功率,最终实现对亮度、转速、输出功率等物理量的精准、高效控制。PWM的频率保持不变,而占空比则在0到100%之间变化:

  • 占空比(Duty Cycle):即高电平占总周期的时间比例。例如,占空比为50%的PWM波表示高电平持续50%的时间,低电平持续50%的时间。
  • 频率(Frequency):PWM波的周期时间,也就是信号变化的频率。

3. 优点及应用范围

优点:

  • 高效能:PWM能有效控制功率传输,并且电源开关工作时几乎没有能量损耗。
  • 精确控制:可以精确地控制功率输出,通过调节占空比来实现精确调节。
  • 热量低:相比传统的线性调节方式,PWM的开关特性能够大大减少因电流流过元件而产生的热量。

应用范围:

  • 电机控制:控制电机转速。
  • 亮度调节:在LED灯光调节中广泛应用。
  • 音频合成:生成模拟音频信号。
  • 电源调节:例如在电源转换中,使用PWM控制输出电压。
  • 马达驱动:如机器人、风扇等设备的调速。

4. 主要参数

  • 频率(Frequency):PWM信号的周期性变化速率,单位为Hz。频率高则调节更细腻,低则响应较慢。
  • 占空比(Duty Cycle):高电平时间与总周期时间的比例,通常以百分比表示。
  • 周期(Period):一个PWM信号从开始到结束的时间总长度,等于1/频率。
  • 电压幅度(Amplitude):高电平时的电压值,一般由驱动电路提供。

5. PWM的产生

PWM信号的产生一般有两种方式:

  • 硬件PWM:由微控制器内部的定时器和计数器自动生成。STM32等微控制器通过配置定时器来输出PWM信号。硬件PWM稳定可靠,效率高,适用于大多数应用。
  • 软件PWM:通过软件控制GPIO引脚的高低电平输出,虽然实现简单,但通常需要较高的计算资源,效率较低,不适合高精度控制。

6. PWM工作原理

PWM的工作原理基于一个固定频率的时钟,通过调节高电平的持续时间(占空比)来实现对功率的调控。信号的周期由时钟产生器设定,信号的高电平和低电平通过占空比控制,常见的PWM波形是矩形波。

  • 占空比:例如占空比50%意味着PWM波在一个周期内,高电平和低电平的时间相等。若占空比为25%,则高电平持续四分之一的周期,低电平占据剩余的部分。

请添加图片描述

7. PWM输出的模式区别

PWM输出有多种工作模式,主要包括:

  • 正常模式(Up Mode):定时器计数从0计数到自动重载值(ARR),然后重载并继续。
  • 向下计数模式(Down Mode):定时器从ARR计数到0,再反向计数。
  • 中心对称模式(Center-aligned Mode):定时器计数到ARR值后会反向计数,这样PWM波形会相对于中心对称,常用于减小噪音和振动。
  • 边沿对齐模式(Edge-aligned Mode):PWM波的上升沿或下降沿与计数器的某些边缘对齐。

8. PWM的计数模式

PWM的计数模式主要有两种:

  • 向上计数(Up-counting):计数器从0开始递增到设定的ARR(Auto-Reload Register)值,当计数器达到ARR值时,它会重新从0开始。

请添加图片描述

  • 向下计数(Down-counting):计数器从ARR开始递减到0,当计数器为0时,会重新从ARR开始。
  • 向上/向下计数(Up/Down-counting):这种模式结合了上升和下降计数,计数器在ARR值和0值之间交替进行计数。此模式下,PWM波形具有更对称的特性。

请添加图片描述

9. PWM相关配置寄存器

在STM32微控制器等基于定时器的PWM生成过程中,涉及到多个寄存器的配置,以下是常见的几个配置寄存器:

(1)捕获/比较模式寄存器(TIMx_CCMR1)
  • 该寄存器用于配置定时器的捕获/比较模式,决定定时器输出的波形类型、PWM的占空比、计数模式等。
  • 主要控制PWM信号的输出模式,比如PWM的极性、输出的比较输出模式等。

请添加图片描述

(2)捕获/比较使能寄存器(TIMx_CCER)
  • 该寄存器用于使能定时器的通道输出。通过设置该寄存器,定时器的捕获/比较输出可以发送到外部引脚。
  • 控制PWM输出信号的开关、极性等。确保PWM信号能够正确地输出到GPIO引脚。

请添加图片描述

(3)捕获/比较寄存器(TIMx_CCR1)
  • 该寄存器用于存储捕获/比较的值,控制PWM信号的高电平持续时间(即占空比)。
  • 通过写入CCR寄存器,可以设置PWM信号的占空比,从而实现对输出信号的调节。

请添加图片描述

总结

PWM(脉冲宽度调制)是一种通过动态调整脉冲信号高电平占空比来精准调控输出功率的核心技术。其核心优势在于能量转换效率高(避免线性调节的功率损耗)、控制精度高(可实现纳秒级占空比调节)、器件发热低(减少无效能耗),因此被广泛应用于电机调速(如无人机电机、家电电机)、LED 亮度控制(如显示屏背光、照明调光)、开关电源稳压等关键领域。

二、工程建立

1. 创建新项目

在STMCubeMX主界面,创建新项目,点击ACCEE TO MCU SELECTOR

请添加图片描述

part name里选择自己的芯片(一般选择直接搜索所需芯片),本文采用STM32F103C8T6点击信息栏中的具体芯片信息选中,点击start project

请添加图片描述

2. RCC配置

System Cor,选择RCC,在右侧弹出的菜单栏中选Crystal/Ceramic Resonator

请添加图片描述

3. SYS配置

选择调试接口,点System Cor,选择SYS。,在右侧弹出的菜单栏中选Serial Wire

请添加图片描述

4. 配置定时器

这里我们选择定时器3和定时器4来实现定时的功位置3,分频系数为71,向上计数模式,计数周期为500,使能自动重载模式。通道1选择:PWM Generation CH1(PWM输出通道1)。
设置分频系数为71,计数周期为500,其它默认。
请添加图片描述

定时器四我们也选择PWM Generation CH1(PWM输出通道1),计数周期根据自己需要进行设置,这里我设置的跟定时器三一样。
请添加图片描述

5. 配置时钟树

如图所示更改配置即可。

请添加图片描述

6. 配置项目设置

如图所示更改配置即可。

请添加图片描述

设置项目名称、路径(不能有中文)、编译器及版本
请添加图片描述

三、代码完善

1. 设置占空比

在main.c中,添加变量,用以存储占空比,且初始值设置为10.

uint16_t duty_num3 = 10;
uint16_t duty_num4 = 10;

请添加图片描述

2. 开启PWM信道

开始TIM3的通道3,输出PWM。
开始TIM4的通道4,输出PWM。
在main函数中添加:

	HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);
	HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_1);

请添加图片描述

3. 具体应用

这里我们设置为每隔50毫秒,占空比加10,如果超过400(也就是PWM周期),又逐渐递减,占空比减10。(即灯会从亮到暗,再从暗到亮逐渐变化)

	    while (1)
  {
    /* USER CODE END WHILE */
		HAL_Delay(50);
		duty_num3 = duty_num3 + 10;
		duty_num4 = duty_num4 + 10;
		if(duty_num3 > 400)
		{
			while(duty_num3!=0)
			{ 	
				HAL_Delay(50);
				duty_num3 = duty_num3 - 10;
		__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_1,duty_num3);			 
			}
			HAL_Delay(50);
			duty_num3 = 0;
		}
		__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_1,duty_num3);
			if(duty_num4 > 450)
		{
			while(duty_num4!=0)
			{ 	
				HAL_Delay(50);	
			    duty_num4 = duty_num4 - 10;
		__HAL_TIM_SetCompare(&htim4,TIM_CHANNEL_1,duty_num4);
			}
			HAL_Delay(50);
			duty_num4 = 0;
		}
		__HAL_TIM_SetCompare(&htim4,TIM_CHANNEL_1,duty_num4);
    /* USER CODE BEGIN 3 */
  }

请添加图片描述

四、硬件连接

根据查询数据手册可发现定时器3,4的一通道分别对应引脚PA6 PB6,然后题目要求还需要直接驱动PC13(最小开发板上已焊接的LED(固定接在 PC13 GPIO端口)),故而我们将对应PWM波作为输入,连接其对应引脚即可实现所需完成功能。

TIM4复用功能重映像:
在这里插入图片描述
TIM3复用功能重映像:
在这里插入图片描述

3V3 —> 3V3
GND —> GND
RXD —> A9
TXD —> A10
LED灯短脚 —> A6
LED灯长脚 —> 3V3
PB6 —> PC13

硬件连接图:

请添加图片描述

五、结果展示

可以看到两个灯有亮到灭,再由灭到亮
在这里插入图片描述

六、心得体会

通过本次 STM32 使用 PWM 制作呼吸灯的实践,我对 PWM 技术的认知从理论走向了实际。此前仅知道 PWM 通过调整占空比控制输出,而在开发中看到 LED 按设定平滑渐变时,才真正理解占空比增减是对 PWM 信号高电平时间的调控,进而改变等效电流实现亮度变化,也切实感受到 PWM 高效低耗、控制精确的优势,明白其为何能广泛应用于电机控制、电源调节等领域。

定时器配置是本次开发的核心,让我深入掌握了 STM32 定时器的工作机制。配置 TIM3 和 TIM4 时,从设定分频系数 71、计数周期 500,到选择向上计数模式、使能自动重载,每个参数都影响 PWM 信号质量。最初因对计数周期与占空比匹配理解不深导致亮度断层,调试后才明确三者协同逻辑,比如将占空比初始值设为 10,每 50 毫秒调整 10 个单位,以特定阈值实现循环,最终达成自然渐变。

软硬件协同的过程,让我积累了调试经验与工程思维。硬件连接时,依据数据手册确认 TIM3 通道 1 对应 PA6、TIM4 通道 1 对应 PB6,再连接 LED,这让我意识到引脚对应关系的重要性 —— 最初误接 LED 正负极导致灯不亮,排查后才明确正确接线方式,打破了仅关注代码的局限。

代码完善环节,通过HAL_TIM_PWM_Start开启 PWM 通道,用__HAL_TIM_SetCompare调整占空比,借HAL_Delay控制渐变速度,我理解了软件逻辑如何驱动硬件。期间曾因while循环中延时函数嵌套错误导致亮度突变,最终通过梳理代码、验证参数解决问题。

此次开发不仅实现了呼吸灯功能,更让我对嵌入式开发本质有了新认知。呼吸灯的平滑渐变,依赖定时器计时、寄存器配置和软硬件协同。未来面对类似项目,我会更注重前期方案设计,保持严谨调试态度,也会将所学应用到更多场景,深化对嵌入式技术的理解。

七、仓库地址

https://gitee.com/zhang-kaikaikaikai/study-timer-and-pwm.git

八、参考博客

http://www.mcublog.cn/stm32/2021_01/stm32cubemx-pwm-huxideng/
https://blog.csdn.net/weixin_64559251/article/details/127581276

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐