SysTick定时器
SysTick定时器,是一个简单的定时器,对于CM3、CM4内核的芯片都有SysTick定时器。SysTick 是一个 24 位的倒计数定时器,当计数到 0 时,将从RELOAD 寄存器中自动重装载定时初值,开始新一轮计数。只要不把它在 SysTick 控制及状态寄存器中的使能位清除(不把Systick定时器关掉),就永不停息。SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15)。在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。例如,为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。
作用:
Systick定时器常用来做延时,或者实时系统的心跳时钟。这样可以节省MCU资源,不用浪费一个定时器。比如:UCOS中,分时复用,需要一个最小的时间戳,一般在STM32+UCOS系统中,都采用Systick做UCOS的心跳时钟。
Systick寄存器:
- CLRL寄存器:Systick控制和状态寄存器
- LOAD寄存器:Systick自动重装载寄存器
- VAL寄存器:Systick当前值寄存器
- CALIB寄存器:Systick校准值寄存器
Systick控制和状态寄存器-CTRL
对于STM32,外部时钟源是HCLK(AHB总线时钟的1/8)内核时钟是HCLK时钟。
配置函数:Systick_CLKSourceConfig();
Systick重装载数值寄存器-LOAD(24位)
Systick当前值定时器-VAL
Systick校准寄存器-CAL
固件库中的Systick相关函数:
SysTick_CLCSourConfig()//Systick时钟源选择,在misc.c文件中。
SysTick_config(uint32_t ticks)//初始化systick时钟为HCLK,并开启中断,在core_cm3/core_cm4文件中。
Systick中断服务函数:
void SysTick_Handler(void);
用中断的方式实现delay延时:(比较耗费资源)
static __IO uint32_t TimingDelay;
void Delay(__IO uint32_t nTime)
{ TimingDelay = nTime;while(TimingDelay != 0);
}
void SysTick_Handler(void)
{if (TimingDelay != 0x00) { TimingDelay--;}
}int main(void){ …if (SysTick_Config(SystemCoreClock / 1000)) //systick时钟为HCLK(系统时钟),中断时间间隔1ms,SysTick_Config()这个函数是设置两次中断之间的时间。{while (1);}while(1){ Delay(200);//200ms… }
}
SysTick_Config函数:
SysTick_Config的参数,其实就是一个时钟次数,叫systick重装定时器的值。意思就是我要多少个1/fosc 时间后中断一下。根据学过的物理中的时间与频率的公式:fosc=1/T T=1/fosc ,fosc为Systick的频率。如果STSystick时钟频率为:72MHz,每次的时间为:T=1/72MHz。1秒钟为:1/(每次的时间)=1/(1/72MHz)=72 000 000次。1MHz是:1000 000。反过来讲。SysTick_Config(72000)代表:72000*(1/72MHz)=1/1000=1(ms)。即定时为1ms。如果需要1S则可以通一设置一个全局变量,然后定初值得为1000,这样每个systick中断一次,这个全局变量减1,减到0,即systick中断1000次,时间为:1ms1000=1S。从而实现1S的定时。 因为SysTick定时器是:24位的,最大定时时间为:2的24次方(1/72MHz)的时间,这里Systick频率为:72MHz的情况下。
delay_init()函数:
static u8 fac_us=0;//us延时倍乘数
static u16 fac_ms=0;//ms延时倍乘数,在ucos下,代表每个节拍的ms数
void delay_init()
{
#if SYSTEM_SUPPORT_OS //如果需要支持OS.u32 reload;
#endifSysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//选择外部时钟 HCLK/8fac_us=SystemCoreClock/8000000;//为系统时钟的1/8 相当于72000000/8000000等于九//一次是1/systick的时钟频率就是1/9 us,fac_us相当于1us,这里的将9赋值给他是给寄存器LOAD计数用的,从9到1就是1us
#if SYSTEM_SUPPORT_OS //如果需要支持OS.reload=SystemCoreClock/8000000;//每秒钟的计数次数 单位为M reload*=1000000/delay_ostickspersec;//根据delay_ostickspersec设定溢出时间//reload为24位寄存器,最大值:16777216,在72M下,约合1.86s左右 fac_ms=1000/delay_ostickspersec;//代表OS可以延时的最少单位 SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;//开启SYSTICK中断SysTick->LOAD=reload; //每1/delay_ostickspersec秒中断一次 SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK #elsefac_ms=(u16)fac_us*1000;//非OS下,代表每个ms需要的systick时钟数
#endif
}
void delay_us()函数:
void delay_us(u32 nus)
{ u32 temp; SysTick->LOAD=nus*fac_us; //时间加载 SysTick->VAL=0x00; //清空计数器SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数 do{temp=SysTick->CTRL;}while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达 SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器SysTick->VAL =0X00; //清空计数器
}
void delay_ms()函数:
void delay_ms(u16 nms)
{ u32 temp; SysTick->LOAD=(u32)nms*fac_ms; //时间加载(SysTick->LOAD为24bit)SysTick->VAL =0x00; //清空计数器SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数 do{temp=SysTick->CTRL;}while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达 SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器SysTick->VAL =0X00; //清空计数器
}
- T=1/1KHZ=1ms=1微秒=1/1000秒
- T=1/1MHZ=1us=1微秒=1/1000000秒
- 10MHz=1/10us=0.1us
- 20MHz=1/20us=0.05us
- 50MHz=1/50us=0.02us
- 1GHz=1ns=1纳秒=1/1000000000秒
- 1MHZ=1000KHZ=1000000HZ
- 1GHZ=1000MHZ