系统定时器systick 提供了更大的功能
艾瑞卡软件库7月1日消息,想到定时器可能会想到通用定时器(TIM2) ~ TIM5 和 TIM9 ~ TIM14)或高级定时器(TIM1和TIM8)。这些定时器具有很强的功能,除了定时的基本功能外,还可以测量输入信号的脉冲宽度,生产输出波形。
当然,使用起来相对复杂。如果我们的项目只想要定时功能,使用这些定时器可能有点不必要。事实上,系统定时器Systick也可以实现软件定时,但在裸机中,我们大多数人只使用它作为延迟功能。
一、Systick简介
SysTick—系统定时器是CM4内核中嵌入NVIC的外围设备。一般情况下,我们称他为系统定时器或滴答定时器。它是一个向下递减的24bit计数器,每次计数时间为1/1SYSCLK,当重装载数值寄存器的值降低到 0时,系统定时器会产生一次中断,从而循环往复。操作系统一般采用系统定时器,用于产生时基,维持操作系统的心跳。比如RTOS的心跳是Systick产生的。
二、Systick寄存器
SysTick—该系统定期有4个寄存器,简要介绍如下。使用Systick定时生成时,只需配置前三个寄存器,不需要使用最后一个校准寄存器。
SysTick—属于系统定时器 CM4内核中的外设,所以在core_cm4中.在h文件中可以看到对应结构体的介绍。
三、配置Systick寄存器
Systick是Systick 24 位递减计数器,我们只需要掌握ARMCMSIS软件提供的函数
SysTick_Config,原代码如下:
__STATIC_INLINE uint32_t SysTick_Config(uint32__t ticks)
{
// 重装载值不可能,超出范围
if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
{
return (1UL);
}
// 设置重装载寄存器
SysTick->LOAD = (uint32__t)(ticks - 1UL);
// 设置中断优先级,优先级最低
NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL);
// 设置当前的数值寄存器
SysTick->VAL = 0UL;
// 设置系统定时器的时钟源是 AHBCLK=180M
// 中断系统定时器
// 使能定时器
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk;
return (0UL);
}
第 2024 行,函数的形状参考用于配置滴答定时器LOAD寄存器的值。由于滴答定时器是递减计数器,启动后将LOAD寄存器的值赋予VAL寄存器,然后VAL寄存器进行递减操作,等待递减 0 重新加载LOAD寄存器的值继续递减。函数的形参表示内核时钟在多少个周期后触发一次 Systick 例如,形参配置为以下值。函数的形参表示内核时钟在多少个周期后触发一次 Systick 例如,形参配置为以下值。
-- SystemCoreClock / 1000 表示定时频率为 1000Hz, 也就是说,定期周期为 1ms。
-- SystemCoreClock / 500 表示定时频率为 500Hz, 也就是说,定时周期为 2ms。
-- SystemCoreClock / 2000 表示定时频率为 2000Hz, 也就是说,定期周期为 500us。
注:SystemCoreClock 是 STM32F407 的系统主频 168MHz。
第 2029 是的,这个函数设置滴答定时器是最低优先级。
第 2032 配置滴答定时器控制寄存器,中断滴答定时器。滴答定时器的中断服务程序相对简单,没有清除中断标志,只需填写用户想要实现的功能。
在使用固件库编程时,我们只需要调用库函数Systick_Config()可以,形参ticks用于设置重装载寄存器的值,当重装载寄存器的值递减到0时中断,然后重装载寄存器的值重新装载递减计数,从而循环往复。然后设置中断优先级,最后配置系统定时器的时钟,中断定时器和定时器,配置系统定时器,完成库函数。
四、Systick实现延迟功能
实现延迟功能非常简单。调用Systick_config函数,传输定时器的重载值,然后结合时钟定期中断。
这个参数到底是怎么设置的?
A:Systemcoreclock是固件中定义的系统核心时钟,STM32F4xx通常是 168MHz,别跟我说你的Systemcoreclock是160MHz。
Systick定时器的计数器向下递减,计数一次时间。当重装载寄存器中的值降至0时,会产生中断。可以看出,中断一次的时间
=,
其中 SystemCoreClock 。若设置为168,则中断时间=。不过 中断毫无意义。整个程序的重点是进出中断,没有时间处理其他任务。因此,我们将重装载值设置为SystemCoreClock / 1000 =168 0000,T_的中断时间INT = 168 0000/168MHz = 1ms。因此,不难理解:
SystemCoreClock / 1000 表示定时频率为 1000Hz, 也就是说,定期周期为 1ms
SystemCoreClock / 500 表示定时频率为 500Hz, 也就是说,定期周期为 2ms
SystemCoreClock / 2000 表示定时频率为 2000Hz, 也就是说,定期周期为 500us
对于常规应用,我们通常取定时周期1ms。对于低速CPU或低功耗应用程序,定时周期可设置为 10ms。对于低速CPU或低功耗应用程序,定时周期可设置为 10ms。
然后定时周期设置好后,到时间到了,就会跳转到Systick定时器中断服务函数中,这个函数在stm32fxxx.it.c文件中。如果您想在其他地方更改代码或重写代码,请注释此函数。
void SysTick_Handler(void)
{
TimingDelay_Decrement();
}
五、Systick实现多组软件定时
前面是铺垫,讲的是Systick的基础知识。以下是重点。既然是定时器,我们就不能简单地使用他的延迟功能。在单片机中,当你想到定时器时,你可能会想到通用定时器(TIM2) ~ TIM5 和 TIM9 ~TIM14或高级定时器(TIM1) 和 TIM8)。这些定时器具有很强的功能,除了定时的基本功能外,还可以测量输入信号的脉冲宽度,生产输出波形。当然,使用起来也很麻烦。如果我们的项目只想要定时功能,可能不需要使用这些定时器。事实上,系统定时器Systick也可以实现软件定时,但在裸机中,我们大多数人只使用它作为延迟功能。
既然要实现定时功能,就必须需要定时不同的时间,比如定时500ms,LED灯翻转一次。定时200ms,蜂鸣器响一次等等。因此,我们需要一个结构来实现多组延迟。
1、定时器结构体
/* 成员变量必须是定时器结构体 volatile, 否则,C编译器优化可能会有问题 */
typedef struct
{
volatile uint8_t Mode; /* 计数器模式,1次性 */
volatile uint8_t Flag; /* 定期到达标志 */
volatile uint32_t Count; /* 计数器 */
volatile uint32_t PreLoad; /* 计数器预装值 */
}SOFT_TMR;
Mode:计数器模式,一次或多次。
Flag:定时到达标志,定时到达,flag为1。
Flag:定时到达标志,定时到达,flag为1。
Count:计数器。
PreLoad:计数器预装值 。
由于多组软件是定时的,因此定义了一个结构体数组变量。
#define TMR_COUNT 4 /* 软件定时器的数量 (定时器ID范围 0 - 3) */
/* 软件定时器结构的变量 */
static SOFT_TMR s_tTmr[TMR_COUNT];
这里定义了几个软件定时器的全局变量。这里必须添加__IO即是volatile,由于在中断和主程序中同时访问该变量,可能会导致编译器的错误优化。TMR_COUNT是一个定时器的数量,您可以将其设置为其它值,以实现多个定时器。
2、定时器初始化
定时器的初始化主要是清空结构变量的值,然后只需调用Systick_Config();函数就够了,前面已经详细介绍过了。
void Soft_TimerInit(void)
{
uint8_t i;
/* 清除所有软件定时器 */
for (i = 0; i < TMR_COUNT; i )
{
s_tTmr[i].Count = 0;
s_tTmr[i].PreLoad = 0;
s_tTmr[i].Flag = 0;
s_tTmr[i].Mode = TMR_ONCE_MODE; /* 缺陷是一次性工作模式 */
}
SysTick_Config(SystemCoreClock / 1000);/*SystemCoreClock / 1000是重装载寄存器的LOAD*/
}
3、启动定时器
该函数主要给定时器赋重装载值。开关中断操作在结构体变量赋值前后进行,因为该结构体变量也应在滴答定时器中断中调用,以防止变量赋值出现问题。开关中断操作是在结构变量分配前后进行的,因为结构变量也应该在滴答定时器中断中调用,以防止变量分配出现问题。重装载值分配完成后,程序可以定期定期中断,即在定时器中断服务函数中执行相应的代码。
void StartTimer(uint8___t _id, uint32_t _period)
{
DISABLE_INT(); /* 关中断 */
s_tTmr[_id].Count = _period; /* 实时计数器的初始值 */
s_tTmr[_id].PreLoad = _period; /* 自动重装计数器,只有自动模式起作用 */
s_tTmr[_id].Flag = 0; /* 定时到达标志 */
s_tTmr[_id].Mode = TMR_ONCE_MODE; /* 一次性工作模式 */
ENABLE_INT(); /* 开中断 */
}
void SysTick_Handler(void)
{
SysTick_ISR(); /* 滴滴定期中断服务程序 */
}
4、定时器中断服务函数
例如,我们设置定时器的定时周期为1ms,然后每1ms程序进入Systick_Handler一次,在Systick_Handler函数中调用Systick_ISR函数减少软件定时器的计数器,因为这里设置了TMR_Count组软件定时,需要减少每组的Count,如果定时器变量减少到1,设置定时器到达标志,表示定期结束。
void SysTick_ISR(void)
{
uint8_t i;
/* 每隔1ms,减少软件定时器的计数器 */
for (i = 0; i < TMR_COUNT; i )
{
SoftTimerDec(&s_tTmr[i]);
}
}
static void SoftTimerDec(SOFT_TMR *_tmr)
{
if (_tmr->Count > 0)
{
/* 如果定时器变量减少到1,则设置定时器以达到标志 */
if (--_tmr->Count == 0)
{
_tmr->Flag = 1; /* Flag = 1 用于检查定时器的时间 */
}
}
}
5、检查定时器是否超时
软件定时器已经在前面打开,然后在程序中,需要检测时间是否到达。比如我定时500ms,500ms到了我想做什么,需要一个函数。
总结
以上就是今天所分享的内容了,更多行业知识、软件引荐、功能比照、工具测评请关注艾瑞卡软件库。每天给大家带来更高效的企业服务软件,其中包括有微信,逗鱼时刻,微客优品,千喜惠,聊讯,优乐购,淘卷淘,花惜,易凡,有趣超市,淘金甄选,韵鹿严选,海豚甄选,泡泡易选,创南北,思语,美宜购,陌陌,百盛,达信酷,钉钉,悦信,坤米,惊喜淘,会友,多多联盟,支付宝,QQ,加圈,微信红包辅助,新密购,苹果微信多开,微信分身,安卓微信多开等现如今热门社交软件,其中功能有秒抢,避雷,秒,埋雷软件,扫尾,单透软件等一些红包强项外挂功能软件免费下载使用!