SysTick定时器介绍
在给STM32进行编程的时候,我们在程序中会遇到有的时候需要延时,以前我们采用的是循环多次来达到延时的功能,但这样延时很不准确,而通过STM32的SysTick定时器可以让我们更加精确的进行延时操作。
SysTick定时器是一个24位的倒计数定时器,计到0时,将从 RELOAD
寄存器(下面介绍)中自动重装载定时初值。只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作。
SysTick定时器的时钟来源是系统时钟SYSCLK,不分频为 72MHz,8 分频为 9MHz
SysTick有4个相关的寄存器:
- 控制和状态寄存器: CTRL
- 自动重装载初值寄存器: LOAD
- 当前值寄存器: VAL
- 校准值寄存器: CALIB(用于校准,不常用)
控制及状态寄存器
根据下表介绍进行相关位的配置即可
位修改的技巧:
例如,NUM表示一个二进制数,要将它的第2位置1,其它位不变,则可以这样写:
重装载寄存器
注意这是一个24位寄存器,因此装载的最大值为 224−1
计时范围:[0, 224−1]
计数方向:倒计数
当前值寄存器
看表格描述
校准值寄存器(不常用)
SysTick定时器使用
使用SysTick定时器前要导入 misc.c
文件
配置步骤
- 选择SysTick定时器的时钟源
- 设定重装载初值
- 清零定时器当前计数值
- 开启SysTick定时器
- 判断什么时候停止
- 停止后关闭计数,清零计数值
相关库函数
时钟源选择,定义在misc.c文件中
可选择的时钟源:
SysTick_CLKSource_HCLK_Div8
: AHB 8分频输出
SysTick_CLKSource_HCLK
: AHB 时钟输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource) { assert_param(IS_SYSTICK_CLK_SOURCE(SysTick_CLKSource)); if (SysTick_CLKSource == SysTick_CLKSource_HCLK) { SysTick->CTRL |= SysTick_CLKSource_HCLK; } else { SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8; } }
|
寄存器的定义,在 core_cm3.h
文件中
1 2 3 4 5 6 7 8
| typedef struct { __IO uint32_t CTRL; __IO uint32_t LOAD; __IO uint32_t VAL; __I uint32_t CALIB; } SysTick_Type;
|
中断服务函数,在 stm32f10x_it.c
文件,使用前要配置CTRL
寄存器中关于中断的位,开启中断后即可在此函数写中断处理的语句
1 2 3 4 5 6 7 8
|
void SysTick_Handler(void) { }
|
例子
用于实现精确延时us和ms,按照前面说的6个步骤:
- 选择SysTick定时器的时钟源
- 设定重装载初值
- 清零定时器当前计数值
- 开启SysTick定时器
- 判断什么时候停止
- 停止后关闭计数,清零计数值
代码太长不想看的,看后面具体函数解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| #include "SysTick.h"
static u8 fac_us=0; static u16 fac_ms=0;
void SysTick_Init(u8 SYSCLK) { SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); fac_us = SYSCLK/8; fac_ms = (u16)fac_us*1000; }
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(u16 nms) { u32 temp; SysTick->LOAD=(u32)nms*fac_ms; 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; }
|
函数解析
1 2 3 4 5 6 7 8 9 10
| void SysTick_Init(u8 SYSCLK) { SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); fac_us = SYSCLK/8; fac_ms = (u16)fac_us*1000; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| 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; }
|
虚拟调试注意
使用keil进行虚拟调试时,要配置晶振频率为8MHZ,因为使用的是最最最初始的时钟源HSE=8MHZ(个人认为的,还不确定是不是真的这样),如图:
调试结果