1.Systick知识
1.Systick是什么
是一个简单的定时器(系统滴答定时器),通常用于延时函数,可以节省CPU资源
24位的倒计速定时器,从RELOAD寄存器中自动装载定时器初值
还被绑定在NVIC中,会产生Systick异常(15)
Systick的中断优先级也可以设置
2.Systick寄存器
1.Systick寄存器
CTRL(控制和状态寄存器)
LOAD(自动重装载除值寄存器)
VAL(当前指寄存器)
CALIB(校准寄存器)
2.Systick寄存器详解
1.CTRL(控制和状态寄存器)
位0,使能位
位1,计数到0是否产生中断请求
位2,时钟源选择,外部时钟是HCLI(AHB总线时钟)的8分频,内部时钟是HCLK
位16,标志位,是否到0
配置函数
HAL_SYSTICK_CLKSourceConfig(uint32_t CLKSource) //选择外部或内部时钟
uint32_t SysTick_Config(uint32_t ticks) //配置经过多少ticks发生中断
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
{
return (1UL); /* Reload value impossible 不能超过24位*/
}
SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register load装入值*/
NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* 优先级set Priority for Systick Interrupt */
SysTick->VAL = 0UL; /* Load the SysTick Counter Value */
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* 设置内核时钟源,开启中断,使能SysTick,Enable SysTick IRQ and SysTick Timer */
return (0UL); /* Function successful */
}
2.LOAD(自动重装载除值寄存器)
每次计数到0,会把load的值放到但前值寄存器
3.VAL(当前指寄存器)
读取倒计数器当前的值当前的值
4.CALIB(校准寄存器)
3.Systick延时函数
1.使用中断的方法实现
1000个systick周期发生中断,中断服务函数不断递减,一直减到0,时间就到了
2.使用查询的方法实现
static u32 fac_us=0; //us延时倍乘数
void delay_init(u8 SYSCLK)
{
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);//SysTick频率为HCLK(180MHZ)
fac_us=SYSCLK; //不论是否使用OS,fac_us都需要使用,1us需要180个SYSTICK周期
}
void delay_us(u32 nus)
{
u32 ticks;
u32 told,tnow,tcnt=0;
u32 reload=SysTick->LOAD; //LOAD的值
ticks=nus*fac_us; //需要的节拍数
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; //时间超过/等于要延迟的时间,则退出.
}
};
}
//延时nms
//nms:要延时的ms数
void delay_ms(u16 nms)
{
u32 i;
for(i=0;i<nms;i++) delay_us(1000);
}
delay_us(u32 nus)函数
就是先输入nus(us),1us需要180个SysTick周期,故需要180nus个SysTick周期
然后先记下LOAD,就是每次溢出到0恢复的值
在设立两个值,一个用于存当前val的值tnow,一个用于存上次val的值told(val是SysTick定时器的不断减1时候所处的位置)
如果当前的小于上次的,代表一直在减少,没有溢出,那么经过的SysTick周期周期数为told-tnow
当前的大于上次的,那么代表溢出了(因为到0,会重新装上load的值,是比当前的大的),那么经过的SysTick周期周期数为load-tnow+told
不断改变当前val的数值,再加上经过的SysTick周期的总和,如果超过180nus,则代表延时结束