994|3

1339

帖子

0

资源

纯净的硅(高级)

【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);
}

编译下载,上电顺利跑起来。完美!看看效果吧:

led.gif

 

此帖出自GD32 MCU论坛

回复

5846

帖子

18

资源

五彩晶圆(中级)

我干了差不多15年代码,上个月第一次用pwm搞了个呼吸灯,哈哈哈哈。

此帖出自GD32 MCU论坛

点评

呼吸灯只是小道,是锦上添花,让效果看起来好一点而已。  详情 回复 发表于 2022-2-21 12:21
个人签名

默认摸鱼,再摸鱼。2022、9、28


回复

1339

帖子

0

资源

纯净的硅(高级)

freebsder 发表于 2022-2-20 22:06 我干了差不多15年代码,上个月第一次用pwm搞了个呼吸灯,哈哈哈哈。

呼吸灯只是小道,是锦上添花,让效果看起来好一点而已。

此帖出自GD32 MCU论坛

点评

我印象里我以前还真没做过呼吸灯,上个月第一次搞的时候还是费了点功夫。  详情 回复 发表于 2022-2-21 22:14

回复

5846

帖子

18

资源

五彩晶圆(中级)

yang_alex 发表于 2022-2-21 12:21 呼吸灯只是小道,是锦上添花,让效果看起来好一点而已。

我印象里我以前还真没做过呼吸灯,上个月第一次搞的时候还是费了点功夫。

此帖出自GD32 MCU论坛
个人签名

默认摸鱼,再摸鱼。2022、9、28


回复
您需要登录后才可以回帖 登录 | 注册

相关帖子
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
    关闭
    站长推荐上一条 1/6 下一条

    About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

    站点相关: 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

    北京市海淀区知春路23号集成电路设计园量子银座1305 电话:(010)82350740 邮编:100191

    电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2022 EEWORLD.com.cn, Inc. All rights reserved
    快速回复 返回顶部 返回列表