《MCU软件定时器常见的实现方式.docx》由会员分享,可在线阅读,更多相关《MCU软件定时器常见的实现方式.docx(37页珍藏版)》请在课桌文档上搜索。
1、在一般的嵌入式产品设计中,介于成本、功耗等,所选型的MCU基本都是资源受限的,而里面的定时器的数盘更是有限.在我们软件设计中往往有多种定时需求,例如脉冲输出、按捷检测、1.CD切屏延时等等,我们不可能让每一个定时业务都去开一个硬件定时器,一来硬件资源可能不足,二米会使软件过度依赖F健件平台,从而导致较差的可移植性.而若我们有一个软件定时器,所有定时业务都依赖于软件定时器,不仅节省硬件资滁,以后在移植的时候也只需要将软件定时器和硬件相关的部分修改就行了,其他部分都不用动。软件定时器实现方式:一、用结构体数蛆的方式实现软件定时器用结构体数组的方式实现起来较简单,也容易理解,除此之外和之后的链去实现
2、方式比起来没有其他优点。但还是介绍一下实现方法:在结构体数组内定义一个Start标志和定时时长duration,还有一个为计数值count,这3个变量为爆墙本的3个变量,其他的可以自己补充,比如运行模式、向调函数指针等.还有就是每一个结构体数组就是一个定时滞.能要我们提前定义好这个结构体数组有多大。定义好之后,在开启定时渊的时候我们将对应的数组内Start标志置位,在硬件tick中断服务函数里面我们去向所有结构体数组内的Stan标志是否置位,当查到当前start被置位时将此数组内的duration和count做比较,如果相等就说明此定时器定时时间到了,如果不等就将count+.然后接着查其他数
3、组的start标志,以此无限循环.此种方式缺点非常明显,那就是在硬件tick中断服务函数内,我们得轮询所有数组,如果我们软件业务需求是20个定时任务,那我们就存在软件定时器的实现里定义20个数组,空间浪费倒是其次的,关键是硬件tick轮询的数组越多,执行到某个数组的时间就越长,若以后有50个、100个定时需求时,将会导致定时时间极不精准.二、用链表实现软件定时得介于以上用结构体数组实现软件定时的种种缺点,我们提出改进方案.经过分析,在大多数定时业务中,往往只M要在某个时间段定时一次,也就是说定时岩会开R定时和结束定时,当然,用数组的实现的定时岩也可以开启定时和关闭定时,只需要用Start标志去
4、决定就行了,但是用散组实现的方式中,即使你关闭了定时器,也就是去掉了Start标志,此定时器虽然不运行了,但是数组的空间不会减少,梗件tick依然要轮询所有数组。所以我们福要用链表来实现软件定时器,在硬件tick中轮询所有节点,开启一个定时那就加入一个书点,关闭定时器就删除一个节点,可以保证在当前时刻只轮询器要定时的节点,可以极大的保证定时准确性.在加上可以让用户选择定时时间到了直接在硬件tick内执行或者在硬件tick内置标志,然后在whi1.e循环内排队执行,可以非常有效的解决关键业务定时不精准的问即.比如脉冲输出这种需要定时准确的业务.性表实现方式H文件:* sfor_timer_1.i
5、st.h* 彼表实现的软件定时器库* /*1.fndef_SOFT_TIMER_1.IST_H-define* 硬件中断tick* /edefineriMER_HARD_TICK1Ums,硬件tick取决于硬件定时中断时间*/typedefenumONCE_MODE,公行延时单次定时愎式,即超时后自动关闭定时器/CONTINUEJODE,/持续定时模式.只转开J:除非手动关闭否则永不停歇/DEFINjNUM_MODE,/*定义次数的模式行指定的次数后关闭定时器*/TimerTimi11gModeType;/typedefenumRUN_IN_1.OOP_MODE,*轮询执行模式*/RUN_IN
6、_INTERRUPT_MODE,/*中断实时执行模式/JTimerRunModeType;*软件定时器根本类型*/typedefstructSoftTimerunsigned1.ongcounter;*计数*/unsigned1.ongduration;*定时时长*/unsigned1.ongrun-num;*自定义的定时次数*/BOO1.Start_f1.ag;*启动标志/BOO1.1.oop_f1.ag;*轮询标志*/数TimerRunModeTyperun-mode;TimerTimingModeTypetimingJnOe1.e;void(*ca1.1.back_function)(v
7、oid);/*回调函structSoftTimer,next;SoftTimer;duration:要计时的时长,冷位为硬件中断的tick*timeout_hand1.er:定时到了之后要执行的函数指针return:无/externvoidcreat_sing1.e_soft_timer(SoftTimer*p,TimerRunModeTypemode,unsigned1.ongduration,void(*timeout-had1.er)(void);/*创建永远运行的软件定时器并立刻开始计时* 初始化软件定时器的硬件tick/externvoidsoft_timer_tick_init(v
8、oid);* 创建一个只运行次的软件定时器并立刻开始计时* 参数表:p:定时器结构体指针,由用户创建*mode:选择运行模代,可选定时器到了之后是H接在tick中断内执行还是置起标志在WhiIe循环内轮询执行*参数表:P:定时器结构体指针,由用户创建* mode:选择运行模式,可选定时器到了之后是直接在tick中断内执行还是置起标志在WhiIe循环内轮起执行* duration:要计时的时长,单位为硬件中断的tick* timeOUt.hand1.er:定时到了之.后要执行的函数指什* return:无externvoidcreat_continue_soft_timer(SoftTimerm
9、ode:选择运行模式,可选定时器到了之后是直接在tick中断内执行还是置起标志在whi1.e循环内轮渐执行*duration:要计时的时长,单位为映件中断的tick*time。UjhandIer:定时到了之后要执行的函数指针*return:无*/externvoidrestart_sing1.e_soft_timer(SoftTimer*p,TimerRunModeTypemode,unsigned1.ongduration,void(*timeout-hand1.er)(void);/*p,TimerRunModeTypemode,unsigned1.ongduration,void(*ti
10、meout_hand1.er)(void)* 创建指定次数运行的软件定时器并立刻开始计时* 参数表:p:定时器结构体指针,由用户创建eTypemode,unsigned1.ongrun_num,unsigned1.ongduration,void(timeout-ha11d1.er)(void);/* 重启指定的单次软件定时器* 参数衣:p:定时器结构体指针,由用户创建* 系统main循环进程,用于执行轮询模式的回调函数/externvoidsoft_timer_main_1.oop(void);* 此函数为tick中断服务函数,而要桂我在外部硬件定时器上* 因此蟆件定时器的定时精度由此函数挂
11、载的硬件定时时间决定,* 比如此函数挂载在定时50ms的外部定时器上,那么定时dutation* 为2。时定时时间就是2e*50ms=1.S* /externvoidsystem_tick_IrqHand1.er(void);endif*!1SOFTTIMER_1.IST_H/C文件:sfor_timer_1.ist.c* 链表实现的软件定时阵SdefineNU1.1.(void*软件定时器内部变量/staticSoftTimerhead-point=NU1.1.;staticstructSoftTimer*creat-node(SoftTimer*node);staticcharde1.et
12、e-node(SoftTimer*node);staticBOO1.is_node_a1.ready_creat(SoftTimertnode);初始化软件定时器的硬件tick*/voidsoft_timer_tick_init(void)R_IT_Create();1.1.11j.-,iWtick10ms/)0)typedefenumFA1.SE=,TRUE=!FA1.SEBOO1.;inc1.udemeter_inc1.ude.h包含用户的燃件定时滞初始化南族inc1.udesoft_timer_1.ist.hR_IT_Start();*系统main衡环进程,用于执行轮询模式的回调函数*/
13、voidsoft_timer_main_1.oop(void)(structSoftTimerp1.=head-poi11t;whi1.e(p1.I=NU1.1.)卜二不为,if(p1.-1.oop_f1.ag=TRUE)p1.-1.oop_f1.ag=FA1.SE;p1.-ca1.1.back-function();if(p1.-start-f1.agI=TRUE)de1.ete,node(p1.);*寻找下个有意义的节点*/p1.p1.-next;/*创建一个只运行一次的软件定时器并刻开始计时*参数表:p:定时器结构体指针,由用户创建 mode:选择运行模式,可选定时器到了之后是直接在ti
14、ck中断内执行还是月起标志在Whi1.e沛环内轮询执行 duration:要计时的时长,通位为硬件中断的tick timeout,hand1.er:定时到了之后要执行的函数指针 return:无 /voidcreat_sing1.e_soft_timer(SoftTimerp,TimerRunModeTypemode,unsigned1.ongduration,void(timeout-ha11d1.er)(void)if(p=NU1.1.)II(timeout_hand1.er=NU1.1.)duration=0)return;p-start-f1.agTRUE;p-counter=0;p-
15、1.oop-f1.ag三FA1.SE;p-duration=duration;if(modeRUN_IN_1.OOP_MODE)p-run-mode=RUN_IN_1.OOP_MODE;e1.sep-run_mode=RUN_IN_INTERRUPT_MODE;p-ca1.1.back-function=timeout-hand1.er;p-timing-mode=ONCE_MODE;p-run-num=0;/1.m1.门定M故的靖一卜此片dhead-point=creat-node(p);)* 创建永远运行的软件定时器并立刻开始计时* 参数表:p:定时器结构体指针,由用户创建* mode:选
16、择运行模式,可选定时器到J之后是直接在tick中断内执行(除非实在必要)还是置起标志在whi1.e循环内轮询执行* duration:要计时的时长,单位为政件中断的tick* time。UJhand1.er:定时到了之后要执行的函数指针return:无voidcreat_continue_soft_timer(SoftTimer*p,TimerRunModeTypemode,unsigned1.ongduration,void(*timeout-hand1.er)(void)if(p=NU1.1.)II(timeout-hand1.er=NU1.1.)duration=0)return;p-s
17、tart_f1.agTRUE;p-counter=0;p-1.oop_f1.ag=FA1.SE;p-duration=duration;if(mode-RUN_IN_1.OOP_MODE)p-run-mode=RUN_IN_1.OOP_MODE;e1.sep-run-mode=RUN_IN_INTERRUPT_MODE;p-ca1.Iback_function=timeout-hand1.er;p-timing-mode=CoNT1.NUE_MODE;p-run-num=0;效*/head-point=creat_node(p);/* 创建指定次数运行的软件定时器并立刻开始计时* 参数表:P:
18、定时器结构体指针.由用户创建* mode:选择运行模式,可选定时器到了之后是直接在tick中断内执行还是直起标志在WhiIe循环内轮询执行* run_num:要定时的次数,比如1就是定时1次,5就足定时5次以if(modeRUN_IN_1.OOP_MODE)p-run-mode=RUN_IN_1.OOP_MODE;e1.sep-run_mode=RUN_IN_INTERRUPT_MODE;p-ca1.1.back_functiontimeout_hand1.er;p-timing-mode=DEFINE_NUM_MODE;p-run-num=run_num;timeout_hand1.er:定
19、时到j之后要执行的函数指舒return:无*/voidrestart_sing1.e_soft_timer(SoftTimerp,TimerRunModeTypemo只T。门定义七行次数的情况?此值才有效*/head-point=creat_node(p);de,unsigned1.ongduration,void(*timeout-hand1.er)(void)(if(p-NU1.1.)II(timeout-hand1.erNU1.1.)duration0)return;p-StarjfIag=TRUE;p-counter-0;p-1.oop_f1.ag=FA1.SE;p-duration=
20、duration;if(mode=RUN_IN_1.OOP_MODE)p-run-mode-RUN_IN_1.OOP_MODE;e1.sep-run_modeRUN_IN_INTERRUPT_MODE;p-ca1.1.back-function=time。UJhand1.er;p-timing-mode=ONCE_MODE;-run-num-0;xcounter0;p-start-f1.ag=FA1.SE;de1.ete_node(p);)staticstructSoftTimercreat-node(SoftTimer*node)structSoftTimer*p1.;/p1.1-6if(n
21、ode=NU1.1.)returnhead_point;if(i$_node_a1.ready-creat(node)!=FA1.SE)de1.ete.node(node);,还是删除后重新创建,目前不新创建*/当头节点为空时,将传入的节点作为头节点,返回头节点if(head_pointNU1.1.)head_point=node;node-ext-NU1.1.;returnhead-point;)p1.=head-point;whi1.e(p1.-next!=NU1.1.)p1.=p1.-net;/移个:,.if(p1.-next-NU1.1.)(p1.-net=node;node-next
22、=NU1.1.;e1.sereturnhead-point;staticcharde1.ete-node(SoftTimer*node)structSoftTimer*p1.;,p1.,structSoftTimertemp;if(node=NU1.1.)return1;p1.=head-point;if(nodehead-point)head-point-head-point-net;*.一;/.二Jii.7头指针后移*/e1.sewhi1.e(p1.I=NU1.1.)头5如果不为/temp=p1.;:已录当F:节点*/p1.=p1.-next;*i4fj:1.;个节,/if(p1.NU1.
23、1.)return1;if(p1.=node)temp-net=1.-net;4.,1Ireturn0;)return0;staticBOO1.is_node_a1.ready_creat(SoftTimer*node)structSoftTimer*p1.;/p1.if(node=NU1.1.)returnFA1.SE;p1.=head-point;whi1.e(p1.!NU1.1.)(if(p1.node)returnTRUE;p1.=1.-net;后移个节点returnFA1.SE;没有到达没switch(p1.-timing-mode)(caseONCE_MODE:p1.-startf
24、1.ag=FA1.SE;break;caseCONTINUEeMODE:break;caseDEFINEeNUMeMOOE:if(p1.-runnum)(if(-p1.-run-nutn0)(1.-start-f1.ag=FA1.SE;)defau1.t:break;if(p1.-run-mode-RUN_IN_INTERRUPT_MODE)1.-ca1.1.back-function();/结构体实现方式最后在附上用结构体数组实现的软定时器以作参考.H文件:像一些超时判断类的应用以轮询的方式进行执行*中断执行模式越多.其他定时器越不准,毕竟中断允许占时间,查询其他定时器时:;U1.mf.二i
25、.回调函数,用于实时性比较扁的程序/if(p1.-start-f1.ag!TRUE)de1.ete_node(p1.);e1.sep1.-1.oop_f1.agTRUE;p1.-counter=0;寻找下一个有意义的节点/=p1.-net;open_g1.oba1._ir();/*自动切换中断实时操作或者不实时的轮询操作,可以有效解决硬件资源*不足或者软件定时器定时不准的问Sg.定时误差就几个C语言语句,倘若 限也最大1。个软件定时器,误咨就是以多个for循环的时间*/ifndefSOFTJIMER_ARRAY_Hdefine_SOFT_TTMER_ARRAY_H 定义七大的可用的软件定时器数
26、或 理论上可以无限大,但是数量:越大定时误差越大,所以用几个开几个*误差在于轮询检测所有定时器,定时器越多轮询到自己的定时器就越慢.此外,数G用多亦会带来空间增大ONCE_MODE,/*的次定时模式,即超时后自动关闭定时器会有延时/typedefenum/C0NTINUE_M0DE,/*持续定时模式,只要开启除小手动关闭否则永不停歇*/DEFINE_NUM_MODE,/*定义次数的模式,运行指RUN_IN_1.00P_M0DE,/*轮询执行模式*/定的次数后关闭定时器/JTimerTimingModeType;*定时超时后运行的回调函数可以选择在中断宜接运行或者挂起任:务轮询执行只要在定时窗求
27、准确的时候才建议选择中断模式执行,类似无磁传感器冲测中断实时执行模式*/RUN_IN_INTERRUPT_MODE,JTimerRunModeType;软件定时器在本类型*/typedefstructunsigned1.ongcounter;*计数*/unsigned1.ongduration;*定时时长*/unsigned1.ongrun_num;*自定义的定时次数/unsignedcharStarjf1.ag;*启动标志*/unsignedchar1.oop_f1.ag;*轮海标志*/TimerRunModeTyperun-mode;TimerTimingModeTypetiming_mo
28、de;void(ca1.1.back-function)(void);t-:t/JSoftTimer;系统main循环进程,用于执行轮询模式的回调函数*删除一个软件定时器*/externvoidstop_timer(void(*创建一个软件定时牌并立刻开始计时return:没有空闱定时器时返回1,创建成功时返回。/externcharsoft_timer_start(TimerTimingModeTypetiming-mode,TimerRunModeTyperun-mode,unsigned1.ongrun-num,unsigned1.ongduration,void(*ca1.1.back
29、-function)(void);ca1.1.back-function)(void);externvoidsoft_timer_main_1.oop(void);* 此函数为tick中断服务因数,商要挂我在外部硬件定时潜上因此软件定时器的定时精度由此函数挂我的硬件定时时间决定,* 比如此函数挂载在定时50ms的外部定时器.那么定时dutation* 为2。时定时时间就是20sfor_timer_array.c*数组实现的软件定时器库一个软件定时滞解决整个项目中所有的定时需求何调函数可根据应用*自动切换4,断实时操作或者不实时的轮询操作,可以解决强件资源*return;没有空闲定时器时返【可1
30、,创建成功时返回。/charsoft_timer_start(TimerTimingModeTypetiming-mode,TimerRunMOdeTyperun-mode,unsigned1.ongrun-num,unsigned1.ongduration,void(ca1.1.back_function)(void)unsignedchari=0;if(!ca1.1.back-function)return1;50ms-1.S* /externvoidsystem_tick_IrqHandIer(void);endif/!1_SOFT_TIMER_1.IB_H/C文件:*不足或者软件定时器
31、定时不准的何战*/inc1.udesoft_timerarray.h*软件定时器内部变幻*/staticSoftTimersoft_timerMAX_TIMER_NUM;/创建一个软件定时器并立刻开始计时stop_timer(ca1.1.back_function);4.i1.1.1.JIz有的话先删除*/for(i-0;iMAX_TIMER_NUM;i+)if(soft-timeri.start-f1.ag=0)*r1!-.器*/(Sofjtimeri.StarJf1.ag=1;soft-timeri.counter=0;soft-timeri.1.oop-f1.ag=0;soft_time
32、ri.duration三duration;soft-timeri.run-mode=run_mode;soft_timeri.ca1.1.back-function=ca1.1.back-function;if(soft-timeri.timing-mode=timing-mode)=DEFINE_NUM_MODE)soft_timeri.run_num=run-num;只有在自定义运行次数的情况下比值才有效*/break;*没有空闲定时器*/)if(i=MAX_TIMER_NUM)return1;return0;删除一个软件定时器*/voidstop-timer(void(*ca1.1.ba
33、ck-function)(void)unsignedchari;for(i=0;iMAX_TIMER_NUM;i+)if(soft-timeri.ca1.1.back-function=ca1.1.back_function)soft_timeri.start-f1.ag=0;soft_timeri.1.oop-f1.ag=0;*系统main环进程,用于执行轮询模式的回调函数voidsofttimermain-1.oop(void)unsignedchari;for(i=;iMAX_TIMER_NUM;i+)*电而执fjH函数/if(soft-timeri.1.oop-f1.ag=1)soft
34、_timeri.1.oop-f1.ag=0;SOfjtimeri.ca1.1.back-function();I1.return;运行一次任务后就退出去等胞一轮后运行卜.个程序防止任务堆枳在一起运行*/)*此函数为tick中断服务函数,需要挂旗在外部硬件定时器上内此软件定时器的定时精度由此函数挂栽的硬件定时时间决定,* 比如此函的挂被在定时5ms的外郃定时器上,那么定时dutation* 为2。时定时时间就足20*50ms=1.S* /voidSyStem_ticJIrqHand1.er(VOid)(unsignedchari0;for(i=0;i=soft-timeri.duration)*
35、,Mr,川时仃没仃达/switch(Soft_timeri.timingJnOde)caseONCE_MODE:soft-timeri.start-1.ag=0;break;caseCONTINUEeMODE:break;caseDEFIN-NUM-M0DE:if(softtimeri.run-num0)(if(-soft-timeri.run-num0)(soft-timeri.start_f1.ag-0;)defau1.t:break;)if(soft,timeri.ru-modeRUN_IN_INTERRUPT_MODE)soft_timeri.ca1.1.back-function()
36、;*,1.,断内直接运行回调函数用F实时性比较高的程序/e1.sesoft-timeri.1.oop-f1.ag=1;soft_timeri.counter-0;I1.e1.sedefineTIMER_200MS_TICK(200U/TIMER_HARD_TICK)/TIMER_HARD_TICK(2)三100mSdefineTIMER_SEC_TICK(1000U/TIMER_HARD_TICK)/TIMER_HARD_TICK*(2)=IS*定时模式选择定时超时后运行的回调函数可以选择在中断出接运行或者挂起任务轮询执行*只要在定时需求准确的时候才建议选择中断模式执行,类似无磁传感器脉冲测K
37、像一些超时判断类的应用以轮询的方式进行执行*中断执行模式越多.其他定时器越不准,毕竟中断允许占时间,一询其他定时器时*return:无externvoidcreat1.imitnumsofttimer(SoftTimerp,TimerRunModmode:选择运行模式,可选定时器到了之后是直接在tick中断内执行还是置起标志在whi1.e循环内轮i团执行*run_num:要定时的次数,比如就是定时T次,S就是定时5次以后自动关闭定时器*duration:要计时的时长,冷位为硬件中断的ticktimeout-ha11d1.er:定时到之后要执行的函数指针*眈除一个软件定时器*/externvoi
38、dstop-timer(SoftTimer*p);后自动关闭定时器*duration:要计时的时长,中一位为硬件中断的tick*time。UJhandIer:定时到了之后要执行的函数指针return:无*/voidcreat_1.imit_num_soft_timer(Softimer*p,TimerRunModeTypemode,unsigned1.ongrun-num,unsigned1.ongduration,void(*timeout-hand1.er)(void)(if(p三=NU1.1.)II(timeout-hand1.er=NU1.1.)duration=0)return;p-
39、start-f1.agTRUE;p-counter=0;p-1.oop-f1.agFA1.SE;p-duratio11=duration;*垂启指定的单次软件定时器*参数表:p:定时器结构体指针,由用户创建*mode:选择运行模式,可选定时器到了之后是它接在tick中断内执行还是说起标志在Whi1.e衡环内轮询执行*duration:要计时的时长,冷位为硬件中断的tick*此函数为tick中断用务函数,需要挂毂在外部便件定时器上*因此软件定时器的定时精度由此函数挂教的硬件定时时间决定,比如此函数扑载在定时5ms的外部定时器上,那么定时dutation为20时定时时间就是20*50ms=1.S*/voidsystem_tick_IrqHand1.er(void)structSoftTimerp1.=head-point;c1.ose_g1.oba1._ir();,闭中断.根禺由T台佬改whi1.e(p1.I=NU1.1.)下个。力.0米不为;if(p1.-start,f1.ag!=FA1.SE)*I1.JM启/if(+p1.-counter=p1.-duration)*sfor_timer_arrayh数组实现的软件定时库个软件定时器解决整个项目中所有的定时需求,回调函数可根据应用*/defineMAXJ1.MER_NUM10*定时模式选择*/typedefenum