滴答定时器介绍
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.001s
NVIC_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 = 200
2
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灭。