STM32:SysTick详解
写在最前
本文是个人学习Stm32时所做笔记,没有写过C51,但学校学过 微机原理 ,但没学好,实验套件是正点原子Stm32zet6精英板,参考资料为正点原子所提供,本文所涉及代码均使用固件库。本文供自己日后需要时复习所用,同时希望可以给有需要的小伙伴给予帮助。
本文使用滴答定时器实现精准延时。
才疏学浅还望不吝指正!
一、滴答定时器(SysTick)
Cortex‐M3处理器内部包含了一个简单的定时器。因为所有的CM3芯片都带有这个定时
器,软件在不同 CM3器件间的移植工作得以化简。该定时器的时钟源可以是内部时钟(FCLK,
CM3上的自由运行时钟),或者是外部时钟(CM3处理器上的STCLK信号),具体需要检视
芯片的器件手册来决定选择什么作为时钟源。
SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15)。SysTick定时器能产生中断,在中断向量表中有它一席之地。
注:摘自Cortex-M3权威指南
简言之,SysTick定时器可以选择不同的时钟源,可以产生中断,并且SysTick定时器是一个倒计数的计数器,每隔一个时钟周期计数值减一,计数至0后重新从计数初值处开始倒计数。
例如:计数初值为100,经过一个时钟周期后,计数值减一,即99,98,97……1,0;计数至0后,又重新开始从100开始倒计数至0。
可以借此做精准延时。
二、SysTick的组成
SysTick包含四个寄存器,都是24位的寄存器,分别是:
>SysTick控制及状态寄存器 -- 0xE000 E010
>
>SysTick重装载寄存器 -- 0xE000 E014
>
>SysTick当前值寄存器 -- 0xE000 E018
>
>SysTick校准值寄存器 -- 0xE000 E01C
它们的功能如下:
注:摘自Cortex-M3权威指南
三、SysTick实现精准延时
3.1 SysTick编程步骤
-
配置SysTick时钟源
固件库函数:SysTick_CLKSourceConfig( );
头文件:misc.h
参数:
SysTick_CLKSource_HCLK_Div8 –> 系统时钟 HCLK的8分频
SysTick_CLKSource_HCLK –> 系统时钟 HCLK
-
配置SysTick的重装载值和清空计数值
重装载值寄存器是一个24位的寄存器,在设置重装载值时,重装载值不能超过2^24 – 1
(1)使用结构体SysTick_Type进行设置,该结构体在core_cm3.h中声明,声明如下:
(2)在core_cm3.h中,将 (SysTick_Type *) define 为SysTick,因此可以这样使用:
SysTick->CTRL |= 0x01; //使能SysTick定时器
在设置重装载值时,重装载值不能超过2^24 – 1
-
开启SysTick定时器
SysTick->CTRL |= 0x01; //使能SysTick定时器
3.2 延时初始化
设置SysTick的时钟源,若系统时钟为72MHz,经过8分频后,SysTick的时钟为9MHz,也就是说每计数一次需要的时间为 T = 1/(9MHz),换算一下,即T = 1/9 us,换言之:延时 1 微妙,需要计数9次,因此微妙级别的倍频因子fac_us即等于9,为了可移植性,fas_us = (系统内核时钟频率) / 8000000,毫秒级别的倍频因子fac_ms = 1000*fac_ms即可。
void delay_init()
{
/* 配置时钟源 --> 72MHz / 8 = 9MHz,
* 滴答定时器每计数一次所需时间为 T = 1/(9MHz) s,即 1us = 10^(-6)s ,
* T = (1/9) * 10^(-6) s = 1/9 us , 即每计数一次的时间为1/9微秒
* 换言之,系统时钟频率为72MHz时,1us需要计数9次
*/
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
/* fac_us 和 fac_ms 是定义的全局变量,是倍频因子*/
fac_us = SystemCoreClock / 8000000;
fac_ms = 1000 * fac_us;
}
3.3 微妙级延时实现
SysTick时钟频率为9MHz时,要延时10微秒,即传入的参数 us = 10,而计数一次需要的时间是1/9 微秒,因此计数初值需要设置为 10/(1/9);这里fac_us实际上是延时1微秒需要计数的次数,延时10微妙,需要计数10*fac_us次,即计数重装载值为10 * fac_us。
void delay_us(unsigned int us)
{
unsigned int temp = 0;
/*1us需要计数9次,计数初值为9*/
/*设置重装载值*/
SysTick->LOAD = fac_us * us;
/*当前值寄存器清0,即清空计数器*/
SysTick->VAL = 0x00;
/*滴答定时器控制寄存器,使能滴答定时器*/
SysTick->CTRL |= 0x01;
do
{
/*获取控制寄存器的当前状态*/
temp = SysTick->CTRL;
}while((temp & 0x01) && !(temp & (0x01 << 16)));
SysTick->CTRL &= 0x00;
SysTick->VAL = 0x00;
}
3.4 毫秒级延时实现
由于SysTick只提供了一个24位的倒计数寄存器,因此计数初值不能超过2^24-1,即 fas_ms * ms不能超过2^24 – 1。
void delay_ms(unsigned int ms)
{
unsigned int temp = 0;
/*设置重装载值*/
if(fac_ms * ms <= ((0x01 << 24) - 1))
{
SysTick->LOAD = fac_ms * ms;
}
else
{
return ;
}
/*设置重装载值*/
SysTick->VAL = 0x00;
/*滴答定时器控制寄存器,使能滴答定时器*/
SysTick->CTRL |= 0x01;
do
{
/*获取控制寄存器的当前状态*/
temp = SysTick->CTRL;
}while((temp & 0x01) && !(temp & (0x01 << 16)));
SysTick->CTRL &= 0x00;
SysTick->VAL = 0x00;
}