【GD32L233C-START评测】第3篇 PWM驱动呼吸灯
[复制链接]
官方的点灯程序只是流水灯。我们来玩点稍微复杂的呼吸灯。
呼吸灯的简单原理就是用PWM波驱动LED,逐渐调大占空比,到达最大占空比后再逐渐调小占空比。由于PWM的频率比较高,再加上人眼的视觉暂留效应,用户感觉不到LED的闪烁,只能感受到LED明暗的变化,从而实现呼吸的效果。
兆易创新的GD32L233C系列MCU没有直接提供 PWM外设,不过可以通过定时器实现。 兆易创新的GD32L233C系列MCU提供四类定时器:通用定时器L0(TIMER1, TIMER2),通用定时器L1(TIMER8, TIMER11),基本定时器(TIMER5, TIMER6)和低功耗定时器LPTIMER。其中通用定时器L0(TIMER1, TIMER2),通用定时器L1(TIMER8, TIMER11)和低功耗定时器LPTIMER都可以实现可编程PWM功能。注意:基本定时器(TIMER5, TIMER6)不能实现可编程PWM功能。出此之外,兆易创新的GD32L233C系列MCU的定时器功能还是挺强悍的,可以实现多种用途。兆易创新的提供的固件库和例子程序也很给力。
我们这次使用通用定时器L0(TIMER2)实现可编程PWM,简单地采用边沿对齐型。TIMER2输出通道1连接PA7(评估板上PA7正好驱动LED1) 。顺便说一下,基本定时器(TIMER5, TIMER6)之所以不能实现PWM功能是因为它们没有输出通道。
先进行PWM外设----TIMER2输出通道1连接的PA7功能设置:
void gpio_config(void)
{
rcu_periph_clock_enable(RCU_GPIOA);
/* TIMER1 GPIO */
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_7 );
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_7);
gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_7);
}
接下来设置TIMER2的PWM功能: 好像有点复杂。。不过多看兆易创新的提供的例子程序吧,很多东西可以参考。
void timer_config(void)
{
timer_oc_parameter_struct timer_ocinitpara;
timer_parameter_struct timer_initpara;
/* enable the peripherals clock */
rcu_periph_clock_enable(RCU_TIMER2);
/* deinit a TIMER */
timer_deinit(TIMER2);
/* initialize TIMER init parameter struct */
timer_struct_para_init(&timer_initpara);
/* TIMER2 configuration */
timer_initpara.prescaler = 63;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 9999;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_init(TIMER2, &timer_initpara);
/* initialize TIMER channel output parameter struct */
timer_channel_output_struct_para_init(&timer_ocinitpara);
/* configure TIMER channel output function */
timer_ocinitpara.outputstate = TIMER_CCX_ENABLE;
timer_ocinitpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
timer_channel_output_config(TIMER2, TIMER_CH_1, &timer_ocinitpara);
timer_channel_output_pulse_value_config(TIMER2, TIMER_CH_1, pwm_pulse_value);
/* CH0 configuration in OC timing mode */
timer_channel_output_mode_config(TIMER2, TIMER_CH_1, TIMER_OC_MODE_PWM0);
timer_enable(TIMER2);
}
接下来就是主程序的实现了:死循环中调整PWM的占空比参数(先逐渐增大,后逐渐减小),再延时5ms。
#include "gd32l23x.h"
#include "gd32l233c_start.h"
#include "systick.h"
uint16_t T_ms = 0,pwm_pulse_value = 20;
void gpio_config(void);
void nvic_config(void);
void timer_config(void);
int main(void)
{
systick_config();
gpio_config();
timer_config();
while(1)
{
T_ms ++;
if(T_ms < 400)
{
pwm_pulse_value = pwm_pulse_value + 10;
}
else
{
pwm_pulse_value = pwm_pulse_value - 10;
}
if(T_ms == 800)
{
T_ms = 0;
pwm_pulse_value = 20;
}
timer_channel_output_pulse_value_config(TIMER2, TIMER_CH_1, pwm_pulse_value);
delay_1ms(5);
}
}
编译下载,上电顺利跑起来了。
不过用延时加死循环来更新占空比参数是不是档次有点低?我们干脆把占空比的更新放到定时器的中断函数中实现,用基本定时器(TIMER5)实现一个5ms的定时器(把下面代码加入到上面定时器的配置程序void gpio_config(void)中):(注意定义了2个全局变量 uint16_t T_ms = 0,pwm_pulse_value = 20; )
/* enable the peripherals clock */
rcu_periph_clock_enable(RCU_TIMER5);
/* deinit a TIMER */
timer_deinit(TIMER5);
/* initialize TIMER init parameter struct */
timer_struct_para_init(&timer_initpara);
/* TIMER5 configuration */
timer_initpara.prescaler = 63;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 5000; //5ms
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_init(TIMER5, &timer_initpara);
/* auto-reload preload enable */
timer_auto_reload_shadow_enable(TIMER5);
/* clear channel 0 interrupt bit */
timer_interrupt_flag_clear(TIMER5, TIMER_INT_FLAG_UP);
/* channel 0 interrupt enable */
timer_interrupt_enable(TIMER5, TIMER_INT_UP);
/* enable a TIMER */
timer_enable(TIMER5);
还有一个是需要在 gd32l23x_it.c文件中添加TIMER5的中断程序 void TIMER5_IRQHandler(void):
void TIMER5_IRQHandler(void)
{
if(SET == timer_interrupt_flag_get(TIMER5, TIMER_INT_FLAG_UP))
{
/* clear channel 1 interrupt bit */
timer_interrupt_flag_clear(TIMER5, TIMER_INT_FLAG_UP);
T_ms ++;
if(T_ms < 600)
{
pwm_pulse_value = pwm_pulse_value + 2;
}
else
{
pwm_pulse_value = pwm_pulse_value - 2;
}
if(T_ms == 1200)
{
T_ms = 0;
pwm_pulse_value = 4;
}
timer_channel_output_pulse_value_config(TIMER2, TIMER_CH_1, pwm_pulse_value);
}
}
当然,主程序也需要修改一下:
int main(void)
{
systick_config();
gpio_config();
nvic_config();
timer_config();
while(1)
{
}
}
void nvic_config(void)
{
nvic_irq_enable(TIMER5_IRQn, 0);
}
编译下载,上电顺利跑起来。完美!看看效果吧:
|