stm32 SysTick滴答定时器
SysTick定时器介绍
在给STM32进行编程的时候,我们在程序中会遇到有的时候需要延时,以前我们采用的是循环多次来达到延时的功能,但这样延时很不准确,而通过STM32的SysTick定时器可以让我们更加精确的进行延时操作。
SysTick定时器是一个24位的倒计数定时器,计到0时,将从 RELOAD
寄存器(下面介绍)中自动重装载定时初值。只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息,即使在睡眠模式下也能工作。
SysTick有4个相关的寄存器:
- 控制和状态寄存器: CTRL
- 自动重装载初值寄存器: LOAD
- 当前值寄存器: VAL
- 校准值寄存器: CALIB(用于校准,不常用)
控制及状态寄存器
根据下表介绍进行相关位的配置即可
位修改的技巧:
例如,NUM表示一个二进制数,要将它的第2位置1,其它位不变,则可以这样写:
NUM |= (1<<2); //使用位运算
重装载寄存器
注意这是一个24位寄存器,因此装载的最大值为 \(2^{24}-1\)
计时范围:[0, \(2^{24}-1\)]
计数方向:倒计数
当前值寄存器
看表格描述
校准值寄存器(不常用)
SysTick定时器使用
使用SysTick定时器前要导入
misc.c
文件
配置步骤
- 选择SysTick定时器的时钟源
- 设定重装载初值
- 清零定时器当前计数值
- 开启SysTick定时器
- 判断什么时候停止
- 停止后关闭计数,清零计数值
相关库函数
时钟源选择,定义在misc.c文件中
可选择的时钟源:
SysTick_CLKSource_HCLK_Div8
: AHB 8分频输出SysTick_CLKSource_HCLK
: AHB 时钟输出
/**
* @brief Configures the SysTick clock source.
* @param SysTick_CLKSource: specifies the SysTick clock source.
* This parameter can be one of the following values:
* @arg SysTick_CLKSource_HCLK_Div8: AHB clock divided by 8 selected as SysTick clock source.
* @arg SysTick_CLKSource_HCLK: AHB clock selected as SysTick clock source.
* @retval None
*/
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;
}
else
{
SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;
}
}
寄存器的定义,在 core_cm3.h
文件中
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;
中断服务函数,在 stm32f10x_it.c
文件,使用前要配置CTRL
寄存器中关于中断的位,开启中断后即可在此函数写中断处理的语句
/**
* @brief This function handles SysTick Handler.
* @param None
* @retval None
*/
void SysTick_Handler(void)
{
}
例子
用于实现精确延时us和ms,按照前面说的6个步骤:
- 选择SysTick定时器的时钟源
- 设定重装载初值
- 清零定时器当前计数值
- 开启SysTick定时器
- 判断什么时候停止
- 停止后关闭计数,清零计数值
代码太长不想看的,看后面具体函数解析
#include "SysTick.h"
static u8 fac_us=0; //代表1us延时需要计数的次数
static u16 fac_ms=0; //代表1ms延时需要计数的次数
//初始化延迟函数
//SYSTICK的时钟固定为AHB时钟的1/8
//SYSCLK:系统时钟频率
void SysTick_Init(u8 SYSCLK)
{
//1. 时钟源选择
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
fac_us = SYSCLK/8; //配置延时1us需要计数的次数, 由于时钟源为HCLK/8=9MHz, 所以SYSCLK应该选择72
fac_ms = (u16)fac_us*1000; //配置延时1ms需要计数的次数
}
/*******************************************************************************
* 函 数 名 : delay_us
* 函数功能 : us延时,
* 输 入 : nus:要延时的us数
注意:nus的值,不要大于798915us(最大值即2^24/fac_us@fac_us=21)
* 输 出 : 无
*******************************************************************************/
void delay_us(u32 nus)
{
u32 temp;
//2. 配置重装载值
SysTick->LOAD = nus*fac_us; //fac_us表示1us需要计数的次数,则nus需要计数nus*fac_us次
//3. 清空计数器
SysTick->VAL = 0x00;
//4. 启动计数(倒计数)
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //实际上SysTick_CTRL_ENABLE_Msk值为1
//5. 判断CTRL寄存器值(赋给temp)的第16位是否为1,如果是1,则计数完成
do
{
temp = SysTick->CTRL;
}while((temp&0x01)&&!(temp&(1<<16)));//循环条件:第一个表示已经启动定时器,后一个表示还没计数完成
//6. 关闭计数器,清空计数值
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭计数器,将最低位置0
SysTick->VAL = 0X00; //清空计数器
}
/*
*对系统时钟为72M的情况, 要求参数 nms<=1864ms 因为 (2^24-1)/(72/8*1000)=1864
**/
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; //清空计数器
}
函数解析
void SysTick_Init(u8 SYSCLK)
{
//1. 时钟源选择(HCLK单位为MHz)
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
//配置延时1us需要计数的次数, 由于上一行配置SysTick时钟源为HCLK/8
//而系统时钟频率==HCLK频率,所以SysTick计数(HCLK/8)次==1s,1us需要计数HCLK/(8*1000000)次
//即SYSCLK/(8*1000000)次,所以按照下面一行的写法,传入的参数SYSCLK不能写72000000(72000000是默认情况下的系统时钟),而是写72
fac_us = SYSCLK/8;
fac_ms = (u16)fac_us*1000; //配置延时1ms需要计数的次数
}
void delay_us(u32 nus)
{
u32 temp;
//2. 配置重装载值
SysTick->LOAD = nus * fac_us; //fac_us表示1us需要计数的次数,则nus需要计数nus*fac_us次
//3. 清空计数器
SysTick->VAL = 0x00;
//4. 启动计数(倒计数)
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //实际上SysTick_CTRL_ENABLE_Msk值为1
//5. 判断CTRL寄存器值(赋给temp)的第16位是否为1,如果是1,则计数完成
do
{
temp = SysTick->CTRL;
}while((temp&0x01)&&!(temp&(1<<16))); //循环条件:第一个表示已经启动定时器,后一个表示还没计数完成
//6. 关闭计数器,清空计数值
SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //将最低位置0,关闭计数器
SysTick->VAL = 0x00; //清空计数器
}
【虚拟调试注意】
使用keil进行虚拟调试时,要配置晶振频率为8MHZ,因为使用的是最最最初始的时钟源HSE=8MHZ(个人认为的,还不确定是不是真的这样),如图:
调试结果
本文来自博客园,作者:aJream,转载请记得标明出处:https://www.cnblogs.com/ajream/articles/16079889.html