GD32E230F4定时器学习一:更新定时器周期实现LED闪烁(设备运行指示)

在做一些mcu方案开发时,板上的LED如果处理不好,会显得设备很low。所以我借鉴一些设备的运行指示灯的思路,想到,如果可以让LED亮100ms,灭1900ms(时间自行决定)可以看上去稍具B格一点。正好最近在学习和开发一个使用了GD32E230F4的传感器小板,那么就想办法在上面实现一下吧。

实现方法

关于实现方法的选择,我纠结了很多,因为看到同事开发的类似功能的传感器小板的实现方法使用了类似软件PWM的方式,但是我认为硬件外设有咱就用,实在不行再软件模拟,就最终选择使用一个定时器来产生中断,然后中断内操作GPIO,并没有采用生成一个周期2000ms的占空比10%的PWM。因为我的其他应用,也要用到一个固定时间间隔处理一些内容的情况,就算是预习吧

实现过程

实现的过程呢相对比较简单,就是用一个通用定时器产生一个可以精确控制的到小数点后一位的ms值,然后并置位定时器更新标志位(TIMER_INT_FLAG_UP),

void timer_config(void)
{
    /* ----------------------------------------------------------------------------
    TIMER2 Configuration: 
    TIMER2CLK = SystemCoreClock/7200 = 10KHz,the period is 1s(10000/10000 = 1s).
    ---------------------------------------------------------------------------- */
    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         = 7199;
    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);

    /* clear channel 0 interrupt bit */
    timer_interrupt_flag_clear(TIMER2, TIMER_INT_FLAG_UP);
    /* enable the TIMER interrupt */
    timer_interrupt_enable(TIMER2, TIMER_INT_UP);
    /* enable a TIMER */
    timer_enable(TIMER2);
    nvic_irq_enable(TIMER2_IRQn, 0);
}

然后我们看上面的注释也能理解,经过分频后,然后通过自动重载值来达到精确控制定时器更新时间,那么接下来的核心就是我们要动态更新这个自动重载值就可以了,接下来就到了关键点了,这里我在写的时候,其实使用了赛博拐棍(AI工具)来帮我生成,但是它生成的更新自动重载值的函数是没有的,一眼假那种。类似下面的效果:

void TIMER2_IRQHandler(void) {
    if (timer_interrupt_flag_get(TIMER2, TIMER_INT_FLAG_UP) != RESET) {
        timer_interrupt_flag_clear(TIMER2, TIMER_INT_FLAG_UP);
        static uint8_t led_state = 0;
        if (led_state) {
            gpio_bit_reset(GPIOC, GPIO_PIN_13); // LED灭
            timer_update_config(TIMER2, 8000 - 1); // 设置为800ms
        } else {
            gpio_bit_set(GPIOC, GPIO_PIN_13); // LED亮
            timer_update_config(TIMER2, 2000 - 1); // 设置为200ms
        }
        led_state = !led_state;
    }
}

接下来来到了重点,也是我写本篇博文的目的,记录一下我找对应函数的思路。

  1. 首先通过前面定时config时候的函数和结构体找到他的寄存器操作代码
    GD32E23x_Firmware_Library_V2.1.0\Firmware\GD32E23x_standard_peripheral\Source\gd32e23x_timer.c文件的121行函数中,找到 TIMER_CAR(timer_periph) = (uint32_t)initpara->period;
  2. 上面确定了寄存器操作的代码,然后打开 GD32E23X固件库使用指南搜索 TIMER_CAR(可能没法搜索,文档有问题,内容在3.18.1的定时器 外设寄存器说明下面),就会发现这个 TIMER_CAR就是 计数器自动重载寄存器那么就可以确定是我们要找的内容了。
  3. 接下来再拿上面的 TIMER_CAR回到代码里面搜索,就会得到一个全新的函数 void timer_autoreload_value_config(uint32_t timer_periph, uint16_t autoreload)
  4. 使用它替换赛博拐棍的错误
void TIMER2_IRQHandler(void) {
    if (timer_interrupt_flag_get(TIMER2, TIMER_INT_FLAG_UP) != RESET) {
        timer_interrupt_flag_clear(TIMER2, TIMER_INT_FLAG_UP);
        static uint8_t led_state = 0;
        if (led_state) {
            gpio_bit_reset(GPIOC, GPIO_PIN_13); // LED灭
            timer_autoreload_value_config(TIMER2, 8000 - 1); // 设置为800ms
        } else {
            gpio_bit_set(GPIOC, GPIO_PIN_13); // LED亮
            timer_autoreload_value_config(TIMER2, 2000 - 1); // 设置为200ms
        }
        led_state = !led_state;
    }
}

上面就是完成的效果,如果学到了就去试试吧。

最后修改:2024 年 09 月 12 日
如果觉得我的文章对你有用,请随意赞赏