前言
SysTick 比起那些 TIM 定时器可以说简单多啦~~~~~哥的心情也好了不少, 嘎嘎!!
ARM Cortex-M3 内核的处理器内部包含了一个 SysTick 定时器,它是一个24 位的倒计数定时器,注意,是倒计数!
当计到 0 时它就会从 LOAD 寄存器中自动重装载定时初值。只要不把 CTRL 寄存器中的 ENABLE 为清 0,它就永不停息!
遗憾的是,SysTick 定时器在《STM32 参考手册》里一个屁都没放,只有在《ARM Cortex-M3 技术参考手册》和《ARM Cortex-M3 权威指南》才找到相关寄存器的介绍。
一、SysTick 的时钟来源
我们先来看看 STM32 的时钟树
The RCC feeds the Cortex System Timer (SysTick) external clock with the AHB clock(HCLK) divided by 8.
The SysTick can work either with this clock or with the Cortex clock(HCLK), configurable in the SysTick Control and Status Register.
上面这段话的意思是,SysTick的时钟来源可以是HCLK的8分频或就是HCLK,
具体是哪种可通过配置"控制和状态寄存器(CTRL)"来选择。
二、SysTick的寄存器简介
SysTick的寄存器一共有4个。
控制和状态寄存器CTRL(复位值0x00000000)
位段 | 名称 | 类型 | 描述 |
16 | COUNTFLAG | 只读 | 计数到0时置1;读取该位将清0 |
2 | CLKSOURCE | 可读可写 | 时钟来源 0=HCLK/8;1=HCLK |
1 | TICKINT | 可读可写 | 1=计数到0时产生SysTick异常请求 |
0 | ENABLE | 可读可写 | 使能位,即定时器的开关,1有效 |
重装值寄存器LOAD(复位值不可预测)
位段 | 名称 | 类型 | 描述 |
23:0 | RELOAD | 可读可写 | 当计数到0时将被重装载的值 |
当前值寄存器VAL(复位值不可预测)
另外还有一个校准值寄存器CALIB,暂时用不到,先不刁它!
三、SysTick的库函数
1、寄存器定义在哪里?答:在core_cm3.h中!
typedef struct
{
__IO uint32_t CTRL;
__IO uint32_t LOAD;
__IO uint32_t VAL;
__I uint32_t CALIB;
} SysTick_Type;
…
#define SysTick ((SysTick_Type *) SysTick_BASE)
2、函数在哪里?
在V3.3的函数库中关于SysTick的函数只有两个。一个是在misc.C文件中的
SysTick_CLKSourceConfig函数,它是一个时钟源配置函数;另一个是在
core_cm3.h文件中的SysTick_Config函数,它的输入参数只有一个,传给了重装值寄存器LOAD,
另外还将VAL寄存器清0了,此外还将CTRL寄存器中的[2:0] 三位都设为了1,分别是使用HCLK时钟,允许异常请求,开启计数器。
在 misc.C 文件最后有下面一个函数
/**
- @功能: 配置 SysTick 时钟源
-
@输入参数: SysTick_CLKSource: 指定SysTick 时钟源.
- 该参数可以是以下其中一个值:
- @ SysTick_CLKSource_HCLK_Div8: AHB 时钟 8 分频作为 SysTick 时钟源
- @ SysTick_CLKSource_HCLK: AHB 时钟作为 SysTick 时钟源.
*/
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 中有一个 SysTick_Config 函数
/* ############### SysTick 函数 ################### */
#if (!defined (__Vendor_SysTickConfig)) || (__Vendor_SysTickConfig == 0)
/**
- @功能 初始化并开启 SysTick计数器及其中断
- @输入参数 ticks 两次中断间的 ticks 数值
-
@返回值 1 = 失败, 0 =成功
- 初始化系统滴答定时器及其中断并开启系统滴答定时器在自由运行模式下以产生周期中
断
*/
static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* 重装值超过了 24 位,是不可
能的。返回失败值 0 */
SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* 设置重装载寄存器 */
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* 设置优先级 for Cortex-M0 系统中断 */
SysTick->VAL = 0; /* 装载计数器值(当前计数值清 0) */ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk| SysTick_CTRL_ENABLE_Msk; /*
使能 SysTick 中断请求和 Systick 定时*/
return (0); /* 成功,返回 0 */
}
#endif
3、编写一个精确延时函数!
鉴于SysTick的寄存器比较少,库函数也没写出啥玩意。所以完全有信心用寄存器的方法写出一个SysTick精确延时函数。偷学了网上的一点程序,写出了如下的函数,比网上的还精简了几行,哈哈!
/* 微秒级精确延时函数 */
void Delay_us(uint32_t n) 延时多少微秒,n 就输入多少!
{
SysTick->LOAD=72*n; //装载计数值,因为时钟 72M,72 次在 1μs SysTick->CTRL=0x00000005;//时钟来源设为为 HCLK(72M),打开定时器while(!(SysTick->CTRL&0x00010000)); //等待计数到 0
SysTick->CTRL=0x00000004;//关闭定时器
}
编写一个点亮LED的函数测试一下。
int main(void)
{
GPIO_Configuration(); while(1)
{
GPIO_SetBits(GPIOD, GPIO_Pin_3); //输出高电平
Delay_us(10); //精确延时 10μs
GPIO_ResetBits(GPIOD, GPIO_Pin_3); //输出低电平
Delay_us(10); //精确延时 10μs
}
}
经示波器测试,发现确实很准,嘎嘎~~~△X=10.5μs,那0.5μs的误差来自哪里呢?因为要调用GPIO和Delay_us函数,包括Dealy_us函数中的几条设置语句,所以说还是相当准的!嘎嘎 ~~~~~~~~~~
STM32 的系统滴答定时器( Systick) 彻底研究解读 - nevel - 博客园
第11章 基础重点—SysTick 定时器
一、关于SysTick定时器
SysTick定时器(又名系统滴答定时器)是存在于Cortex-M3的一个定时器,只要是ARM Cotex-M系列内核的MCU都包含这个定时器。使用内核的SysTick定时器来实现延时,可以不占用系统定时器,节约资源。由于SysTick是在CPU核内部实现的,跟MCU外设无关,因此它的代码可以在不同厂家之间移植。
本章将使用系统滴答定时器实现延时函数, 注 意 SysTick 用于了 HAL 库的毫秒级延时函数“HAL_Delay()”,不建议日常使用SysTick去作为其它用途,这里只作为演示。
SysTick定时器是一个24位递减定时器,即计数器可以从最大值224开始,每个时钟周期减1,当减到0时,会产生Systick异常,同时再自动重载定时初值,开始新一轮计数。通过设置这个定时初值,就可以实现得到指定时间。如下图 11.1.1 所示,y为定时器初值,然后随着时间增加,值逐渐减小,直至为0,再重新加载初值,如此往复,x1、x2、x3这些时间段,就是我们需要的延时时间。
假设STM32F103工作在72MHz,即72000000Hz,意味着1s时间内,会计数72000000次。那么1ms则计数72000000/1000=72000次。这个72000就可以作为系统滴答定时器的初始值,将这个值写入系统滴答定时器,定时器在每个时钟周期减1,减到0时,就刚好是1ms,同时产生中断通知,再次加载72000如此反复。HAL库提供“HAL_SYSTICK_Config()”函数去设置这个初始值。
系统滴答定时器只有四个控制寄存器:STK_CTRL,STK_LOAD,STK_VAL和STK_CALIB。因 为系统滴答定时器属于Cotex-M3内核的外设,相关寄存器介绍不在《参考手册》,而在《3_STM32F10xx Cortex-M3编程手册》,后简称《编程手册》。
1.1 系统滴答定时器控制和状态寄存器(STK_CTRL)
重点关注Bit[0],用于使能系统滴答定时器,Bit[1]使能系统滴答定时器中断,Bit[2]系统滴答时钟的时钟来源。
1.2 系统滴答定时器加载值寄存器(STK_LOAD)
Bit[23:0],一共24位,用来设置系统滴答定时器的初始值,因此范围为1~ 16777216。
1.3 系统滴答定时器当前值寄存器(STK_VAL)
Bit[23:0],一共24位,用来获取当前系统滴答定时器的计数值。
1.4 系统滴答定时器校准值寄存器(STK_CALIB)
这个寄存器没用到,可以不用管。此外,当处理器在调试期间被暂停(halt)时,系统滴答定时器也将暂停运作。
二、硬件设计
系统滴答定时器属于Cortex-M3内核资源,不涉及外部硬件电路。
三、软件设计
3.1 软件设计思路
实验目的:使用系统滴答定时器实现自定义延时。
分析HAL库的系统滴答定时器配置函数;
初始化系统滴答定时器(设置计数初值、使能等);
封装延时函数,设置系统滴答定时器中断处理函数;
主函数调用验证;
3.2 软件设计思路
3.2.1 分析HAL库的系统滴答定时器配置函数
在HAL库中,使用“HAL_SYSTICK_Config()”函数配置SysTick的初始值。
/**
* @brief Initializes the System Timer and its interrupt, and starts the System Tick Timer.
* Counter is in free running mode to generate periodic interrupts.
* @param TicksNumb: Specifies the ticks Number of ticks between two interrupts.
* @retval status: - 0 Function succeeded.
* - 1 Function failed.
*/
uint32_t HAL_SYSTICK_Config(uint32_t TicksNumb)
{
return SysTick_Config(TicksNumb);
}
该函数调用“SysTick_Config()”函数,函数内容如下代码段 11.3.2所示。
#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U)
/**
\brief System Tick Configuration
\details Initializes the System Timer and its interrupt, and starts the System Tick Timer.
Counter is in free running mode to generate periodic interrupts.
\param [in] ticks Number of ticks between two interrupts.
\return 0 Function succeeded.
\return 1 Function failed.
\note When the variable <b>__Vendor_SysTickConfig</b> is set to 1, then the
function <b>SysTick_Config</b> is not included. In this case, the file <b><i>device</i>.h</b>
must contain a vendor-specific implementation of this function.
*/
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
{
return (1UL); /* Reload value impossible */
}
SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
SysTick->VAL = 0UL; /* 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 (0UL); /* Function successful */
}
#endif
通过对“HAL_SYSTICK_Config()”函数分析,可知只需要传入SysTick初始值,其它的都默认已经设置完成了。
3.2.2 初始化系统滴答定时器
/*
* 函数名:void SysTickInit(uint32_t cycle)
* 输入参数:cycle,设置系统滴答时钟周期
* 输出参数:无
* 返回值:无
* 函数作用:初始化系统滴答时钟的频率和中断优先级
*/
void SysTickInit(uint32_t cycle)
{
uint32_t init_t = 0;
init_t = SystemCoreClock/cycle;
/* 时间(单位:s)=1/频率(单位:HZ)
* SystemCoreClock频率: 72MHz = 72,000,000
* 即MCU 1秒会计数72,000,000次
* 1ms则计数 72MHz/1000 = 72000次
* 72000就是滴答时钟的初始值,它向下计数72000次,计数将变为0,就会产生一次中断
* 滴答时钟初始值范围:1~16777216
*
* SystemCoreClock/1000: 1ms中断一次
* SystemCoreClock/100000: 10us中断一次
* SystemCoreClock/1000000: 1us中断一次
*/
if(HAL_SYSTICK_Config(init_t) != HAL_OK)
{
Error_Handler();
}
// 设置滴答定时器中断优先级:最高
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
// 使能滴答定时器中断
HAL_NVIC_EnableIRQ(SysTick_IRQn);
}
为了方便修改SysTick的初始值,这里定义几个常见的延时周期:
#define CYCLE_100MS 10
#define CYCLE_10MS 100
#define CYCLE_1MS 1000
#define CYCLE_100US 10000
#define CYCLE_10US 100000
#define CYCLE_1US 1000000
3.2.3 封装延时函数,设置系统滴答定时器中断处理函数
创建延时函数“SysTickDelay()”,在该函数里设置自定义全局变量systick_t的初始值,SysTick每计数完一次则进入SysTick中断,将全局变量systick_t的值减1,如代码段 11.3.6 所示。一直到systick_t变为零,结束延时,如代码段 11.3.5 所示。
3.2.4 主函数调用验证
int main(void)
{
// 初始化HAL库函数必须要调用此函数
HAL_Init();
/*
* 系统时钟即AHB/APB时钟配置
* 使用外部高速时钟HSE(8MHz)配置系统时钟,经过PLL放大9倍,得到72MHz
*/
SystemClock_Config();
// 调用库函数来检验自己的配置是否成功配置为系统频率72MHz
sys_clk = HAL_RCC_GetSysClockFreq();
/*
* 初始化滴答时钟
* 通过改变传入参数改变滴答时钟的频率,即SysTickDelay(1)的时长
*/
SysTickInit(CYCLE_1MS);
// 初始化LED
LedGpioInit();
while(1)
{
/* 通过延时一段时间让LED亮灭实现LED闪烁,可以通过示波器打LED的引脚反转周期,精确看时间是否与设置的一致*/
RLED(ON); // 点亮LED
SysTickDelay(1000); // 延时CYCLE_1MS*1000=1s
RLED(OFF); // 熄灭LED
SysTickDelay(1000); // 延时CYCLE_1MS*1000=1s
}
}
四、代码工程
工程链接:基本重点-SysTick
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_37391577/article/details/131777374