hehung · 2022年12月12日 · 四川

【GD32F427开发板试用】6. 定时器运用之精确定时1s

之前发帖

【GD32F427开发板试用】1. 串口实现scanf输入控制LED
【GD32F427开发板试用】2. RT-Thread标准版移植
【GD32F427开发板试用】3. 硬件IIC0驱动OLED显示中文
【GD32F427开发板试用】4. ADC采集摇杆模块移动量
【GD32F427开发板试用】5. SPI驱动TFTLCD屏幕

前言

定时器相对而言较为简单,但是因为没有在官方例程中找到单纯使用定时器功能的用例(官方例程都是使用定时器映射端口输出PWM等等)因为后期实现的项目需要用到定时器,遂实现了定时器功能,介绍定时器的用法。

本文实现了如下功能:

  1. 定时器配置计数count为1000000,向上计数模式;
  2. 使能定时器中断,1s触发一次;
  3. 在定时器中断中反转PC6(LED2)。

定时器介绍

查看用户手册第十八章 18.定时器(TIMERx)有详细的介绍,GD32F4xx的定时器种类很多,分类见下表:
1.png

本文中使用的是普通定时器TIMER1。

关于定时器的介绍,本文不再做赘述,参考用户手册即可。
而且用户也不需要关注寄存器设置,只需要对定时器做一个大致的了解,因为官方提供了库文件可以直接调用相关库文件进行操作控制定时器即可。

时钟配置

了解了定时器的基本知识,但是要操作定时器还是少不了时钟的配置,如果时钟设置不对,会导致定时时间不精确,对功能影响较大。
参考用户手册第四章 4.复位和是中单元(RCU)了解时钟树以及定时器分频相关知识。
时钟树:
3.png

从时钟树中可以看到,定时器1是连接到了AHB时钟的,AHB时钟最高支持240MHz,但是也只是针对GD32F470而言,GD32F427最多支持200MHz,这个信息在数据手册中有描述。
4.png

通过查看代码也可以知道时钟配置为200MHz。
5.png

有上述信息以及代码初始化可知,APB1时钟为四分频,所以APB1时钟为50MHz。
6.png

通过寄存器对定时器进行倍频控制,设置为4倍频,让定时器的工作频率等同于单片机的时钟频率,这样便于后续在分频控制。
2——0.png
2.png

软件编写

知道了时钟分频控制以及定时器知识,现在可以开始进行软件编写了。

定时器初始化

其中,
rcu_timer_clock_prescaler_config设置4倍频,使定时器工作频率为200MHz;
timer_initpara.prescaler = 200-1设置定时器预分频系数为200,则定时器工作频率为200MHz/200 = 1MHz;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE设置上升沿计数模式;
timer_initpara.counterdirection = TIMER_COUNTER_UP设置向上计数模式;
timer_initpara.period = 1000000设置向上计数上限值为100000,即计数周期为1/1MHz*1000000 = 1s;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1设置不再分频;
timer_initpara.repetitioncounter = 0表示重新开始计数值初始值为0.

void Timer_Init(void)
{
    timer_oc_parameter_struct timer_ocintpara;
    timer_parameter_struct timer_initpara;

    rcu_periph_clock_enable(RCU_TIMER1);
    rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);

    timer_struct_para_init(&timer_initpara);
    timer_deinit(TIMER1);

    /* TIMER1 configuration */
    timer_initpara.prescaler         = 200-1;
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE;
    timer_initpara.counterdirection  = TIMER_COUNTER_UP;
    timer_initpara.period            = 1000000;
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 0;
    timer_init(TIMER1, &timer_initpara);

    /* auto-reload preload enable */
    timer_auto_reload_shadow_enable(TIMER1);
    /* Enable the interrupt for overflow */
    timer_interrupt_enable(TIMER1, TIMER_INT_UP);
    /* Configure the interrupt priority */
    nvic_irq_enable(TIMER1_IRQn, 5, 2);
    /* TIMER1 enable */
    timer_enable(TIMER1);
}

定时器1中断实现

表示每次进入中断都会将LED1反转一次,用来查看定时是否准确。

int aa = 1;
void TIMER1_IRQHandler(void)
{
    if(SET == timer_interrupt_flag_get(TIMER1, TIMER_INT_UP))
    {
        aa ^= 1;
        rt_pin_write(LED2_PIN, aa);
        /* clear TIMER interrupt flag */
        timer_interrupt_flag_clear(TIMER1, TIMER_INT_UP);
    }
}

主函数

主函数中不需要什么操作,定时器计数值满了之后会直接到中断中反转PC6(LED2)

效果验证

下图为定时器工作效果,可以看到,定时1s还是很精确的。
1.gif

推荐阅读
关注数
10711
内容数
187
中国高性能通用微控制器领域的领跑者兆易创新GD系列芯片技术专栏。
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息