STM32的Systick滴答定时器及延时函数编写
一、Systick滴答定时器是什么?
Systick定时器就是系统滴答定时器,一个24 位的倒计数定时器,计到0 时,将从RELOAD 寄存器中自动重装载定时初值。只要不把它在SysTick 控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作。
定时器既是在规定时间之后执行某个操作。
Systick定时器常用来做延时,或者实时系统的心跳时钟。这样可以节省MCU资源,不用浪费一个定时器。比如UCOS中,分时复用,需要一个最小的时间戳,一般在STM32+UCOS系统中,都采用Systick做UCOS心跳时钟。
------------------------------------------------------------------------------------------------------------------------------------------------------
二、Systick一般用来做延时,精确延时。
一共4个Systick寄存器
CTRL SysTick 控制和状态寄存器
LOAD SysTick 自动重装载初值寄存器
VAL SysTick 当前值寄存器
CALIB SysTick 校准值寄存器
------------------------------------------------------------------------------------------------------------------------------------------------------
三、systick定时器原理
这个定时器是设置一个初值,然后这个初值减数到0,就是定时完成,完成之后可以产生中断,也可以不使用中断。
第0位是使能位,可以使能或者使能定时器
第1位是使能中断位,减数结束之后是否产生中断。
第2位是时钟选择位,可以选择外部的或者内部时钟作为时钟源。
第16位是标志位,减数到0之后该位被置位1,读取过后自动清清零。
------------------------------------------------------------------------------------------------------------------------------------------------------
四、uSysTick 重装载数值寄存器-LOAD
当当前值寄存器减数到0,自动会将把这个RELOAD的值赋给当前值寄存器。
if(VAL == 0)
VAL = RELOAD
------------------------------------------------------------------------------------------------------------------------------------------------------
五、SysTick 当前值寄存器- VAL
VAL就是从初值(RELOAD)一直减一,倒数到0的时候,重新将初值(RELOAD)赋给VAL。
------------------------------------------------------------------------------------------------------------------------------------------------------
六、滴答定时器的实现
对于STM32,外部时钟源是HCLK(AHB总线时钟)的1/8内核时钟是HCLK时钟
1、选择时钟源
SysTick_CLKSourceConfig();//选择时钟源 misc.c文件中
SysTick_Config(uint32_t ticks) //初始化systick,时钟为HCLK,并开启中断 core_cm4.h文件中
2、编写延时函数
3、设置中断优先级分组
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_2);
一般使用中断都需要在最开始对我们的优先级进行分组,分好之后再进行优先级的设置。
尽量不要在同一个程序里面频繁的改变分组,频繁切换分组可能会使程序出现不可预料错误。
------------------------------------------------------------------------------------------------------------------------------------------------------
七、用中断的方式实现delay延时
Systick中断服务函数:void SysTick_Handler(void);
-----------------------------------------------------------------------------------------------------------------
注意:
uCortex-M系统中,Systick代码可以通用。
如果使用中发现延时不一致,问题一般都是因为不同内核时钟不一样而已。修改ticks值即可。
------------------------------------------------------------------------------------------------------------------------------------------------------
参考代码如下:
void init_delay(void)
{
/*我们外部晶振为8MHz,然后倍频到168M,那么Systick时钟即为21M,也就是Systick的计数器
VAL每减1就代表过了1/21us*/
//1.选择时钟源(选择外部时钟)
//外部时钟要/8,内部始终不用
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
}
//2.编写延时函数
//最大延时不超过798.915ms,即(2^24)/21/1000
void delay_us(u32 nus)
{
u32 temp = 0;
//1、实现1us*nus的延时
//21外是外部时钟频率,如果选择内部时钟就是168M/8
SysTick->LOAD = 21*nus;//设置自动装载值为21(1us)
SysTick->VAL = 0x00;//设置当前初值为0
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; // 开启(使能)计数:使能SysTick定时器
do
{
//读取控制寄存器
temp = SysTick->CTRL;
}while(!(temp & (1<<16)));//等待计数时间到达(位16)
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; // 关闭(失能)计数
SysTick->VAL = 0x00;//再设置当前初值为0,重置VAL
}
void delay_ms(u32 nms)
{
u32 temp = 0;
//1、实现1us*nus的延时
SysTick->LOAD = 21000*nms;//设置自动装载值为21(1us)
SysTick->VAL = 0x00;//设置当前初值为0
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; // 开启(使能)计数
do
{
//读取控制寄存器
temp = SysTick->CTRL;
}while(!(temp & (1<<16)));
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; // 关闭(失能)计数
SysTick->VAL = 0x00;//再设置当前初值为0
}
void delay_s(u32 s)
{
while(s--)
{
delay_ms(500);
delay_ms(500);
}
}
下一篇: java LinkedList的实例详解