SysTick—系统定时器
SysTick—系统定时器有 4 个寄存器,简要介绍如下。在使用 SysTick 产生定时的时候,
只需要配置前三个寄存器,最后一个校准寄存器不需要使用。
SysTick 寄存器汇总
寄存器名称 | 寄存器描述 |
---|---|
CTRL | SysTick 控制及状态寄存器 |
LOAD | SysTick 重装载数值寄存器 |
VAL | SysTick 当前数值寄存器 |
CALIB | SysTick 校准数值寄存器(不常用到) |
SysTick 控制及状态寄存器
位段 | 名称 | 类型 | 复位值 | 描述 |
---|---|---|---|---|
16 | COUNTFLAG | R/W | 0 | 如果在上次读取本寄存器后, SysTick 已经计到了 0,则该位为 1。 |
2 | CLKSOURCE | R/W | 0 | 时钟源选择位, 0=AHB/8, 1=处理器时钟 AHB |
1 | TICKINT | R/W | 0 | 1=SysTick 倒数计数到 0 时产生 SysTick 异常请求, 0=数到 0 时无动作。也可以通过读取COUNTFLAG 标志位来确定计数器是否递减到0 |
0 | ENABLE | R/W | 0 | SysTick 定时器的使能位 |
功能框图
SysTick定时时间计算
- t = reload * ( 1/clk ) Clk = 72M时,
- t = (72) *(1/ 72 M )= 1US
- Clk = 72M时, t = (72000) *(1/ 72 M )= 1MS
时间单位换算:
1s = 1000ms = 1000 000 us = 1000 000 000ns
编程要点
1、设置重装载寄存器的值
2、清除当前数值寄存器的值
3、配置控制与状态寄存器
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* 如果ticks超过2^24函数不执行*/
SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* 设置reload寄存器的值 (即延时时间)*/
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* 配置系统中断的优先级,默认为最低的(1<<4)-1=15 */
SysTick->VAL = 0; /* Load the SysTick Counter Value */
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |// 设置系统定时器的时钟源为 AHBCLK=72M
SysTick_CTRL_TICKINT_Msk |//使能中断(SysTick 倒数计数到 0 时产生 SysTick 异常请求)
SysTick_CTRL_ENABLE_Msk; // 使能systick /* Enable SysTick IRQ and SysTick Timer */
return (0); /* Function successful */
}
系统定时器的中断优先级
static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
if(IRQn < 0) { //内核外设<0
SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for Cortex-M3 System Interrupts */
else {
NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for device specific Interrupts */
}
用固件库编程的时候我们只需要调用库函数SysTick_Config()即可,形参 ticks 用来设置重装载寄存器的值,最大不能超过重装载寄存器的值 2^24,当重装载寄存器的值递减到 0的时候产生中断,然后重装载寄存器的值又重新装载往下递减计数,以此循环往复。紧随其后设置好中断优先级,最后配置系统定时器的时钟等于AHBCLK=72M,使能定时器和定时器中断,这样系统定时器就配置好了,一个库函数搞定。
void SysTick_delayms(uint32_t ms)
{
SysTick_Config(72000);//72/72M(时钟源)=1us 72000/72M(时钟源)=1ms
for(i=0;i<ms;i++)
{
while(!(SysTick->CTRL&(1<<16)));
}
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
}
注意点:
- 在 NVIC_SetPriority()函数中出现了(uint_32)(-1) & 0xF)其中uint_32(-1)=0xFFFFFFFF;
- 寄存器的位数是从第0位开始计数的所以<<16是移动到了位16。
- 计算左移的大小(1 <<n)=(2^n-1)同理:(N <<n)=N*(2 ^n-1)