定时器,顾名思义是拿来定时的,但除了定时之外,我们还可以利用定时器的计数特性,演变出其他有意思的功能出来(诸如控制马达转速)。不过在这之前,我们还是先了解了解定时器的工作原理叭。
下面我们先来捋捋定时器的一些重要概念,只有相关概念了解熟悉了,才好继续玩耍不会学懵逼不是嘛。
这里指计数器的位数。如:CM3内核中Systick定时器的计数位有24位,即最大计数值为 224 -1= 16,777,215。我们就说Systick的计数宽度为24。
定时器是人设计,而设计是自由的。既然你规定了计数的数值范围,那么我们从0数到16,777,215,跟从16,777,215 数到 0 都是可以的不是嘛,所以这就引申出了工作模式的概念:
这两种模式,从本质上来说没有任何区别。不过某些定时器可能没有给与我们开发者辣么自由的操作空间,限定了只可以向上计数or只可以向下计数。
既然我们规定了计数的范围,那么从1计数到2,从2计数到3之间的时间周期是多少?我们如何实现计数周期的不变?
这个问题其实很简单。。。利用时钟啊!时钟的脉冲信号变化规律是很容易确定的。那么我们就可以直接使用时钟实现计数周期,即:
啥?刚刚说完计数周期,你现在给我来个计数时长?啥玩意?
哦,这哥们是拿来中断用的。
我们一开始提到了计数宽度,它决定了我们可以取到的最大计数值。但它也只是决定了我们可以取到的最大计数值,实际计数值CNT(count的简写)是多少,这不还是由我们自己定的嘛。根据项目需求,你想取多少就多少。即:
当向上计数or向下计数达到了CNT次后,计数就会溢出触发一次定时器中断。这个中断有什么用?别急,后面我们我讨论到它。
刚刚我们已经说了当向上计数or向下计数达到了CNT次,就会触发一次定时器中断。那么中断结束之后,计数器怎么继续计时?很简单,设计一个专门控制检测计数状态的模块,当每次计数值达到了我们指定的CNT后,就重置计时器,让它重新计数就OK了。
而这个重置操作,一般称为重装载计数器,我们可以通过操作相关寄存器去控制它。
根据以上信息,我们可以构筑出下图的定时器模型:
SysTick—系统定时器是属于 CM3 内核中的一个外设,内嵌在 NVIC 中。也常称为滴答定时器,因为它只要简单的计数功能。
系统定时器是一个 24bit 的向下递减的计数器(PS:这里只能向下计数),计数器每计数一次的时间为 1/SYSCLK。
因为 SysTick 是属于 CM3 内核的外设,所以所有基于 CM3 内核的单片机都具有这个
系统定时器,使得软件在 CM3 单片机中可以很容易的移植。系统定时器一般用于操作系统,用于产生时基,维持操作系统的心跳。
(以上为本人从野火的资料中,截取修改而来。)
对于Systick而言,有4个寄存器控制它,分别是:
有了上一节的内容做铺垫,对于这几个寄存器的出现应该不难理解。而且,如果我们需要直接操作寄存器的话,一般来说只需要操作前3个寄存器即可。当然,我们现在一般都直接用固件库操作啦。
而对于Systick的应用,我们一般都直接用于实现延时函数,做到精确延时。
从前面的介绍我们知道,当计数器的值到了我们指定的CNT后,会产生一次中断。
我们可以定义一个变量Delaytime。每次中断的时候都对Delaytime--处理。在延时函数中,我们只需要传入我们想要延时的时长time给Delaytime,判断Delaytime是否为0即可。
具体操作上,我们只需要调用固件库提供的库函数Systick_Config()即可。
这个函数只需要我们传入计数器的值,大大的简化了操作步骤,结合前面的简易模型看看:
那么一般传入参数是多少呢?以stm32f10x系列为例,系统时钟一般为72Mhz,因为单片机执行指令的速度是微秒级的,所以我们一般设定一次中断时间为1ms,即一般传参为72000。
只讲原理不讲应用示例都是耍流氓。。。
这里我使用野火的指南者实现1s的LED闪烁为举例。
《零死角玩转STM32—F103指南者》
为什么stm32 本身就有定时器,还要systick干嘛
通用定时器可以是16位,32位,单次,可重载由用户根据需求自己设置, 而且还可以实现捕捉和PWM。通用定时器/计数器应用起来更有针对性更实际些。
systick是系统滴答器,不同于普通的定时器。它可用来产生操作系统的时钟节拍,便于不同处理器之间程序移植,还可作为一个闹铃测量时间。
systick 是核心的一个组件,使用 cortex m 核心都带。显然一个时钟不够用。所以就增加了外设时钟。
Systick就是一个定时器而已,只是它放在了NVIC中,
主要的目的是为了给操作系统提供一个硬件上的中断(号称滴答中断)。
操作系统进行运转的时候,也会有“心跳”。它会根据“心跳”的节拍来工作,把整个时间段分成很多小小的时间片,
每个任务每次只能运行一个“时间片”的时间长度就得退出给别的任务运行,这样可以确保任何一个任务都不会霸占整个系统不放。
或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。
因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,
以维持操作系统“心跳”的节律。 只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息。
这样写更容易明白点,我要计时1ms的话,即1/1000s的时间,(1/1000)/(1/00可以看出我们要计时1ms的话设置为9000是这样得来的。其实上面的公式自己可以推导一下,设系统的时钟频率为SystemFrequency我们要给滴答定时器设置的值为SystemFrequency / (1/时间基准)。例如1ms的设置 / (1/0.001S)=9000.通过这里我们可以很容易的分配时间。注意设置的时候不要超过24位的最大值0xffffff.
} 看这个函数就很好理解,配置好要基准的时间,就等中断发生吧。
}在中断函数,我们可以划分时间片,不要使CPU空等待.也就是到达你想要的那个时间就执行你想做的动作,主要不超出时间片的时间就行。
为什么stm32 本身就有定时器,还要systick干嘛