hal库利用PWM制作呼吸灯

本文介绍如何使用STM32的TIM3和TIM4定时器输出PWM波形,通过改变占空比实现LED呼吸灯效果。包括硬件配置、软件编程及实验现象等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实验目的

使用TIM3和TIM4,分别输出一个PWM波形,PWM的占空比随时间变化,去驱动你外接的一个LED以及最小开发板上已焊接的LED(固定接在 PC13 GPIO端口),实现2个 LED呼吸灯的效果。

实验材料

硬件

  • STM32F103C8T6最小开发板
  • CH340模块
  • LED灯一个
  • 杜邦线若干
  • 面包板一块

软件

  • KEIL5
  • FLYMCU

实验原理

呼吸灯,就是指灯光设备的亮度随着时间由暗到亮逐渐增强,再由亮到暗逐渐衰减, 很有节奏感地一起一伏,就像是在呼吸一样。要控制 LED 灯达到呼吸灯的效果,实际上就是要控制 LED 灯的亮度拟合呼吸特性曲线。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KazyWMNN-1667782846011)(E:\学习资料\嵌入式作业\12_hal_pwm\5.png)]

因为引脚要么输出1,要么0,没有“慢慢升高或降低”这一说法,因此要实现呼吸灯,需要使用到PWM。所谓PWM,就是通过对一系列脉冲的宽度进行调制,来等效地获得所需要波形(含形状和幅值)。

以正弦信号为例,通过一系列不同的脉冲宽度的信号,可以等效地得到正弦信号:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OwC6hSLa-1667782846011)(E:\学习资料\嵌入式作业\12_hal_pwm\6.png)]

对于呼吸特性曲线,也一样可以用这种方法拟合,让LED灯阴极引脚输出呼吸特性曲线的等效脉冲信号波形,就可以实现呼吸灯。

项目制作

CubeMX初始化

1、时钟配置

在这里插入图片描述
在这里插入图片描述
按上图依次配置,将PCLK1配置为36MHz。

2、定时器配置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cp2qXP2n-1667782846013)(E:\学习资料\嵌入式作业\12_hal_pwm\3.png)]

因为实验要求控制两个LED,因此我使用TIM3与TIM4进行输出PWM。上图以配置TIM3介绍过程。

点击TIM3,再勾选内部时钟,并选择通道2输出PWM。这里也可以选用其他通道,不过这会导致PWM输出的GPIO口不同,要注意一下。

再选择分频为71,计数为500。这里的计数不用写太大。

配置一下项目路径与名称,以及使用的ide,生成项目。

代码实现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UbgCNWJm-1667782846013)(E:\学习资料\嵌入式作业\12_hal_pwm\4.png)]

源码在这里:

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_TIM3_Init();
  MX_TIM4_Init();
	HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);
	HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_2);
	uint16_t status = 0;
	int16_t duty_num = 0;
  while (1)
  {
		HAL_Delay(50);
		if (status == 0){
			duty_num = duty_num + 17;
			if(duty_num > 500)
			{
				status = 1;
				duty_num = 493;
			}
		}
		else{
			duty_num = duty_num - 17;
			if(duty_num < 17)
			{
				status = 0;
				duty_num = 17;
			}
		}
		
		__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_2,duty_num);
		__HAL_TIM_SetCompare(&htim4,TIM_CHANNEL_2,duty_num);

  }

}

呼吸灯有两个过程,一个过程是慢慢亮灯,一个是慢慢灭灯。一个周期中低电平占比越多,灯就越亮。这里变量duty_num用来设置一个周期中高电平的时间。我的定时器一个周期计数个数为500,因此duty_num的范围就是0-500之间。

想要慢慢变亮,就慢慢降低高电平所占一个周期的时间,即每隔一段时间降低duty_num的值;想要慢慢变暗,就慢慢提升高电平所占一个周期的时间,即每隔一段时间增大duty_num的值。

那每次增大多少呢?

主循环第一行,设置的每50ms改一次占空比。首先要知道你想让一个呼吸灯亮灭的周期是多少,比如我想让led灯一呼一吸是3秒,那么就是3000ms,要设置60次占空比。

前面说过,呼吸灯有两个过程,一个过程是慢慢亮灯,一个是慢慢灭灯,两个过程时间一样,那么每个过程要设置30次占空比。设置占空比就是设置高电平在一个中断周期中所占时间,前面说了一个中断周期数500个数,灯最亮的时候高电平时间为0,为了30次将0变成500,每次让duty_num增大500/30,就是17。灯由灭变亮同理。

知道了每次duty_num变化量,那么就可以将新的duty_num值用于设置高电平计数个数。

但是由于每次是加17,因此当493加到510时,会超过一个中断周期的500计数,因此要检测溢出。如果检测到duty_num为510,就改成500,并开始逐渐减小。

因为减小的时候是500开始减,每次减17,因此最后会出现负数。也要做一样的操作。

实验现象

接3.3V到面包板外围,LED灯正极接面包板正极,阴极接TIM3的PWM输出口;拿一个杜邦线一端插入TIM4的PWM输出口,另一端插入PC13口(自带的LED灯阴极是这个口)。

连接好串口模块,烧录程序,发现外接的LED与自带的LED一起变成了呼吸灯:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qHJznfqE-1667782846014)(E:\学习资料\嵌入式作业\12_hal_pwm\1.gif)]

总结

使用PWM来拟合呼吸波曲线,来控制LED灯的亮度。使用HAL库配置定时器,使定时器按照占空比输出高低电平。并以一定时间间隔修改占空比。

参考资料

http://www.mcublog.cn/stm32/2021_01/stm32cubemx-pwm-huxideng/

### 使用HAL实现PWM控制呼吸 #### 初始化配置 为了使STM32通过PWM输出来模拟LED的渐亮渐暗(即所谓的“呼吸”效果),需要先初始化定时器以及相应的PWM通道。这通常涉及到设置定时器的工作模式、预分频系数、自动重装载值等参数。 ```c TIM_HandleTypeDef htim2; void MX_TIM2_Init(void) { __HAL_RCC_TIM2_CLK_ENABLE(); htim2.Instance = TIM2; htim2.Init.Prescaler = 8000 - 1; // 设置预分频值,假设系统时钟为80MHz,则此频率约为10kHz htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 999; // 自动重载值决定占空比范围 htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; if (HAL_TIM_PWM_Init(&htim2) != HAL_OK) { Error_Handler(); } TIM_OC_InitTypeDef sConfigOC; sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 0; // 初始脉冲宽度设为零 sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) { Error_Handler(); } } ``` 上述代码完成了对`TIM2`定时器及其PWM功能的具体配置[^1]。 #### 开启PWM输出并调整亮度 一旦完成硬件资源的初始化工作之后,在主循环里可以通过改变PWM波形的占空比来动态调节LED发光强度: ```c int main(void) { /* Reset of all peripherals, Initializes the Flash interface and Systick. */ HAL_Init(); SystemClock_Config(); // 配置系统时钟 MX_GPIO_Init(); // GPIO初始化 MX_TIM2_Init(); // 定时器初始化 uint16_t dutyCycle = 0; int direction = 1; while (1) { __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, dutyCycle); if ((dutyCycle >= 1000 && direction > 0) || (dutyCycle <= 0 && direction < 0)) { direction *= -1; } dutyCycle += direction * 5; // 调整步长大小可影响变化速度 HAL_Delay(20); // 控制刷新速率 } } ``` 这段程序展示了如何利用软件延时函数配合变量更新的方式逐步增加或减少PWM信号的高电平持续时间,从而达到让连接到指定GPIO引脚上的LED呈现出缓慢变亮再慢慢熄灭的效果[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值