十八、PWM呼吸灯
1. 配置流程
我们外接一个LED灯进行PWM实现,注意一下要选择合适规格的LED。
一般使用定时器PWM功能,都需要有以下几个步骤。
- 使能时钟
- 配置GPIO
- 配置定时器
- 配置PWM
- 使能TIMER
- 调整定时器输出通道占空比
2. 使能时钟
用PWM实现一个呼吸灯的效果。首先LED灯连接在PB0引脚上,查找数据手册的第29页可知,PB0有定时器3通道的复用功能,如图所示:
这里选择PB0的复用功能,也就是使用TIMER3_CH3进行PWM输出。
使能时钟:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定时器3时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能GPIO外设
2
3. 配置GPIO
前面介绍过PWM输出是依赖于定时器的,所以要对定时器进行配置,但是我们不使用定时器的中断功能,顾不用对定时器的中断进行配置。又因为我们使用的PB0是定时器3的通道3,所以我们要配置PB0的GPIO参数。
首先是GPIO的参数结构体:
GPIO_InitTypeDef GPIO_InitStructure; // GPIO结构体
然后GPIO配置参数:
//设置该引脚为复用输出功能,输出TIM3 CH3的PWM脉冲波形GPIOB0
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //TIM3_CH3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
2
3
4
使能GPIO配置。
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO
4. 配置定时器
要使用定时器参数配置有一个结构体,如图所示:
参数解释
TIM_Prescaler
:预分频器值。用于除以TIM的时钟频率。这个参数可以是0x0000到0xFFFF之间的任何数值。预分频器的实际作用是减慢定时器的计数速度,从而允许定时器在更宽的时间范围内工作。TIM_CounterMode
:计数器模式。这个参数指定定时器的计数模式,可以是以下几种模式之一(这些模式决定了定时器是如何计数的):- TIM_CounterMode_Up:向上计数模式。
- TIM_CounterMode_Down:向下计数模式。
- TIM_CounterMode_CenterAligned:中心对齐模式,计数器向上计数到一个值然后向下计数到0。
TIM_Period
:周期值。这个参数指定了自动重装载寄存器的值,在下一个更新事件时被加载。这个参数必须是0x0000到0xFFFF之间的数值。周期值实际上定义了定时器溢出(或者达到预设的计数值)的时间点,从而触发相关的中断或事件。TIM_ClockDivision
:时钟分频。这个参数可以是以下几种值之一,这个分频是在预分频器之后进一步对时钟进行分频:- TIM_CKD_DIV1:不分频。
- TIM_CKD_DIV2:时钟分频2。
- TIM_CKD_DIV4:时钟分频4。
TIM_RepetitionCounter
:重复计数器值。每次RCR(重复计数器)倒数到0时,都会生成一个更新事件,并且计数重新从RCR值(N)开始。在PWM模式下,这意味着(N+1)对应于【这个参数必须是0x00到0xFF之间的数值。注意,这个参数只对TIM1和TIM8有效。】:- 边沿对齐模式下的PWM周期数。
- 中心对齐模式下的半PWM周期数。
结构体定义:
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
相关配置如下:
//初始化TIM3
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc - 1; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 时钟分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
2
3
4
5
初始化配置:
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
//根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
2
5. 配置PWM
配置好TIMER3参数之后,需要配置PWM输出结构体。
结构体定义如下:
TIM_OCInitTypeDef TIM_OCInitStructure;
结构体配置如下:
//初始化TIM3 Channel3 PWM模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性
2
3
4
初始化配置:
TIM_OC3Init(TIM3, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM3 OC3
注意:每个通道有不同的函数。通道2是TIM_OC2Init,通道3是TIM_OC3Init,如此以此类推。。。。
使能预装载寄存器:
TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR3上的预装载寄存器
注意:每个通道有不同的函数。通道2是TIM_OC2PreloadConfig,通道3是TIM_OC3PreloadConfig,如此以此类推。。。。
6. 使能TIMER
我们使用函数TIM_Cmd初始化函数:
TIM_Cmd(TIM3, ENABLE); //使能TIM3
7. 调整定时器输出通道占空比
我们使用以下函数调整占空比:
void TIM_SetCompare3(TIM_TypeDef* TIMx, uint32_t Compare3);
这个函数是用于设置STM32系列微控制器中定时器的捕获比较3寄存器(CC3R)的值。通过设置这个寄存器,可以控制定时器的输出比较(Output Compare)或输入捕获(Input Capture)功能,这对于生成精确的时间延迟、测量脉冲宽度或产生复杂的PWM输出等应用至关重要。
参数解释:
TIMx
:指定要操作的定时器实例。STM32微控制器通常包含多个定时器实例(如TIM1、TIM2等),这个参数允许选择特定的定时器实例进行操作。不同的STM32型号支持的定时器数量和功能可能有所不同。Compare3
:指定捕获比较3寄存器(CC3R)的新值。在输出比较模式下,这个值通常用于与定时器的计数值进行比较,以控制定时器的行为,如在达到特定计数值时触发中断或改变某个输出引脚的状态。在输入捕获模式下,它可以用于捕获和存储外部事件(如脉冲到达)的时间点。无返回值!!!(
@retval None
)
注意:每个通道有不同的函数。通道2是TIM_SetCompare2,通道3是TIM_SetCompare3,如此以此类推。。。。
在PWM(脉冲宽度调制)应用中,可以通过改变CC3R的值来调整PWM信号的占空比。例如,增加CC3R的值会增加PWM高电平的持续时间,从而增加占空比。
8. 编写呼吸灯函数
要实现一个呼吸灯的效果,首先我们来看呼吸灯产生的原理。呼吸灯产生的原理就是LED灯逐渐变亮再逐渐变暗,然后一直循环下去。控制LED灯的亮暗是通过改变PWM的占空比,占空比越大,LED灯越亮,占空比越小,LED灯越暗。所以,我们只需要调节PWM的占空比就可以实现呼吸灯的效果。设置PWM的占空比的函数在之前介绍过,编写呼吸灯代码如下:
void pwm_breathing_lamp(void)
{
uint32_t brightness = 0; // 当前亮度
int step = 1; // 亮度改变的步长
int delayTime = 3; // 延时时间
// 逐渐增加亮度
for(brightness = 0; brightness <= 1000; brightness += step)
{
TIM_SetCompare3(TIM3, brightness); // 使用TIM3的Channel 3
delay_ms(delayTime);
// 随着亮度的增加,增加步长,使亮度变化加快
if(brightness < 500)
{
step = 1 + brightness / 100;
}
else
{
step = 1 + (1000 - brightness) / 100;
}
}
// 短暂暗淡
delay_ms(100);
// 逐渐减少亮度
for(brightness = 1000; brightness != 0; brightness -= step)
{
TIM_SetCompare3(TIM3, brightness); // 使用TIM3的Channel 3
delay_ms(delayTime);
// 随着亮度的减少,减少步长,使亮度变化减慢
if(brightness > 500)
{
step = 1 + (1000 - brightness) / 100;
}
else
{
step = 1 + brightness / 100;
}
}
// 短暂暗淡
delay_ms(100);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
函数解释
- 变量初始化:
- uint32_t brightness = 0;:定义并初始化亮度变量brightness,用于控制LED的亮度。
- int step = 1;:定义并初始化步长变量step,用于控制每次亮度变化的大小。
- int delayTime = 3;:定义并初始化延时变量delayTime,用于控制每次亮度变化之间的延时,单位为毫秒。
- 逐渐增加亮度:
- 使用一个for循环,从0开始逐步增加brightness的值,直到1000(假设这是LED的最大亮度值)。
- 在循环内部,调用TIM_SetCompare3(TIM3, brightness);来设置TIM3的Channel 3的比较值为当前亮度值,实际上是调整PWM信号的占空比,从而控制LED的亮度。
- 使用delay_ms(delayTime);在每次亮度变化后引入短暂的延时。
- 根据当前亮度值调整步长step,在亮度较低时步长较小,亮度较高时步长增大,使亮度变化加快。
- 短暂暗淡:
- 在亮度增加到最大值后,使用delay_ms(100);引入100毫秒的延时,模拟呼吸灯在最亮时的短暂停留。
- 逐渐减少亮度:
- 使用另一个for循环,从1000开始逐步减少brightness的值,直到0。
- 循环内部的操作与增加亮度时相似,不同之处在于亮度是逐渐减少的。
- 同样根据当前亮度值调整步长step,在亮度较高时步长较大,亮度较低时步长减小,使亮度变化减慢。
- 再次短暂暗淡:
- 在亮度减少到最低值后,再次使用delay_ms(100);引入100毫秒的延时,模拟呼吸灯在最暗时的短暂停留。
9. 实验现象
关于这一章节的代码百度网盘下载,在立创·STM32F103C8T6开发板资料(标准库)/第03章软件资料/代码例程/009PWM呼吸灯。
烧写代码之后,会观察到LED灯由暗变亮,继而由亮变暗的效果。