十八、PWM呼吸灯
1.配置流程
我们外接一个LED灯进行PWM实现,注意一下要选择合适规格的LED。
一般使用定时器PWM功能,都需要有以下几个步骤。
- 配置通道引脚GPIO
- 配置定时器
- 配置输出结构体
- 配置定时器输出通道
- 配置定时器输出通道占空比
- 定时器自动重载影子使能
1.1.配置通道引脚GPIO
GD32F407VET6单片机一共有14个定时器,除了基本定时器没有PWM功能,其它定时器都有1个、2个或4个PWM通道。这一章节就用PWM实现一个呼吸灯的效果。首先LED灯连接在PA5引脚上,查找数据手册的第43页可知,PA5有好几个定时器通道的复用功能,如图1-1-1所示。
这里选择PA5的复用功能AF1进行操作,也就是使用TIMER1_CH0进行PWM输出。
要操作GPIO引脚,必不可少的就是对GPIO进行配置,开启时钟,配置模式,配置输出,设置复用功能等,还是这一系列的操作。
PA5引脚宏定义如下:
/* PA5 TIMER1_CH0 */
#define BSP_PWM_RCU RCU_GPIOA
#define BSP_PWM_PORT GPIOA
#define BSP_PWM_PIN GPIO_PIN_5
#define BSP_PWM_AF GPIO_AF_1
2
3
4
5
初始化GPIO引脚的配置如下:
/* 开启时钟 */
rcu_periph_clock_enable(BSP_PWM_RCU);
gpio_mode_set(BSP_PWM_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, BSP_PWM_PIN);
gpio_output_options_set(BSP_PWM_PORT,GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,BSP_PWM_PIN);
/* 配置IO为定时器的通道 */
gpio_af_set(BSP_PWM_PORT, GPIO_AF_1, BSP_PWM_PIN);
2
3
4
5
6
上面的代码都是一些常规操作,需要注意的点就是设置复用功能的时候配置为GPIO_AF_1,因为我们使用的是PA5引脚的AF1的功能。
1.2.配置定时器
前面介绍过PWM输出是依赖于定时器的,所以要对定时器进行配置,但是我们不使用定时器的中断功能,顾不用对定时器的中断进行配置。
又因为我们使用的PA5的AF1是定时器1的通道0,所以我们要配置定时器1的参数。关于定时器1的宏定义如下:
/* TIMER */
#define BSP_PWM_TIMER_RCU RCU_TIMER1 // 定时器时钟
#define BSP_PWM_TIMER TIMER1 // 定时器
#define BSP_PWM_TIMER_CH TIMER_CH_0 // 定时器输出通道
2
3
4
接下来就要配置定时器的参数
首先是定义定时器的参数结构体:
timer_parameter_struct timer_initpara; // 定义定时器结构体
然后使能定时器时钟和配置参数:
/* 配置定时器参数 */
timer_initpara.prescaler = 168 - 1; // 时钟预分频值 PSC_CLK= 168MHZ / 168 = 1MHZ
timer_initpara.alignedmode = TIMER_COUNTER_EDGE; // 边缘对齐
timer_initpara.counterdirection = TIMER_COUNTER_UP; // 向上计数
timer_initpara.period = 10000 - 1; // 周期 T = 10000 1MHZ = 10ms f = 100HZ
timer_initpara.clockdivision = TIMER_CKDIV_DIV1; // 分频因子
timer_initpara.repetitioncounter = 0; // 重复计数器 0-255
timer_init(BSP_PWM_TIMER,&timer_initpara); // 初始化定时器
2
3
4
5
6
7
8
时钟分频值为168,那PSC_CLK = 168MHZ / 168 = 1MHZ,周期值设置为10000 -1,那对应的PWM输出的频率就是1MHZ / 10000 = 100HZ。需要注意的是LED灯刷新率在50HZ以下会有明显的闪烁,顾PWM的频率设置不能低于50HZ。
最后不要忘记使能定时器。
/* 使能定时器 */
timer_enable(BSP_PWM_TIMER);
2
1.3.配置输出结构体
要使用定时器的PWM功能就是用定时器的输出功能,关于输出功能的参数配置有一个结构体,如图1-3-1所示。
- ocpolarity:通道输出的极性,也就是配置为低电平有效还是高电平有效,这里配置为高电平有效TIMER_OC_POLARITY_HIGH。
- outputstate:通道输出状态,一般是使能TIMER_CCX_ENABLE,使能PWM输出到端口。
其它的参数都是高级定时器使用的,可以不用配置。
1.4.配置定时器输出通道
配置好输出通道参数之后,需要初始化这个结构体,并且还需要配置使用定时器的通道几进行输出。
void timer_channel_output_config( uint32_t timer_periph,uint16_t channel, timer_oc_parameter_struct* ocpara); 这个函数是配置定时器通道的输出功能,有三个参数,第一个参数就是要使能的定时器外设,第二个参数是要使能的定时器通道,第三个参数是配置的输出结构体。
配置定时器输出功能代码如下:
/* 配置定时器输出功能 */
timer_channel_output_config(BSP_PWM_TIMER,BSP_PWM_TIMER_CH,&timer_ocinitpara);
2
1.5.配置定时器输出通道占空比
void timer_channel_output_pulse_value_config( uint32_t timer_periph, uint16_t channel, uint32_t pulse); 这个函数是配置定时器通道输出的脉冲值。有三个参数,第一个参数是要配置的定时器,第二个参数是要配置的定时器通道,第三个参数是要设置的脉冲值。脉冲值的取值范围为(0-65535)。一般我们调节占空比也是调用这个函数,通过设置这个通道的输出脉冲值,改变不同的占空比。
这里我们将占空比设置为50%,配置如下:
/* 配置定时器通道输出脉冲值 */
timer_channel_output_pulse_value_config(BSP_PWM_TIMER,BSP_PWM_TIMER_CH,5000 - 1);
2
这里设置输出脉冲值为5000-1,我们设置的定时器的周期为10000-1,则占空比为5000 / 10000 = 50%。
void timer_channel_output_mode_config(uint32_t timer_periph, uint16_t channel,uint16_t ocmode); 这个函数是配置外设定时器通道输出比较模式。有三个参数,第一个参数是要配置的定时器外设,第二个参数是要配置的定时器通道,第三个参数是要配置的比较模式。
关于第三个参数的可选选项如图1-5-1所示。
这里设置为PWM模式0,也就是配置为TIMER_OC_MODE_PWM0。配置代码如下:
/* 配置定时器通道输出比较模式 */
timer_channel_output_mode_config(BSP_PWM_TIMER,BSP_PWM_TIMER_CH,TIMER_OC_MODE_PWM0);
void timer_channel_output_shadow_config(
uint32_t timer_periph, uint16_t channel, uint16_t ocshadow);
2
3
4
这个函数是配置定时器通道输出比较影子寄存器功能。有三个参数,第一个参数是要配置的定时器外设,第二个参数是要配置的定时器通道,第三个参数是输出比较影子寄存器功能的状态。我们禁止输出比较影子寄存器,配置如下:
/* 配置定时器通道输出影子寄存器 */
timer_channel_output_shadow_config(BSP_PWM_TIMER,TIMER_CH_0,TIMER_OC_SHADOW_DISABLE);
2
1.6.定时器自动重载影子使能
void timer_auto_reload_shadow_enable(uint32_t timer_periph); 这个函数是自动重载影子使能。有1个参数是要使能的定时器。配置如下:
/* 自动重载使能 */
timer_auto_reload_shadow_enable(BSP_PWM_TIMER);
2
到此,关于PWM的配置就完成了。
2.呼吸灯函数
要实现一个呼吸灯的效果,首先我们来看呼吸灯产生的原理。呼吸灯产生的原理就是LED灯逐渐变亮再逐渐变暗,然后一直循环下去。控制LED灯的亮暗是通过改变PWM的占空比,占空比越大,LED灯越亮,占空比越小,LED灯越暗。所以,我们只需要调节PWM的占空比就可以实现呼吸灯的效果。设置PWM的占空比的函数在之前介绍过,编写呼吸灯函数如下:
void pwm_breathing_lamp(void)
{
static uint16_t value = 0;
static uint8_t direct = 0;
if(direct == 0)
{
value += 300;
if(value > 10000)
direct = 1; // 改变方向
}else
{
value -= 300;
if(value <= 0)
direct = 0; // 改变方向
}
timer_channel_output_pulse_value_config(BSP_PWM_TIMER,BSP_PWM_TIMER_CH,value); // 配置定时器通道输出脉冲值
delay_ms(50);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
这里简单介绍一下,如果direct为0则为正方向变化,脉冲值value逐渐变大,LED灯逐渐变亮,当超出最大周期的时候,也就是亮度最大的时候,改变direct的值为1,脉冲值value逐渐变小,LED灯逐渐变暗,当小于等于0的时候,又改变direct的值为0,继续正方向变化,然后一直循环下去。
每一次脉冲值变化后都会重新配置。delay_ms(50)是为了有一个变化的过程,不然执行太快看不出来效果,如果配置为delay_ms(10)将会执行的非常快,直接从暗变化到亮,再从亮变化到暗,能实现一个爆闪的效果。
3.实验现象
下载
在下载中心
的入门手册资料(点击跳转🚀)百度网盘链接下载 软件资料
-> 代码例程
里面,可以下载需要的压缩包。
烧写我们的代码之后,会观察到LED灯由暗变亮,继而由亮变暗的效果。