Cortex-M0系统滴答定时器Systick详解

发布者:meirong最新更新时间:2016-12-08 来源: eefocus关键字:Cortex-M0系统  滴答定时器  Systick 手机看文章 扫描二维码
随时随地手机看文章

Cortex-M0 Systick

上图是LPC1114系统滴答定时器(SysTick)的结构图。系统滴答定时器位于Cortex-M0内核中,也就是说,不论是LPC1114,还是其他的Cortex-M0内核单片机,都有这个系统定时器。其存在的主要目的是为嵌入式操作系统提供100Hz(即10ms)的定时节拍。当然,也可以做为其它的普通定时等其他用途。下面是LPC1114用户手册上列举出的一些用途,你可以了解了解。

  • 可编程设置频率的RTOS 定时器(例如100 Hz),调用一个SysTick 服务程序。

  • 用于核时钟的高速报警定时器。

  • 简单计数器。软件可使用它测量时间 (如:完成任务所需时间、已使用时间)。

  • 基于丢失 / 命中期限控制的内部时钟源。控制和状态寄存器中的COUNTFLAG 位域,
    可用于决定一个动作是否在设定的期限内完成,作为动态时钟管理控制环的一部分。

一、寄存器

系统定时器使用起来非常简单。它一共有4个寄存器:SYST_CSR、SYST_RVR、SYST_CVR、SYST_CALIB。定义如下所示:

Systick寄存器

4个寄存器中,校准寄存器SYST_CALIB不用我们考虑,出厂前就配置好了。这时,就剩下3个寄存器了。一共需要配置3个寄存器就可以完成工作的模块,你想想会很难使用吗?英文不好的同学,请看下面的寄存器翻译:

  • SYST_CSR寄存器,就是系统定时器控制和状态寄存器

  • SYST_RVR寄存器,就是系统定时器重载值寄存器

  • SYST_CVR寄存器,就是系统定时器当前值寄存器

1.SYST_CSR寄存器

SYST_CSR寄存器

翻译成中文的:

SYST_CSR中文

CSR寄存器用到的位有4个,bit0用于是否开启定时器,bit1用于是否产生中断,bit2用于选择定时器的时钟源是等于主时钟还是等于主时钟的一半,bit16是定时器的状态。

2.SYST_RVR寄存器

SYST_RVR寄存器

翻译成中文的:

SYST_RVR中文

RVR寄存器用到bit0~23,即24位数,这个值是定时器倒计时的初值,打开定时器以后,值会从此值倒计时到0,因为倒计时到0以后,又会从此值开始倒计时,所以定义里面叫这个寄存器位重载值。

3.SYST_CVR寄存器

SYSR_CVR寄存器英文

翻译成中文:

SYST_CVR寄存器中文

CVR寄存器用到bit0~23,即24位数,这是一个状态寄存器,当定时器开始运作,这个值在不断地变化,从RVR寄存器获取初值以后,倒计时到0.

二、如何调用Keil自带的系统定时器函数

系统自带的Systick函数,由CMSIS(关于什么是CMSIS,去百度搜吧)提供,位于core_cm0.h文件,你可以在LPC1114工程中,如下地方找到:

core_cm0文件

双击上图红色框内的文件名称,打开对应文件。在core_cm0.h文件的最底部,有一个函数,如下所示:

__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
  if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk)  return (1);      /* Reload value impossible */

  SysTick->LOAD  = ticks - 1;                                  /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  /* set Priority for Systick Interrupt */
  SysTick->VAL   = 0;                                          /* 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 (0);                                                  /* Function successful */
}

此函数就是CMSIS提供的系统定时器控制函数SysTick_Config()。在使用的时候,可以直接调用,函数有一个参数ticks。由函数内部的语句
“SysTick->LOAD  = ticks – 1;”知道,ticks就是LOAD值,即重载值,表示两次中断的计数。

例如,要产生10ms的中断,可以在程序中如下调用函数:

Systick_Config(SystemCoreClock/100);

函数参数中的SystemCoreClock是当前主频的值,假如现在的主频是50MHz,SystemCoreClock就是50 000 000 ,50 000 000 /100=500 000。我们把参数带进去以后,LOAD=499 999,也就是说,定时器开始运行后,定时器的值会从499 999递减到0,进入中断函数,然后再次从499 999 递减到0,如此循环。

这时候,你心中会有一个大大的问号:“为什么从499 999递减到0就是10ms?”接下来,瑞生给你解答,其实很简单,不信听我说。

定时器运行,要知道“为什么从499 999递减到0就是10ms”,只要知道定时器每递减一个值需要多长时间就可以了。知道每递减一个值需要多长时间,那么递减500 000下,需要多长时间,就知道了。

要知道每递减一个值需要多长时间,就需要知道当前定时器运行的时钟是多少。由寄存器CSR知道,定时器的时钟有两种,一种是等于主频,一种是等于主频的二分之一,由CSR寄存器中的bit2决定。

函数中用到的寄存器名称和我们手册上给出的名称不太一样,但是你要知道,名称就是个代号,实际调用的其实是名称背后的寄存器地址。函数中LOAD就是我们之前说的RSR,VAL就是我们之前说的CVR,CTRL就是我们之前说的CSR。

函数中,对控制寄存器的bit0 bit1 bit2都置1,对照前面的寄存器定义可知,时钟设置为等于主频,打开系统定时器中断,允许定时器运行。

我们知道了时钟,就知道定时器每递减一个值需要的时间了,即:1/SystemCoreClock 秒,换算成毫秒即:(1/SystemCoreClock)*1000=1000/SystemCoreClock毫秒,即每递减一个值,耗时1000/SystemCoreClock毫秒。所以如果要使得10ms定时,即10/(1000/SystemCoreClock)=SystemCoreClock/100,回头看看前面定时10ms的参数,是不是这个值呢。以此类推,需要定时多长时间,你可以自己算一个参数带进去了,需要注意的是,LOAD值是个24位数,带进去的数不要超过24位数的最大值。还有一个需要注意的地方,就是LOAD值最小255,当你给LOAD值带进去小于255值,LOAD会自动变成255。

三、系统定时器中断函数怎么写

系统定时器的中断函数名称如下所示:

void SysTick_Handler(void)  
{                              
                                                
}

有的童鞋会问,函数名称可以自己改吗?答案是不可以改,非要自己改一个,需要一定的步骤。接下来瑞生给你解答。

打开一个工程,双击startup_LPC11xx.h文件打开

startup_LPC11xx

在第74行,你可以看到系统定时器中断函数的名称,如下所示:

中断函数名称

你不仅可以看到系统定时器中断函数的名称,所有的中断函数的名称,都已经写好了,在用其它模块的中断时,到这个地方找就对了。还有前面那个是否可以自己改的问题,你把这个地方的名称改了,就可以在.c文件中使用你修改后的名称了,不过为了程序的移植性统一性阅读性,瑞生建议大家不要修改。

四、写一个毫秒延时函数delay_ms()

1.自己配置寄存器(假设当前主频为50MHz)

static volatile uint32_t TimeTick = 0;
          
void SysTick_Handler(void)               // 中断函数  
{
    TimeTick++;
}

void delay_ms(uint32_t ms)  // 参数最大带入671
{
    SysTick->LOAD =    25000*ms-1;     
    SysTick->VAL   =     0;                  
    SysTick->CTRL  |=  ((1<<1)|(1<<0));   // 开定时器,开中断
    while(!TimeTick);
    TimeTick = 0;
    SysTick->CTRL =0;   // 关定时器
}

为什么主频为50MHz时,上面函数中与ms乘的数是25000?我在上面已经讲过了,这里我再讲一次,非常简单哦。CTRL寄存器bit2默认是0,也就是说默认的系统定时器时钟是主频的1/2,即25 000 000。所以定时器每递减1,耗时1/25 000 000秒,换成毫秒为单位即:1/25000毫秒。所以每毫秒需要的定时器递减数为1/(1/25000)=25000,即你把25000-1给了LOAD寄存器,就是1ms进一次中断,2ms就是2*25000-1,以此类推,SysTick->LOAD=(25000*ms-1)。

接下来让我们来看看,为什么参数最大值是677?我们知道8位值,最大是255,16位数,最大值是65535,那么24位值最大值是多少呢?打开你的电脑上的计算器,在科学型模式下,16进制输入FFFFFF,再转换成十进制,得到16777215,没错,这就是24位值的最大值。用16777215+1然后除以25000得到最大值671。如果带入超过671的数,就会超过24位最大值,使得程序不可用。

这时候,又有人会抱怨,你这函数最大才能延时671毫秒,那我要延时1秒,岂不是不能用此函数了?瑞生说呀,你妈小时候是教育你将来不要做一个不三不四的人,但是你也不能这么二吧!你要延时1秒钟,用两次延时500毫秒不就可以了么!

delay_ms(500);
delay_ms(500);

2.自己配置寄存器(适应不同主频)

static volatile uint32_t TimeTick = 0;
          
void SysTick_Handler(void)               // 中断函数  
{
    TimeTick++;
}

void delay_ms(uint32_t ms)  
{
    SysTick->LOAD =    (SystemCoreClock/2000)*ms-1;     
    SysTick->VAL   =     0;                  
    SysTick->CTRL  |=  ((1<<1)|(1<<0));   // 开定时器,开中断
    while(!TimeTick);
    TimeTick = 0;
    SysTick->CTRL =0;   // 关定时器
}

为了在不同的主频下使用此函数,而不用每次去修改不同主频下的那个值(例如50MHz对应的25000),我们把LOAD赋值语句改成了上面函数中所示。SystemCoreClock是当前的主频。

3.利用Keil自带系统定时器配置函数写毫秒延时函数delay_ms()

void SysTick_Handler(void)  
{                              
  msTicks++;                                                 
}

void delay_ms(uint32_t ms)
{
  SysTick_Config((SystemCoreClock/1000)*ms); 
  while(!msTicks);
  msTicks = 0;
  SysTick->CTRL =0;   // 关定时器
}

为什么前面的函数SystemCoreClock是除以2000,而这里是除以1000?答:因为前面的函数中,系统定时器时钟使用主频的二分之一,而Keil自带的配置是使用主频。


关键字:Cortex-M0系统  滴答定时器  Systick 引用地址:Cortex-M0系统滴答定时器Systick详解

上一篇:Cortex-M0 LPC1114中断优先级怎么设置
下一篇:ARM Cortex M3系列GPIO口介绍(工作方式探讨)

推荐阅读最新更新时间:2024-03-16 15:24

STM32 SysTick配置函数
之前使用SysTick滴答定时器都是通过查找内核编程手册配置寄存器让SysTick滴答定时器工作的。其实在内核相关的头文件core_cm4.h中已经有SysTick滴答定时器的相关配置了。 条件__Vendor_SysTickConfig == 0成立,配置函数才能使用。 刚好在stm32f4xx.h中定义了__Vendor_SysTickConfig = 0,所以可以使用该配置函数。 观察函数__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks),其中的寄存器和我们在Systick查询定时中用到的寄存器其实是一样的。 __STATI
[单片机]
STM32 <font color='red'>SysTick</font>配置函数
STM32菜鸟成长记录---系统滴答定时器systick)应用
1.systick介绍 Systick就是一个定时器而已,只是它放在了NVIC中,主要的目的是为了给操作系统提供一个硬件上的中断(号称滴答中断)。滴答中断?这里来简单地解释一下。操作系统进行运转的时候,也会有“心跳”。它会根据“心跳”的节拍来工作,把整个时间段分成很多小小的时间片,每个任务每次只能运行一个“时间片”的时间长度就得退出给别的任务运行,这样可以确保任何一个任务都不会霸占整个系统不放。或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。 只要不把它
[单片机]
STM32菜鸟成长记录---<font color='red'>系统</font><font color='red'>滴答</font><font color='red'>定时器</font>(<font color='red'>systick</font>)应用
STM32用定时器精确延时的方法(非SysTick
用TIM2来做延时,延时基准时间1ms,最大可延时65535ms。 系统基础频率是8MHz*4=32MHz。 先配置定时器: TIM_TimeBaseInitTypeDef timInitStruct; timInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; // 定时器基准频率32MHz timInitStruct.TIM_Prescaler = 32000; // 计数频率为1KHz timInitStruct.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数 timInitStruct.TIM_Rep
[单片机]
关于STM32的systick定时器的详细说明
我不得不说意法半导体确实有点风骚!甚至有点变态。我对ST文档STM32F10XXX参考手册的编辑水平真是不敢恭维。手册中好多说明都是含糊不清,甚至将好多对初学者来说很重要的地方都一笔带过,让人着实摸不着头脑。比如前面我说过的关于NVIC嵌套向量中断控制器的介绍,这部分我认为是非常重要的,但当你看完他这部分介绍,你根本不会设置中断服务程序,他有哪些寄存器都不知道,更别说去设置了,NVIC的详细介绍是在Cotex-M3中有详细的介绍,不多说。今天我们说的是systick定时器。 systick定时器和我上面说的情况一样,在手册中根本没有介绍。我费了九牛二虎之力才在一个犄角格拉里找到systick定时器的英文版的说明。在Cotex-
[单片机]
STM32F103标准库开发---精准延时delay---SysTick使用
一、SysTick使用详解 1. SysTick简介 SysTick是一个24bit的倒计数定时器,具有自动重载和溢出中断功能,所有基于Cortex_M3处理器的微控制器都有一个SysTick定时器,从而获得一定的时间间隔。 2. SysTick相关寄存器 状态寄存器-CTRL STCLK外部时钟源:AHB总线时钟的 1/8 FCLK 内部时钟:AHB总线时钟——STM32F103是72MHz 重装载数值寄存器-LOAD 当前值寄存器-VAL 校准寄存器-CALIB 二、编写精准延时——delay 1. 非中断式精准延时 void delay_us(uint16_t us)//uS微秒级延时程序(参考值即是延时
[单片机]
STM32F103标准库开发---精准延时delay---<font color='red'>SysTick</font>使用
STM32入门学习之SysTick系统定时器(STM32F030F4P6基于CooCox IDE)
#include stm32_lib/inc/stm32f0xx_misc.h #include stm32_lib/inc/stm32f0xx_rcc.h int main(void){ //配置初值,系统定时器是倒数计时器,减1的 //注意:该函数的参数类型虽为uinit32_t,实际最大值为16777215,也就是2^24 SysTick_Config(SystemCoreClock/10); while(1); } //中断函数 void SysTick_Handler(void){ //这里做你想做的事情 } 系统定时器,就是这么简单!时钟为系统时钟,只要配置好倒计时数即可。 特别
[单片机]
STM32入门学习之<font color='red'>SysTick</font><font color='red'>系统</font><font color='red'>定时器</font>(STM32F030F4P6基于CooCox IDE)
STM32的SYSTICK_Init()配置
void SYSTICK_Init(void) { /* SysTick end of count event each 1ms with input clock equal to 4.5MHz (HCLK/8, default) SysTick_SetReload(4500); /* Enable SysTick interrupt SysTick_ITConfig(ENABLE); /* Enable the SysTick Counter SysTick_CounterCmd(SysTick_Counter_Enable); } 系统时钟定时器的周期与驱动的时钟频率和Reload值相关。
[单片机]
stm32之滴答定时器(4):滴答定时器的优先级设置
上次讲的只剩滴答定时器的优先级设置函数NVIC_SetPriority没有讲,这个函数具体如下 static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) { if(IRQn 0) { SCB- SHP = ((priority (8 - __NVIC_PRIO_BITS)) & 0xff); } * set Priority for Cortex-M3 System Interrupts */ else { NVIC- IP = ((priority (8 - __NVIC_PRIO_BITS)) & 0xff); }
[单片机]
stm32之<font color='red'>滴答</font><font color='red'>定时器</font>(4):<font color='red'>滴答</font><font color='red'>定时器</font>的优先级设置
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved