本文主要是介绍[9]STM32 SysTick嘀嗒定时器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
前言
这次主要讲了STM32 systick嘀嗒定时器和相关函数的应用,通过systick实现计时,但实际上正点原子的开发板已经把systick封装起来了用的自己的delay函数,反而更方便,这篇博客主要讲一下systick的相关寄存器和库函数,以及systick的应用。
SysTick基础知识
SysTick 是一个 24 位的倒计数定时器,当计数到 0 时,将从RELOAD 寄存器中自动重装载定时初值,开始新一轮计数,这是Systick的主要功能,就是一个无限循环的一个计数器。
SysTick 有四个寄存器分别是CTRL(SysTick控制及状态寄存器),LOAD(SysTick重装载数值寄存器),VAL(SysTick当前数值寄存器),CALIB(SysTick校准数值寄存器),因为systick是内核级别的,所以可以参考《Cortex-M3权威指南-中文》第八章最后一个小节,里面对怎么配置寄存器有详细的介绍。
SysTick寄存器
typedef struct
{__IO uint32_t CTRL; /*!< Offset: 0x00 SysTick Control and Status Register */__IO uint32_t LOAD; /*!< Offset: 0x04 SysTick Reload Value Register */__IO uint32_t VAL; /*!< Offset: 0x08 SysTick Current Value Register */__I uint32_t CALIB; /*!< Offset: 0x0C SysTick Calibration Register */
} SysTick_Type;
如下图所示是M3权威指南里面的表格。
对CTRL寄存器第0位是使能,第1位就是中断,第2位是选择时钟源,外部时钟源是HCLK(AHB总线时钟)的1/8,而内部时钟源就是HCLK,具体可参考[7]STM32基础知识-时钟系统里面的时钟框图。而16位是检测Systick定时器是否归0
对LOAD寄存器,顾名思义就是在SysTick定时器计时完之后对其进行装载一个数,使其继续计时。
对VAL寄存器,就是清空计数器,在每次进行计数时一般都要清空计数器再进行装载
SysTick相关函数
**SysTick_CLKSourceConfig()**函数主要是配置CTRL寄存器,对Systick时钟源进行选择
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)
{/* Check the parameters */assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource));//有效性判断if (SysTick_CLKSource == SysTick_CLKSource_HCLK){SysTick->CTRL |= SysTick_CLKSource_HCLK; //对第2位寄存器进行判断,选择时钟源}else{SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;}
}
**SysTick_Config(unit32_t ticks)**函数用于初始化systick,时钟为HCLK,并开启中断。ticks表示两次中断之间的计数间隔。
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{ if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); / /* Reload value impossible(ticks有效性判断,因为systick是一个24位计数器) */SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register (装载数是ticks-1,比如计数器是从1000计数到0,在计数到0之后装载999到计数器中)*/NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */SysTick->VAL = 0; /* Load the SysTick Counter Value ()*/SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */return (0); /* Function successful */
}
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--;//共200ms}
}//是在stm32f10x_it.c定义好的”void SysTick_Handler(void){}”就差填里面的函数体,中断的时候自动调用。int main(void){ …if (SysTick_Config(SystemCoreClock / 1000)) //systick时钟为HCLK(时钟72MHz,中断频率为时钟频率的1/1000),中断时间间隔1ms{while (1);}while(1){ Delay(200);//200ms… }
}
正点原子的Delay函数
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
#if SYSTEM_SUPPORT_OS //如果需要支持OS.reload=SystemCoreClock/8000000; //每秒钟的计数次数 单位为K 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(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; //清空计数器
}
//延时nms
//注意nms的范围
//SysTick->LOAD为24位寄存器,所以,最大延时为:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLK单位为Hz,nms单位为ms
//对72M条件下,nms<=1864
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; //清空计数器
}
思路还是比较简单的,就是用函数封装配置寄存器的操作,在之后的程序里面就可以直接调用写好的delay_ms()或者delay_us()的函数进行延时控制了。
参考资料
《STM32F1开发指南-库函数版本》5.1小节
《Cortex-M3权威指南-中文》第八章最后一个小节
这篇关于[9]STM32 SysTick嘀嗒定时器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!