滴答定时器介绍
RISC-V处理器内部包含了一个简单的定时器SysTick,SysTick定时器可用作标准的下行计数器,是一个64位向上计数器,有自动重新装载能力,可屏蔽系统中断发生器,这样就方便了程序在不同的器件之间的移植。SysTick定时器可用于操作系统,提供系统必要的时钟节拍,为操作系统的任务调度提供一个有节奏的“心跳”。
RCU 通过 AHB 时钟(HCLK)8 分频后作为 RISC-V系统定时器(SysTick)的外部时钟。通过对 SysTick 控制和状态寄存器的设置,可选择上述时钟或 AHB(HCLK)时钟作为 SysTick 时钟。
关于系统时钟的介绍可参考用户手册的第93页。输入的时钟默认为160MHz。 需要注意的是,滴答定时器里的时钟源是SOC CLK,SOC CLK并不等于主频(CPU CLK),而是由主频除以一个预分频系数得到的。这个预分频系数可以通过寄存器SysTimer_MTIMECFGR的CLKDIV位来设置,其默认值是4。因此,SOC CLK的实际频率是160MHz / 4 = 40MHz,而不是160MHz。SOC CLK的频率就是滴答定时器实际上的频率。
SysTick定时器设定比较值并使能之后,每经过1个系统时钟周期,计数值就加1,减到0时,SysTick计数器自动重新装载初值并继续计数,同时内部的COUNTFLAG标志位被置位,触发中断(前提开启中断)。
滴答定时器寄存器
在 core_feature_timer.h 中有关SysTick寄存器的介绍,可查看其定义,如图所示。
关于寄存器的配置在core_feature_timer.h下的SysTick_Config函数中已经写好了,如图所示,感兴趣的可以去研究一下。
滴答定时器配置
在systick.c中找到systick_config()这个函数,如图所示。
SystemCoreClock / 4000 是放入重装载寄存器中的值。以系统时钟为160MHz为例,重装载值就为160MHz/4000=40,000,即每振荡40000次就产生一个中断。滴答定时器时钟为40Mhz,1秒振荡40M次,那么每计数一次时钟为 1 / 40 000 000 s 的时间,那么计数SystemCoreClock / 4000 个时钟的时间就是
(SystemCoreClock / 4000) * (1 / 40 000 000) = 40,000 / 40 000 000 = 0.001sNVIC_SetPriority(SysTick_IRQn, 0x00U);是开启中断,每当定时1ms时间到就会进入到中断函数SysTick_Handler里面,所以每进入一次中断就是1ms,如果我们定时5ms,只需要进入5次中断即可。
关于定时时间的设置,可以参考这个公式:
SetValue = SystemCoreClock / (time * systickCLK)- SystemCoreClock:主控频率默认
160MHz; - systickCLK:滴答定时器频率,为主控频率的
4分频率,默认40MHz; - time:要设置的时间,单位为秒;
- SetValue:要设置的滴答定时器比较值;
例如设置滴答定时器20毫秒进行中断,带入公式:
SetValue = 160,000,000 / (0.02 * 40,000,000)
SetValue = 160,000,000 / 800,000
SetValue = 2002
3
因此在代码中修改为200即可。
SysTimer_SetCompareValue(SystemCoreClock / 200);滴答定时器使用
GD32官方也给我们写好了延时1ms的函数,void delay_1ms(uint32_t count),有一个参数count,这个就是我们要延时的时间的ms数,延时1ms就是 delay_1ms(1) , 延时 1s 就是 delay_1ms(1000)。需要注意的是这个延时是阻塞延时,在延时的时间里一直在等待,比较浪费系统资源,慎用。
滴答定时器延时实验
前面我们学习了如何去使用滴答定时器,下面我们就用滴答定时器的延时去实现LED闪烁1s间隔。其实很简单,就是先让LED引脚输出高电平,然后调用 delay_1ms(1000) ,让其维持LED输出高电平一秒时间,再让LED引脚输出低电平,再调用delay_1ms(1000),最后在 while(1) 函数里调用即可。
关于这一章节的代码,可以在开发板资料/03 - 软件资料/代码例程/里面的003滴答定时器灯闪烁。
下载中心跳转📦
资料下载中心:点击跳转🚀
烧写我们的代码之后,可以看到开发板LED1将会1s亮1s灭。