[牛人杂谈] M451的 SysTick 延时

[复制链接]
2077|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 | 显示全部楼层
  1. #include "SmartM_M4.h"
  2. int32_t main(void)
  3. {
  4. PROTECT_REG
  5. (
  6. /* 系统时钟初始化 */
  7. SYS_Init(PLL_CLOCK);
  8. )
  9. /* PB8 引脚初始化为输出模式 */
  10. GPIO_SetMode(PB,BIT8,GPIO_MODE_OUTPUT);
  11. while(1)
  12. {
  13. /* PB8 引脚输出高电平*/
  14. PB8=1;
  15. /* 延时 500 毫秒*/
  16. Delayms(500);
  17. /* PB8 引脚输出低电平*/
  18. PB8=0;
  19. /* 延时 500 毫秒*/
  20. Delayms(500);
  21. }
  22. }


734774645 发表于 2017-3-29 11:20 | 显示全部楼层
这个函数在时钟头文件里有的
734774645 发表于 2017-3-29 11:22 | 显示全部楼层
void CLK_EnableSysTick(uint32_t u32ClkSrc, uint32_t u32Count);
734774645 发表于 2017-3-29 11:22 | 显示全部楼层
  1. /**
  2.   * [url=home.php?mod=space&uid=247401]@brief[/url]      This function execute delay function.
  3.   * @param      us  Delay time. The Max value is 2^24 / CPU Clock(MHz). Ex:
  4.   *                             72MHz => 233016us, 50MHz => 335544us,
  5.                                 48MHz => 349525us, 28MHz => 699050us ...
  6.   * [url=home.php?mod=space&uid=266161]@return[/url]     None
  7.   * [url=home.php?mod=space&uid=1543424]@Details[/url]    Use the SysTick to generate the delay time and the unit is in us.
  8.   *             The SysTick clock source is from HCLK, i.e the same as system core clock.
  9.   */
  10. __STATIC_INLINE void CLK_SysTickDelay(uint32_t us)
  11. {
  12.     SysTick->LOAD = us * CyclesPerUs;
  13.     SysTick->VAL  = (0x00);
  14.     SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;

  15.     /* Waiting for down-count to zero */
  16.     while((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == 0);
  17.    
  18.     /* Disable SysTick counter */
  19.     SysTick->CTRL = 0;
  20. }
dongnanxibei 发表于 2017-3-29 19:16 | 显示全部楼层
当系统定时器使能后,将从 SysTick 的当前值寄存器 (SYST_VAL) 的值向下计数到 0,并在下一个时钟周期,重新加载寄存器 SYST_LOAD 的值,然后再随时钟递减。
 楼主| huangcunxiake 发表于 2017-4-6 18:43 | 显示全部楼层
一般定时器都是向下计数的。
yiyigirl2014 发表于 2017-4-6 21:38 | 显示全部楼层
系统难道不是根据主时钟来运行的吗,如果不启动这个心跳时钟,是不是就系统无法运行?
dongnanxibei 发表于 2017-4-8 11:34 | 显示全部楼层
把整个时间段分成很多小小的时间片,每个任务每次只能运行一个“时间片”的时间长度就得退出给别的任务运行,这样可以确保任何一个任务都不会霸占整个系统不放。
yiy 发表于 2017-4-8 13:25 | 显示全部楼层
24 位写清零(clear-on-write)这个是什么意思,就是你只要往里面执行写操作就自动清零?
xixi2017 发表于 2017-4-9 13:56 | 显示全部楼层
周期的某个时间范围赐予特定的任务等
您需要登录后才可以回帖 登录 | 注册

本版积分规则

223

主题

3745

帖子

11

粉丝
快速回复 在线客服 返回列表 返回顶部