打印

GD32F4(7):GD32F4定时器使用

[复制链接]
1968|23
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
1. 系统环境
  • 系统:win10
  • IDE: Keil5
  • 开发板:GD32官方开发板GD32F427R-START
  • GD库版本:GD32F4xx_Firmware_Library_V3.0.0
2. 定时器描述

对于任何的外设,在使用的时候看一下时钟树都是重要的,因此对于定时器的使用,先看gd32f4的时钟树对定时器的描述如下:


从时钟树我们可知,定时器1、2、3、4、5、6、11、12、13是在APB1总线下面,定时器0、7、8、9、10是在APB2总线下面。



181863d7eb5a70a20.png (253.01 KB )

181863d7eb5a70a20.png

使用特权

评论回复
沙发
和下土|  楼主 | 2023-1-31 00:11 | 只看该作者
同时在时钟树下面有这样一段关于time的描述:

TIMER时钟由AHB时钟分频获得,它的频率可以等于CK_APBx、CK_APBx的两倍或CK_APBx的四倍。
详细信息请参考RCU_CFG1寄存器的TIMERSEL位。

使用特权

评论回复
板凳
和下土|  楼主 | 2023-1-31 00:12 | 只看该作者
既然如此,我们就看看RCU_CFG1寄存器的TIMERSEL位的描述:


可能你看到这一下就懵了,没关系我们先写定时器程序,边写边过来分析,就会恍然大悟。

使用特权

评论回复
地板
和下土|  楼主 | 2023-1-31 00:12 | 只看该作者
3. 定时器程序编写
下面我们实现一个定时器溢出中断,定时器虽然有高级、普通之分,但是那是其它功能(如PWM),对于定时器溢出中断可以说没区别。因此我们就以定时器1为例来写一个定时器最简单的初始化。
void timer_init(void)
{
   
        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,时钟为200M/200/1000 = 1k
    timer_initpara.prescaler         = 200-1;//预分频
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE; //边缘对齐
    timer_initpara.counterdirection  = TIMER_COUNTER_UP; //向上计数方式
    timer_initpara.period            = 1000-1; //计数值
    timer_initpara.clockdivision     = TIMER_CKDIV_DIV1;
    timer_initpara.repetitioncounter = 0; //设置重复计数器值,0表示不重复计数,每次溢出都产生更新事件
    timer_init(TIMER1,&timer_initpara);
   
    timer_auto_reload_shadow_enable(TIMER1);//使能自动重加载
    timer_enable(TIMER1);//使能定时器   
}


使用特权

评论回复
5
和下土|  楼主 | 2023-1-31 00:13 | 只看该作者
下面我们分析一下函数rcu_timer_clock_prescaler_config,因为它决定了定时器的时钟究竟是多少:

rcu_timer_clock_prescaler_config有一个参数,值为RCU_TIMER_PSC_MUL2或RCU_TIMER_PSC_MUL4,我们对照时钟树详细来说一下参数的意思:

使用特权

评论回复
6
和下土|  楼主 | 2023-1-31 00:14 | 只看该作者
这个图里面有三部分被红框标识,我们暂时称之上图1、上图2和上图3,后面分析的时候会用到。

使用特权

评论回复
7
和下土|  楼主 | 2023-1-31 00:14 | 只看该作者
定时器的TIMERSEL寄存器:

看上面时钟树局部图,对于GD32F425来讲,CK_AHB最高可以配置到200M

使用特权

评论回复
8
和下土|  楼主 | 2023-1-31 00:15 | 只看该作者
因为APBx的分频器(上图1)和定时器的时钟倍频器(上图2)是耦合在一起的,定时器的时钟倍频器不可以单独设置,因此有如下情况,

当函数rcu_timer_clock_prescaler_config参数为RCU_TIMER_PSC_MUL2的时候TIMERSEL的值将被设置为0,此时:

若APBx的分频系数为不分频(上图1),那么定时器倍频器(上图2)将不倍频,此时CK_TIMERx = CK_AHB,即定时器时钟就是AHB总线时钟。
若APBx的分频系数为2分频(上图1),那么定时器倍频器(上图2)将进行2倍频,此时依旧CK_TIMERx = CK_AHB,即定时器时钟就是AHB总线时钟。
若APBx设置的分频系数是除不分频、2分频外的其它分频(上图1),那么定时器倍频器(上图2)将进行2倍频,此时CK_TIMERx = 2 x CK_APBx,即定时器时钟就是APBx总线时钟的2倍,具体多少要看APBx的时钟。

使用特权

评论回复
9
和下土|  楼主 | 2023-1-31 00:20 | 只看该作者
当函数rcu_timer_clock_prescaler_config参数为RCU_TIMER_PSC_MUL4的时候TIMERSEL的值将被设置为1,此时:

若APBx的分频系数为不分频(上图1),那么定时器倍频器(上图2)将不倍频,此时CK_TIMERx = CK_AHB,即定时器时钟就是AHB总线时钟。
若APBx的分频系数为2分频(上图1),那么定时器倍频器(上图2)将进行2倍频,此时依旧CK_TIMERx = CK_AHB,即定时器时钟就是AHB总线时钟。
若APBx的分频系数为4分频(上图1),那么定时器倍频器(上图2)将进行4倍频,此时依旧CK_TIMERx = CK_AHB,即定时器时钟就是AHB总线时钟。
若APBx设置的分频系数是除不分频、2分频、4分频外的其它分频(上图1),那么定时器倍频器(上图2)将进行4倍频,此时CK_TIMERx = 4 x CK_APBx,即定时器时钟就是APBx总线时钟的4倍,具体多少要看APBx的时钟。

使用特权

评论回复
10
和下土|  楼主 | 2023-1-31 00:20 | 只看该作者
现在我们指导,这个定时器的时钟和APBx的分频系数相关,那么我们就看一下在时钟初始化的时候,设置情况:

在system_gd32f4xx.c的system_clock_200m_25m_hxtal(void)函数里面(因为我用的是25m晶振,所以是这个函数),里面有段代码如下:

/* HXTAL is stable */
/* AHB = SYSCLK */
RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;
/* APB2 = AHB/2 */
RCU_CFG0 |= RCU_APB2_CKAHB_DIV2;
/* APB1 = AHB/4 */
RCU_CFG0 |= RCU_APB1_CKAHB_DIV4;

使用特权

评论回复
11
和下土|  楼主 | 2023-1-31 00:20 | 只看该作者
现在我们知道,对于我的工程APB1进行了4分频,APB2进行了2分频,那么为了保证挂在APB1总线上的timer1的输入时钟为200M,那么就要选择

rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);

使用特权

评论回复
12
和下土|  楼主 | 2023-1-31 00:21 | 只看该作者
基于其它的设置,就和STM32的定时器基本没有区别了,下面代码prescaler是将定时器的时钟先进行200分频,period是计数周期值为1000一个循环,如下:
timer_initpara.prescaler         = 200-1;//预分频
timer_initpara.period            = 1000-1; //计数值

使用特权

评论回复
13
和下土|  楼主 | 2023-1-31 00:21 | 只看该作者
一个完整的代码例子
下面我们将完成一个定时器1毫秒溢出中断的程序,注意我这个的前提的APB1 = AHB/4, AHB = 200M,具体配置请看上面的描述;
//定时器初始化
void time1_init(void)
{
       
        timer_parameter_struct timer_initpara;//定时器结构体
       
        rcu_periph_clock_enable(RCU_TIMER1);//开启定时器时钟
        //因为APB1是AHB的4分频,因此定时器时钟CK_TIMERx = CK_AHB = 200m
        rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);//配置定时器时钟等于CK_AHB
       
        timer_struct_para_init(&timer_initpara);//将定时器结构体内参数配置成默认参数
    timer_deinit(TIMER1); //复位定时器
       
        /* TIMER1 configuration */
        //200M/200/1000 = 1k
    timer_initpara.prescaler         = 200-1;//预分频
    timer_initpara.alignedmode       = TIMER_COUNTER_EDGE; //边缘对齐
    timer_initpara.counterdirection  = TIMER_COUNTER_UP; //向上计数方式
    timer_initpara.period            = 1000-1; //计数值
    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);//使能自动重加载
       
        timer_interrupt_enable(TIMER1,TIMER_INT_UP);//使能溢出中断
       
        nvic_irq_enable(TIMER1_IRQn, 0, 1);//配置中断优先级
       
    /* TIMER1 enable */
    timer_enable(TIMER1);//使能定时器

}

//main函数
int main(void)
{
        nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);//配置优先级分组       
        timer1_init();
}

//中断函数
void TIMER1_IRQHandler(void)
{
    if(SET == timer_interrupt_flag_get(TIMER1,TIMER_INT_UP)){
        //用户代码
                /* clear TIMER interrupt flag */
                timer_interrupt_flag_clear(TIMER1,TIMER_INT_UP);
    }      
}

使用特权

评论回复
14
和下土|  楼主 | 2023-1-31 00:23 | 只看该作者
代码简述:

利用rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4)将定时器时钟CK_TIMERx = CK_AHB = 200m

进入定时器配置,200M首先进行200分频,然后在计数1000次触发一次中断,此时200M/200/1000 = 1k,也就是说定时器中断周期为1k,即中断时间为1ms。

使用特权

评论回复
15
和下土|  楼主 | 2023-1-31 00:24 | 只看该作者
若需要1秒中断只需要将上面程序中的

timer_initpara.period = 1000-1; //计数值

改为

timer_initpara.period = 1000000-1; //计数值

使用特权

评论回复
16
和下土|  楼主 | 2023-1-31 00:24 | 只看该作者
注意:我们都知道STM32的timer1的溢出中断是有专门的中断函数的,而GD32的timer0对标的STM32的timer1,因此GD32的timer0也有专门的溢出中断函数,而对于GD32的timer1,所有的中断共用一个TIMER1_IRQHandler函数。也有些定时器好几个定时器共用一个中断函数,在编写的时候这点要注意。

使用特权

评论回复
17
玄德| | 2023-2-28 10:30 | 只看该作者

这么好的帖子,必须顶一下。

使用特权

评论回复
18
szt1993| | 2023-3-1 15:38 | 只看该作者
说的很详细,图文解释

使用特权

评论回复
19
tpgf| | 2023-3-2 09:12 | 只看该作者
我就特别爱看寄存器的说明 配合着时钟树就比较明白了

使用特权

评论回复
20
qcliu| | 2023-3-2 09:31 | 只看该作者
请问 不是所有的定时器的溢出中断都有专门的中断函数的吗

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

103

主题

1067

帖子

0

粉丝