打印
[牛人杂谈]

M451的系统定时器 SysTick

[复制链接]
1209|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
ARMCortex-M4集成了一个SysTick,它提供了一种简单的、24位写清零(clear-on-write)、递减的、计数值减到零后
自动重载(wrap-on-zero)的计数器,该计数器带有灵活的控制机制。SysTick其实就是一个定时器而已,只是它放在了NVIC中,主要的目的是为了给操作系统提供一个硬件上的中断(也称作“滴答中断”)。那么什么是滴答中断呢?这里来简单地解释一下。当操作系统进行运转的时候,也会有“心跳”。它会根据“心跳”的节拍来工作,把整个时间段分成很多小小的时间片,每个任务每次只能运行一个“时间片”的时间长度就得退出给别的任务运行,这样可以确保任何一个任务都不会霸占整个系统不放。或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。 只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息。

沙发
dongnanxibei|  楼主 | 2017-5-22 22:48 | 只看该作者
控制Led灯闪烁调用系统时钟模块实现精确的延时。

SysTick时钟源的选择


在这里,我们默认使用12MHz外部晶振(HXT)作为SysTick的时钟源,需要通过设置寄存器CLK_CLKSE0[5:3]为‘000,使用库函数CLK_SetSysTickClockSrc进行设置
CLK_SetSysTickClockSrc(CLK_CLKSEL0_STCLKSEL_HXT);


当设置好SysTick的时钟源,就得按照其提供的频率为SysTick设置相应的定时计数值,涉及到3个寄存器为SYST_CTRL、 SYST_VAL、SYST_LOAD,它们的作用分别是SysTick的控制、SysTick的计数值设置、SysTick的自动重载的计数值,使用到库函数CLK_SysTickDelay


__STATIC_INLINE void CLK_SysTickDelay(uint32_t us) {
/*1.SysTick的自动重载值的设置*/
SysTick->LOAD = us * CyclesPerUs;
/*2.SysTick的计数值设置*/
SysTick->VAL = (0x00);
/*3.SysTick的时钟源选择为内核时钟、使能计数器*/
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
/*4.等待计数器向下计数完毕 */
while((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == 0); }


使用特权

评论回复
板凳
dongnanxibei|  楼主 | 2017-5-22 22:49 | 只看该作者
当系统定时器使能后,将从 SysTick 的当前值寄存器 (SYST_VAL) 的值向下计数到0,并在下一个时钟周期,重新加载寄存器SYST_LOAD的值,然后再随时钟递减。当计数器减到0时,标志位COUNTFLAG置位,读 COUNTFLAG 位使其清零。复位后, SYST_VAL 的值是未知的。使能前,软件应该向寄存器写入值清零。这样确保定时器使能时以SYST_LOAD 的值开始计数,而非任意值。若SYST_LOAD 的值为0,在重新加载后,定时器将保持当前值0。这个功能可以在计数器使能后用于禁用的独立功能。
通过分析代码,寄存器SYST_LOAD自动重载值的设置与寄存器SYST_CTRL中的时钟源的选择再次重新确认。当SysTick第二次选择时钟输入源为内核时钟时,此时内核时钟的频率为72MHz,使用SysTick实现微秒级延时的时候,SysTick->LOAD=us*
(72000000/1000000)=us*72,而变量us就是我们延时的时间,单位为微秒。
为了统一使延时函数调用更加方便,在common.c再次对CLK_SysTickDelay重新进行封装,编写了Delayus和Delayms 函数

使用特权

评论回复
地板
dongnanxibei|  楼主 | 2017-5-22 22:49 | 只看该作者
/****************************************
*函数名称:Delayms
*输        入:u32ms -毫秒延时值
*输        出:无
*功        能:毫秒级延时
******************************************/ void Delayms(uint32_t u32ms)
{ while(u32ms--)
CLK_SysTickDelay(1000);
} /****************************************
*函数名称:Delayus
*输        入:u32us -微秒延时值
*输        出:无
*功        能:微秒级延时
******************************************/ void Delayus(uint32_t u32us)
{
CLK_SysTickDelay(u32us);
}

使用特权

评论回复
5
dongnanxibei|  楼主 | 2017-5-22 22:50 | 只看该作者
关于GPIO的初始化,在这个不再赘述了,实现Led灯闪烁代码如下

#include "SmartM_M4.h"
int32_t main(void)
{
PROTECT_REG
(
/* 系统时钟初始化 */
SYS_Init(PLL_CLOCK);
)
/* PB8引脚初始化为输出模式 */
GPIO_SetMode(PB,BIT8,GPIO_MODE_OUTPUT);
while(1) {
/* PB8引脚输出高电平*/
PB8=1;
/* 延时500毫秒*/
Delayms(500);
/* PB8引脚输出低电平*/
PB8=0;
/* 延时500毫秒*/
Delayms(500);
}
}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

200

主题

3544

帖子

16

粉丝