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。定义如下所示:
4个寄存器中,校准寄存器SYST_CALIB不用我们考虑,出厂前就配置好了。这时,就剩下3个寄存器了。一共需要配置3个寄存器就可以完成工作的模块,你想想会很难使用吗?英文不好的同学,请看下面的寄存器翻译:
- SYST_CSR寄存器,就是系统定时器控制和状态寄存器
- SYST_RVR寄存器,就是系统定时器重载值寄存器
- SYST_CVR寄存器,就是系统定时器当前值寄存器
1.SYST_CSR寄存器
翻译成中文的:
CSR寄存器用到的位有4个,bit0用于是否开启定时器,bit1用于是否产生中断,bit2用于选择定时器的时钟源是等于主时钟还是等于主时钟的一半,bit16是定时器的状态。
2.SYST_RVR寄存器
翻译成中文的:
RVR寄存器用到bit0~23,即24位数,这个值是定时器倒计时的初值,打开定时器以后,SYST_CVR值会从此值倒计时到0,因为倒计时到0以后,又会从此值开始倒计时,所以定义里面叫这个寄存器位重载值。
3.SYST_CVR寄存器
翻译成中文:
CVR寄存器用到bit0~23,即24位数,这是一个状态寄存器,当定时器开始运作,这个值在不断地变化,从RVR寄存器获取初值以后,倒计时到0.
二、如何调用Keil自带的系统定时器函数
系统自带的Systick函数,由CMSIS(关于什么是CMSIS,去百度搜吧)提供,位于core_cm0.h文件,你可以在LPC1114工程中,如下地方找到:
双击上图红色框内的文件名称,打开对应文件。在core_cm0.h文件的最底部,有一个函数,如下所示:
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) { ) > SysTick_LOAD_RELOAD_Msk) ); /* Reload value impossible */ SysTick->LOAD = ticks - ; /* set reload register */ NVIC_SetPriority (SysTick_IRQn, (<<__NVIC_PRIO_BITS) - ); /* set Priority for Systick Interrupt */ SysTick->VAL = ; /* 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 */ ); /* Function successful */ }
此函数就是CMSIS提供的系统定时器控制函数SysTick_Config()。在使用的时候,可以直接调用,函数有一个参数ticks。由函数内部的语句“SysTick->LOAD = ticks – 1;”知道,ticks就是LOAD值,即重载值,表示两次中断的计数。
例如,要产生10ms的中断,可以在程序中如下调用函数:
Systick_Config(SystemCoreClock/);
函数参数中的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就是我们之前说的RVR,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文件打开
在第74行,你可以看到系统定时器中断函数的名称,如下所示:
你不仅可以看到系统定时器中断函数的名称,所有的中断函数的名称,都已经写好了,在用其它模块的中断时,到这个地方找就对了。还有前面那个是否可以自己改的问题,你把这个地方的名称改了,就可以在.c文件中使用你修改后的名称了,不过为了程序的移植性统一性阅读性,瑞生建议大家不要修改。
四、写一个毫秒延时函数delay_ms()
1.自己配置寄存器(假设当前主频为50MHz)
; void SysTick_Handler(void) // 中断函数 { TimeTick++; } void delay_ms(uint32_t ms) // 参数最大带入671 { SysTick->LOAD = *ms-; SysTick->VAL = ; SysTick->CTRL |= ((<<)|(<<)); // 开定时器,开中断 while(!TimeTick); TimeTick = ; SysTick->CTRL =; // 关定时器 }
为什么主频为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(); delay_ms();
2.自己配置寄存器(适应不同主频)
; void SysTick_Handler(void) // 中断函数 { TimeTick++; } void delay_ms(uint32_t ms) { SysTick->LOAD = (SystemCoreClock/)*ms-; SysTick->VAL = ; SysTick->CTRL |= ((<<)|(<<)); // 开定时器,开中断 while(!TimeTick); TimeTick = ; SysTick->CTRL =; // 关定时器 }
为了在不同的主频下使用此函数,而不用每次去修改不同主频下的那个值(例如50MHz对应的25000),我们把LOAD赋值语句改成了上面函数中所示。SystemCoreClock是当前的主频。
3.利用Keil自带系统定时器配置函数写毫秒延时函数delay_ms()
void SysTick_Handler(void) { msTicks++; } void delay_ms(uint32_t ms) { SysTick_Config((SystemCoreClock/)*ms); while(!msTicks); msTicks = ; SysTick->CTRL =; // 关定时器 }
为什么前面的函数SystemCoreClock是除以2000,而这里是除以1000?答:因为前面的函数中,系统定时器时钟使用主频的二分之一,而Keil自带的配置是使用主频。
Cortex-M0系统滴答定时器Systick详解的更多相关文章
- 系统滴答定时器(SysTick)中断配置
系统滴答定时器(SysTick)中断配置 在STM32标准库中是通过SysTick_Config()函数配置时钟中断的,然后SysTick_Handler()函数自动定时触发其中的函数. if(Sys ...
- STM32 的系统滴答定时器( Systick) 彻底研究解读
作者:王健 前言 SysTick 比起那些 TIM 定时器可以说简单多啦~~~~~哥的心情也好了不少, 嘎嘎!! ARM Cortex-M3 内核的处理器内部包含了一个 SysTick 定时器,它是一 ...
- Corex-M0 系统嘀嗒定时器 Systick 详解
- STM32之系统滴答定时器
一.SysTick(系统滴答定时器)概述 操作系统需要一个滴答定时器周期性产生中断,以产生系统运行的节拍.在中断服务程序里,基于优先级调度的操作系统会根据进程优先级切换任务,基于时间片轮转系统会根据时 ...
- STM32 - SYSTICK(系统滴答定时器)
SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15).在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基.例如,为多个任务许以不同数目 ...
- 利用滴答定时器(SysTick)实现简单的延时函数
预备知识: 对标准库来说,如果定义了时钟频率,则系统会默认初始化该时钟频率. SysTick是CM4的内核外设,是一个24位的向下递减计数器,每次计数时间是1/SYSCLK,即1/168000000. ...
- liunx驱动----系统滴答时钟的使用
2019-3-12系统滴答定时器中断使用 定义一个timer 其实就是使用系统的滴答定时器产生一个中断. 初始化timer init_timer函数 实现如下 void fastcall ini ...
- HAL库与Cubemx系列|Systick-系统滴答定时器详解
Systick是什么? 关于Systick,在Context-M3权威指南中如此描述: SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号: 15).在以前,大多操作系统需要一 ...
- STM32 系统滴答计时器
;//us与系统滴答的被乘数 ;//ms与系统滴答的被乘数 ;//系统运行秒数 /** * @description:系统滴答计时系统初始化 * @param 无 * @retval 无 */ voi ...
随机推荐
- [Flux] 3. Actions
Actions contain no functionality, but rather describe an event in our application. In this lesson we ...
- RGB的三维模型与渐变色-颜色系列之一
一.前言 以下与颜色相关的日志记录了俺学习颜色的有关容,限于编写时的水平,难免存在缺点与错误,希望得到朋友.同行和前辈的指教,非常感谢.1. RGB的三维模型与渐变色-颜色系列之一2. <颜 ...
- 学习Oracle应该准备的技能
首先数据库方面的技能:数据库体系结构.基本概念和基本理论.数据库管理.备份.恢复.SQL开发.PLSQL开发.工具的使用等等. 操作系统方面的技能:对Linux/Unix系统应该有相当的基础.理解RA ...
- Eclipse3.7默认字体修改-找回Courser-New字体
1.找到jFace并用WinRAR打开之: jFace的具体位置:$Eclipse目录$/plugins/org.eclipse.jface_3.7.0.I20110522-1430.jar,找到后, ...
- MAC 环境下 初始化新的mysql root 密码
mac 环境下初始化mysql的root密码 关掉mysql服务,打开系统设置最后的mysql,然后将mysql先关掉 生成一个文件命名mysql-init,文件中放入:一句话,这句话不同版本不一样, ...
- 零基础学习云计算及大数据DBA集群架构师【Linux系统环境及权限管理12.21-12.25】
从这周开始Linux的学习,老师是一位女老师,这到给了更多的信心,老师讲得很快,如果说只谈记命令的话是不多,但是要真正去理解,其实内容还是挺多的,我都是以老师讲的内容为主线,然后自己再看鸟哥的书做加深 ...
- vsftpd的主配置文件详解
anonymous_enable=YES 允许匿名用户登录#local_enable=YES 允许本地用户登录#write_enable=YES 允许写权限#local_umask=022 ##ano ...
- Python之路【第十二篇】:JavaScrpt -暂无内容-待更新
Python之路[第十二篇]:JavaScrpt -暂无内容-待更新
- <legend>标签
健康信息身高: 体重: 如果表单周围没有边框,说明您的浏览器太老了. <!DOCTYPE HTML> <html> <body> <form> < ...
- iOS Safari 中点击事件失效的解决办法
问题描述 当使用委托给一个元素添加click事件时,如果事件是委托到 document 或 body 上,并且委托的元素是默认不可点击的(如 div, span 等),此时 click 事件会失效. ...