STM32定时器不止于定时:手把手教你用PWM控制LED呼吸灯(HAL库版)
·
STM32定时器不止于定时:手把手教你用PWM控制LED呼吸灯(HAL库版)
1. 从定时器到PWM:理解呼吸灯的核心原理
第一次看到LED呼吸灯效果时,那种柔和渐变的明暗变化总让人感觉特别"高级"。其实背后的原理并不复杂,关键就在于PWM(脉冲宽度调制)技术。对于STM32开发者来说,定时器模块正是实现PWM的绝佳工具。
PWM本质上是通过快速开关来控制平均功率。想象一下用STM32的GPIO直接驱动LED:如果以100Hz的频率让LED亮灭各半秒,我们看到的是LED闪烁;但当频率提高到1kHz以上,人眼就会感知为亮度减半。这就是PWM调光的基础——通过改变高电平时间(占空比)来模拟不同亮度。
在STM32的定时器中,有三个关键寄存器协同工作:
- ARR(Auto-Reload Register):决定PWM周期
- CCR(Capture/Compare Register):决定脉冲宽度
- CNT(Counter):实时计数值
当CNT<CCR时输出高电平,CNT≥CCR时输出低电平,CNT达到ARR后归零重新计数。通过动态调整CCR值,我们就能实现占空比的连续变化,这正是呼吸灯效果的精髓所在。
2. CubeMX配置:从零搭建PWM工程
2.1 硬件准备与工程创建
在开始前,请确保准备好:
- 任意一款STM32开发板(如STM32F103C8T6)
- 一个LED及适当限流电阻(通常220Ω)
- STM32CubeIDE开发环境
创建新工程时,选择对应型号后,我们需要重点关注定时器的配置。以常见的TIM3为例:
- 在Pinout视图中找到TIM3
- 激活某个通道(如Channel1)的PWM模式
- 自动分配对应GPIO(如PA6)
2.2 定时器参数详解
在Configuration标签页中,定时器的参数配置尤为关键:
| 参数 | 作用 | 推荐值(呼吸灯) |
|---|---|---|
| Prescaler | 时钟预分频系数 | 79 |
| Counter Mode | 计数模式 | Up |
| Period (ARR) | 自动重装载值 | 999 |
| Pulse (CCR) | 初始占空比 | 0 |
| CH Polarity | 输出极性 | High |
计算实际PWM频率的公式为:
PWM频率 = 定时器时钟 / (Prescaler + 1) / (ARR + 1)
以72MHz系统时钟为例,上述配置得到的PWM频率为:
72,000,000 / 80 / 1000 = 900Hz
这个频率远超人眼可辨范围,是LED调光的理想选择。
3. 代码实现:让LED"呼吸"起来
3.1 PWM初始化与启动
生成代码后,在main函数中添加PWM启动代码:
/* 启动PWM通道1 */
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
/* 初始占空比设置为0% */
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, 0);
3.2 呼吸效果算法实现
呼吸灯的核心在于CCR值的动态变化。我们可以在主循环中实现渐变效果:
uint16_t pwmVal = 0;
int8_t dir = 1; // 1表示增加,-1表示减少
while (1) {
HAL_Delay(10); // 控制变化速度
/* 更新CCR值 */
pwmVal += dir;
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, pwmVal);
/* 边界检测 */
if(pwmVal >= 1000) dir = -1;
else if(pwmVal <= 0) dir = 1;
}
这段代码会产生线性变化的呼吸效果。如果想实现更自然的视觉效果,可以改用正弦函数计算pwmVal:
float radian = 0;
while (1) {
HAL_Delay(10);
radian += 0.01;
if(radian > 6.28) radian = 0;
pwmVal = (sin(radian) + 1) * 500; // 映射到0-1000范围
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, pwmVal);
}
4. 进阶技巧与实战优化
4.1 使用中断实现精确控制
直接使用HAL_Delay会阻塞CPU,更好的做法是利用定时器中断:
// 在main中启动基本定时器
HAL_TIM_Base_Start_IT(&htim2);
// 中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
if(htim == &htim2) {
static uint16_t pwmVal = 0;
static int8_t dir = 1;
pwmVal += dir;
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, pwmVal*pwmVal/1000); // 二次方曲线更自然
if(pwmVal >= 1000) dir = -1;
else if(pwmVal <= 0) dir = 1;
}
}
4.2 多通道协同控制
通过配置多个PWM通道,可以实现RGB LED的彩色呼吸效果:
// 设置三个通道的CCR值
void setRGB(uint16_t r, uint16_t g, uint16_t b) {
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, r);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, g);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_3, b);
}
// 在循环中调用
setRGB(pwmVal, (pwmVal+333)%1000, (pwmVal+666)%1000);
4.3 常见问题排查
当PWM输出不正常时,建议检查:
- GPIO是否配置为复用推挽输出
- 定时器时钟是否使能
- PWM通道极性设置是否正确
- ARR和CCR值是否在合理范围内
调试时可以先用示波器观察PWM波形,确认硬件正常工作后再连接LED。
更多推荐
所有评论(0)