关于每个单片机爱好者及工程开发规划人员,在刚触摸单片机的那开端的青翠年月里,都有过点亮跑马灯的阅历。从看到那一排排小灯按着咱们的主意在跳动时激动心境。到跟着经历越多,越来又会感觉到这个小灯是个好东西,尤其是在调试资源有限的环境中,有时会帮上大忙。
但关于绝大多数人,咱们在最开端让灯闪耀起来时大约都会用到堵塞延时完结,会像如下代码的姿态:
然后,在咱们触摸到守时器,咱们会发现,原来用守时中止来处理睬更好。比方咱们能够500ms中止一次,让灯亮或灭,其他的时刻体系还能够做十分之多的作业,功率一下提升了许多。
这时咱们就会渐渐意识到,第一种(堵塞延时)办法功率很低,让芯片在那儿空运转几百毫米,什么也不做,真是极大的糟蹋,尤其在芯片频率较高,使命又许多时,这样做就像在平整宽广的高速公路上挖了一大坑,呈现事端可想而知。
但一个单片机中的守时器究竟有限,假如我需求几十个或许更多不同时刻的守时中止,每一个时刻到都完结不同的处理动作,怎么去做呢。一般咱们会想到在一个守时中止函数中再界说static 变量持续守时,到了所需时刻,做不同的动作。而这样又会导致在一个中止里做了许多不同的作业,会抢占主轮询更多时刻,有时乃至喧宾夺主,并也不是很如的思想逻辑。
那么有没有更好的办法来完结呢,答案是必定的。下面介绍我在一个项目中偶遇,一个精妙规划的非堵塞守时延时软件的规划(此规划首要针关于无操作体系的裸机程序)。
在上篇文章中有对systick的介绍,比方我要设置其10ms中止一次,怎么完结呢?
也很简单,只需调用core_cm3.h文件中 SysTick_Config函数 ,当体系时钟为72MHZ,则设置成如下即可SysTick_Config(720000); (递减计数720000次后中止一次) 。此刻SysTick_Handler中止函数就会10ms进入一次;
使命守时用软件是怎么规划的呢 ?
且先看其数据结构,这也是精妙所在之处,在此作自顶向下的介绍:
其界说结构体类型如:
其间Char_Field 为一联合体,规划如下:
而它内部的Timer_Bit是一个可按位拜访的结构体:
此联合体的这样规划的意图将在后边的代码中体现出来。
如此结构体的规划就完结了。
然后咱们界说的一全局变量,Timer_Struct gTimer;
并在头文件中宏界说如下:
别的为了后边程序明晰,再界说一状况指示:
至此,预备作业就完结了。下面咱们就开端大显身手了!
首要,10ms守时中止处理函数如,能够看出,每抵达10ms 将把bTemp10Msec置1,每50ms 将把bTemp50Msec置1,每100ms 将把bTemp100Msec置1,每1s 将把bTemp1Sec置1,
而这又有什么用呢 ?
这时,咱们需在主轮询while(1)内最开端调用一个守时处理函数如下:
此函数最初与结束两句:
就别离奇妙的完结了bSystemXXX (低4位) 和 bTempXXX(高4位)的清零作业,不必再等守时抵达后还需手动把计数值清零。此处清零作业用到了联合体中的变量共用一个开始存储空间的特性。
但要确保while(1)轮询时刻要远小于10ms,否则将导致守时延时不精确。这样,在每轮询一次,就先把bSystemXXX ,再依据bTempXXX判别是否时刻抵达,并把对应的bSystemXXX 置1,而后边一切的使命就都能够经过bSystemXXX来进行守时延时,在最终函数退出时,又会把bTempXXX清零,为下一次时刻抵达后查询判别作好了预备。
说了这么多,举例说明一下怎么使用:
以上示例四个使命进程,
在主轮询里可进行如下处理:
这样,就能够轻松且明晰完结了多个使命,不同时刻内处理不同工作。(但留意,每个使命处理中不要有堵塞延时,也不要处理过多的作业,致使处理时刻较长。可规划成状况机来处理不同使命。)