跳到主要内容

【十八】PWM呼吸灯

1.1.配置流程

一般使用定时器PWM功能,都需要有以下几个步骤

  • 配置通道引脚GPIO
  • 配置定时器
  • 配置输出结构体
  • 配置定时器输出通道
  • 配置定时器输出通道占空比
  • 定时器自动重载影子使能

1.1.1.配置通道引脚GPIO

GD32F450ZGT6单片机一共有14个定时器,除了基本定时器没有PWM功能,其它定时器都有1个、2个或4个PWM通道。 这一章节就用PWM实现一个呼吸灯的效果。首先LED灯连接在PA5引脚上,查找数据手册的第46页可知,PA5有好几个定时器通道的复用功能,如图1-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

初始化GPIO引脚的配置如下:

static void pwm_gpio_config(void)
{
/* 开启时钟 */
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);
}

上面的代码都是一些常规操作,需要注意的点就是设置复用功能的时候配置为GPIO_AF_1,因为我们使用的是PA5引脚的AF1的功能

1.1.2.配置定时器

前面介绍过PWM输出是依赖于定时器的,所以要对定时器进行配置,但是我们不使用定时器的中断功能,顾不用对定时器的中断进行配置

又因为我们使用的PA5的AF1是定时器1的通道0,所以我们要配置定时器1的参数。关于定时器1的宏定义如下:

/* TIMER */
#define BSP_PWM_TIMER_RCU RCU_TIMER1 // 定时器时钟
#define BSP_PWM_TIMER TIMER1 // 定时器

接下来就要配置定时器的参数

首先是定义定时器的参数结构体:

timer_parameter_struct timer_initpara; // 定义定时器结构体

然后使能定时器时钟和配置参数:

/* 开启时钟 */
rcu_periph_clock_enable(BSP_PWM_TIMER_RCU); // 开启定时器时钟
/* CK_TIMERx = 4 x CK_APB1 = 4x50M = 200MHZ */
rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4); // 配置定时器时钟
timer_deinit(BSP_PWM_TIMER); // 复位定时器
/* 配置定时器参数 */
timer_initpara.prescaler = 200 -1; // 时钟预分频值 PSC_CLK= 200MHZ / 200 = 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; // 分频因子
/* 只有高级定时器才有 配置为x,就重复x+1次进入中断 */
timer_initpara.repetitioncounter = 0; // 重复计数器 0-255
timer_init(BSP_PWM_TIMER,&timer_initpara); // 初始化定时器

这里和之前的定时器实验相比就只有两处发生变化,一个就是时钟分频值修改为199,那PSC_CLK = 200MHZ / 200 = 1MHZ,周期值设置为10000 -1, 那对应的PWM输出的频率就是1MHZ / 10000 = 100HZ。需要注意的是LED灯刷新率在50HZ以下会有明显的闪烁,顾PWM的频率设置不能低于50HZ

最后不要忘记使能定时器

/* 使能定时器 */
timer_enable(BSP_PWM_TIMER);

1.1.3.配置输出结构体

要使用定时器的PWM功能就是用定时器的输出功能,关于输出功能的参数配置有一个结构体,如图1-3-1所示

1
  • ocpolarity:通道输出的极性,也就是配置为低电平有效还是高电平有效,这里配置为高电平有效TIMER_OC_POLARITY_HIGH
  • outputstate:通道输出状态,一般是使能TIMER_CCX_ENABLE,使能PWM输出到端口

其它的参数都是高级定时器使用的,可以不用配置

1.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,TIMER_CH_0,&timer_ocintpara);

1.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,TIMER_CH_0,5000 - 1); // 配置定时器通道输出脉冲值

这里设置输出脉冲值为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所示

1

这里设置为PWM模式0,也就是配置为TIMER_OC_MODE_PWM0。配置代码如下:

timer_channel_output_mode_config(BSP_PWM_TIMER,TIMER_CH_0,TIMER_OC_MODE_PWM0);// 配置定时器通道输出比较模式

void timer_channel_output_shadow_config(

uint32_t timer_periph, uint16_t channel, uint16_t ocshadow);

这个函数是配置定时器通道输出比较影子寄存器功能。有三个参数,第一个参数是要配置的定时器外设,第二个参数是要配置的定时器通道,第三个参数是输出比较影子寄存器功能的状态。我们禁止输出比较影子寄存器,配置如下:

timer_channel_output_shadow_config(BSP_PWM_TIMER,TIMER_CH_0,TIMER_OC_SHADOW_DISABLE);// 配置定时器通道输出影子寄存器

1.1.6.定时器自动重载影子使能

void timer_auto_reload_shadow_enable(uint32_t timer_periph);

这个函数是自动重载影子使能。有1个参数是要使能的定时器。配置如下:

/* auto-reload preload enable */
timer_auto_reload_shadow_enable(BSP_PWM_TIMER);

到此,关于PWM的配置就完成了

1.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,TIMER_CH_0,value); // 配置定时器通道输出脉冲值
delay_1ms(50);
}

这里简单介绍一下,如果direct为0则为正方向变化,脉冲值value逐渐变大,LED灯逐渐变亮,当超出最大周期的时候,也就是亮度最大的时候,改变direct的值为1, 脉冲值value逐渐变小,LED灯逐渐变暗,当小于等于0的时候,又改变direct的值为0,继续正方向变化,然后一直循环下去。 每一次脉冲值变化后都会重新配置。delay_1ms(50)是为了有一个变化的过程,不然执行太快看不出来效果,如果配置为delay_1ms(10)将会执行的非常快, 直接从暗变化到亮,再从亮变化到暗,能实现一个爆闪的效果

1.3.实验现象

关于这一章节的代码,在资源包/04软件资料/代码例程/里面的009PWM呼吸灯

烧写我们的代码之后,会观察到LED4灯由暗变亮,继而由亮变暗的效果