打印
[牛人杂谈]

M451的 SysTick 延时

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

沙发
huangcunxiake|  楼主 | 2017-3-28 23:20 | 只看该作者
使用库函数 CLK_SetSysTickClockSrc 进行设置,代码如下:
程序清单 8.2.1 SysTick 时钟源的选择
CLK_SetSysTickClockSrc(CLK_CLKSEL0_STCLKSEL_HXT);
[2]当设置好 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);
}
当系统定时器使能后,将从 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
函数,详细代码如下:
/****************************************
*函数名称:Delayms
*输 入:u32ms -毫秒延时值
*输 出:无
*功 能:毫秒级延时
******************************************/
void Delayms(uint32_t u32ms)
{
while(u32ms--)
CLK_SysTickDelay(1000);
}
/****************************************
*函数名称:Delayus
*输 入:u32us -微秒延时值
*输 出:无
*功 能:微秒级延时*****************************************/
void Delayus(uint32_t u32us)
{
CLK_SysTickDelay(u32us);
}
[3]关于 GPIO 的初始化,在这个不再赘述了,实现 Led 灯闪烁代码如下:


使用特权

评论回复
板凳
huangcunxiake|  楼主 | 2017-3-28 23:20 | 只看该作者
#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);
}
}


使用特权

评论回复
地板
734774645| | 2017-3-29 11:20 | 只看该作者
这个函数在时钟头文件里有的

使用特权

评论回复
5
734774645| | 2017-3-29 11:22 | 只看该作者
void CLK_EnableSysTick(uint32_t u32ClkSrc, uint32_t u32Count);

使用特权

评论回复
6
734774645| | 2017-3-29 11:22 | 只看该作者
/**
  * [url=home.php?mod=space&uid=247401]@brief[/url]      This function execute delay function.
  * @param      us  Delay time. The Max value is 2^24 / CPU Clock(MHz). Ex:
  *                             72MHz => 233016us, 50MHz => 335544us,
                                48MHz => 349525us, 28MHz => 699050us ...
  * [url=home.php?mod=space&uid=266161]@return[/url]     None
  * [url=home.php?mod=space&uid=1543424]@Details[/url]    Use the SysTick to generate the delay time and the unit is in us.
  *             The SysTick clock source is from HCLK, i.e the same as system core clock.
  */
__STATIC_INLINE void CLK_SysTickDelay(uint32_t us)
{
    SysTick->LOAD = us * CyclesPerUs;
    SysTick->VAL  = (0x00);
    SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;

    /* Waiting for down-count to zero */
    while((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == 0);
   
    /* Disable SysTick counter */
    SysTick->CTRL = 0;
}

使用特权

评论回复
7
dongnanxibei| | 2017-3-29 19:16 | 只看该作者
当系统定时器使能后,将从 SysTick 的当前值寄存器 (SYST_VAL) 的值向下计数到 0,并在下一个时钟周期,重新加载寄存器 SYST_LOAD 的值,然后再随时钟递减。

使用特权

评论回复
8
huangcunxiake|  楼主 | 2017-4-6 18:43 | 只看该作者
一般定时器都是向下计数的。

使用特权

评论回复
9
yiyigirl2014| | 2017-4-6 21:38 | 只看该作者
系统难道不是根据主时钟来运行的吗,如果不启动这个心跳时钟,是不是就系统无法运行?

使用特权

评论回复
10
dongnanxibei| | 2017-4-8 11:34 | 只看该作者
把整个时间段分成很多小小的时间片,每个任务每次只能运行一个“时间片”的时间长度就得退出给别的任务运行,这样可以确保任何一个任务都不会霸占整个系统不放。

使用特权

评论回复
11
yiy| | 2017-4-8 13:25 | 只看该作者
24 位写清零(clear-on-write)这个是什么意思,就是你只要往里面执行写操作就自动清零?

使用特权

评论回复
12
xixi2017| | 2017-4-9 13:56 | 只看该作者
周期的某个时间范围赐予特定的任务等

使用特权

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

本版积分规则

205

主题

3485

帖子

10

粉丝