SysTick 定时器是什么
CM3 内核处理器,内部包含了一个 SysTick 定时器,SysTick 是一个 24 位的向下递减的计数定时器,当计数值减到 0 时,将从 RELOAD 寄存器中自动重装载定时初值,开始新一轮计数。只要不把它在 SysTick 控制及 状态寄存器中的使能位清除,就永不停息。SysTick 定时器常用于操作系统的时钟(FreeRTOS),是操作系统的心脏。
由此图可以看出SysTick属于Cortex-M3处理器的一部分,包含在NVIC(嵌套向量中断控制器)里面,所以和其他片上外设(GPIO,TMI)不同,而是一个内核外设。SysTick属于一个硬件定时器,并且也可以产生中断。
参考手册对其介绍:
在STM32F10xxx参考手册中对其介绍较少(因为SysTick 属于内部定时器,所以要在ARM的官方手册中才能有详细记录)
STM32F10xxx Cortex-M3编程手册对于其介绍
Cortex-M3权威指南对其介绍:
Systick寄存器:
包括四个位寄存器:
SysTick->CTRL(地址:
0xE000_E010
)
SysTick->LOAD
(地址:
0xE000_E014
)
SysTick->VAL
(地址:
0xE000_E018
)
SysTick->CALIB
(地址:
0xE000_E01C
)
时钟源选择:
可选择8分频外部时钟或者不分频(内部时钟)
选择时钟源的位置为表8.9中的CLKSOURCE位此位为 1 的时候 SysTick 的时钟内部时钟(也就是系统的主频,),此位为 0 的时候 SysTick 时钟为 AHB/8(AHB 的八分频)也就是外部时钟的八分频,但是建议选择外部时钟源,因为外部时钟更加精准可靠。
如果外部时钟源为72Mhz,那么经8分频后就是9Mhz,1s的时钟周期个数为9000 000,1ms的时钟周期个数为9000,1us的时钟周期个数为9,也就是一个计数周期后,经过了1/9us。
利用SysTick实现延时函数delay
没有操作系统时
/**
* @brief 微秒级延时
* @param xus 延时时长,范围:0~233015
* @retval 无
*/
void Delay_us(uint32_t xus)
{
SysTick->LOAD = 72 * xus; //设置定时器重装值
SysTick->VAL = 0x00; //清空当前计数值
SysTick->CTRL = 0x00000005; //设置时钟源为HCLK,启动定时器
while(!(SysTick->CTRL & 0x00010000)); //等待计数到0
SysTick->CTRL = 0x00000004; //关闭定时器
}
/**
* @brief 毫秒级延时
* @param xms 延时时长,范围:0~4294967295
* @retval 无
*/
void Delay_ms(uint32_t xms)
{
while(xms--)
{
Delay_us(1000);
}
}
由于在有操作系统(FreeRTOS,UCOSII。。。。),时,SysTick是作为“心跳”(系统节拍),不能随便被打断,所以此时SysTick里面的值不能被随便修改,所以为了方便使用,我们使用时钟摘取法制作延时函数。
参考正点原子(有无操作系统均可使用):
void delay_us(uint32_t nus)
{
uint32_t ticks;
uint32_t told, tnow, tcnt = 0;
uint32_t reload = SysTick->LOAD; /* LOAD 的值 */
ticks = nus * g_fac_us; /* 需要的节拍数 */
#if SYS_SUPPORT_OS /* 如果需要支持 OS */
delay_osschedlock(); /* 锁定 OS 的任务调度器 */
#endif
told = SysTick->VAL; /* 刚进入时的计数器值 */
while (1)
{
tnow = SysTick->VAL;
if (tnow != told)
{
if (tnow < told)
{
tcnt += told - tnow;
/* 这里注意一下 SYSTICK 是一个递减的计数器就可以了 */
}
else
{
tcnt += reload - tnow + told;
}
told = tnow;
if (tcnt >= ticks)
{
break; /* 时间超过/等于要延迟的时间,则退出 */
}
}
}
#if SYS_SUPPORT_OS /* 如果需要支持 OS */
delay_osschedunlock(); /* 恢复 OS 的任务调度器 */
#endif
}