前段时刻,做一个项目,有串口收发指令判别,按键类型判别,长短按之类,power的守时关电,事情的轮询扫描更新和display的守时扫描。这些要求就对守时器提出了要求,可是我的51单片机只要两个守时器,其间一个又有debug口的波特率发生之用。于是乎我可以用的守时器就只剩下了一个。怎么办?或许我们都只能用变量在守时中止函数去做多了使命就行了,可是我总是感觉这样会导致代码看起来太不具有条理性,并且关于日后的办理不是很简单。思来想去,就想到了linux内核中关于守时器的封装,那种面向对象的思维。
主意有了,我觉得完成便是很简单了。下面给我们贴上我的代码:
.h 文件:
#ifndef __SC_TIMER_H#define __SC_TIMER_H/* SC_Common.h文件中包括了对数据类型的界说和包括对应的单片机的装备头文件,这儿就没有列出,依据个人所使用情况而定 */#include "SC_Common.h"#ifdef MODE1T#define T0TIMES (65536-FOSC/1000)#define T1TIMES (65536-10*FOSC/1000)#else#define T0TIMES (65536-FOSC/12/1000) // 0.1ms#define T1TIMES (65536-10*FOSC/12/1000) // 10ms#endif /*MODE1T*/#define TIMER_SIZE 4typedef struct{U8 timerId; /* 守时器的id,实则指明晰起地点数组中的方位 */S8 isRuning; /* 标明当时timer是否正在运转 */U16 curTimes; /* 当时timer时刻 */U16 expireTimes; /* 当时timer的溢出时刻 */U8 existInArry; /* 当时的timer是否存在于数组之中 */TimerFunc timerFunc; /* 当时timer的指定运转函数 */} Timer;void InitTimer(void);S8 AddTimer(Timer *timer);S8 DelTimer(Timer *timer);S8 StartTimer(Timer *timer);S8 ModifyTimer(Timer *timer);S8 StopTimer(Timer *timer);S8 IsRunningTimer(Timer *timer);#endif /*__SC_TIMER_H*/
下面是这部分思维的要点完成,无非便是向timerArray数组中增加删去守时器,简言之,即所谓的增修改查,还有便是发动中止守时器,考虑到51单片机的功能,没有像linux内核中那样用链表完成,一起守时器的总数也是有上限要求的。
.c文件:
#include "SC_Timer.h"#include#include /* 这儿选用数组的方法办理各个timer结构体 */Timer timerArray[TIMER_SIZE];U8 timerUsed = 0;void InitTimer(void){TMOD |= 0x01;TL0 = T0TIMES;TH0 = T0TIMES >> 8;ET0 = 1;TR0 = 1;timerUsed = 0;memset(timerArray, 0, sizeof(timerArray));}S8 AddTimer(Timer *timer){if(timerUsed >= TIMER_SIZE)timerUsed = 0;/*×Ô¶šÒåtimerIdµÄÉú³É·œÊœ¬ŒŽŽú±íÆäÔÚÊý×éÖеÄλÖÃ*/timer->timerId = timerUsed;timerArray[timerUsed] = *timer;timerUsed++;timer->existInArry = 1;timer->isRuning = 0;printf("%bu\n", timer->timerId);return 0;}static void Del_Timer(Timer *timerArray, U8 *timerUsed, U8 pos){U8 i = 0;U8 len = *timerUsed;for(i=pos; i timerId >= TIMER_SIZE || timer->timerId < 0 || timer->existInArry == 0)return -1;if(timerUsed <= 0)return -1;Del_Timer(timerArray, &timerUsed, timer->timerId);timer->existInArry = 0;return 0;}S8 StartTimer(Timer *timer){if(timer->timerId >= TIMER_SIZE || timer->timerId < 0 || timer->existInArry == 0)return -1;timerArray[timer->timerId].isRuning = 1;return 0;}S8 ModifyTimer(Timer *timer){if(timer->timerId >= TIMER_SIZE || timer->timerId < 0 || timer->existInArry == 0)return -1;timerArray[timer->timerId].curTimes = timer->curTimes;timerArray[timer->timerId].expireTimes = timer->expireTimes;timerArray[timer->timerId].timerFunc = timer->timerFunc;return 0; }S8 StopTimer(Timer *timer){if(timer->timerId >= TIMER_SIZE || timer->timerId < 0 || timer->existInArry == 0)return -1;timerArray[timer->timerId].isRuning = 0;return 0;}S8 IsRunningTimer(Timer *timer){S8 ret = -1;if(timer->timerId >= TIMER_SIZE || timer->timerId < 0 || timer->existInArry == 0)return ret;ret = timerArray[timer->timerId].isRuning;return ret;}/* * 守时器的中止函数担任判别各个事情的时刻是否抵达,假如抵达调用相应的相应函数进行运转* 我们51单片机的函数指针是没有仓库维护的,所以这儿加入了汇编指令碑文仓库的维护,个人* 水平有限,这儿期望我们纠正是否有过错之处,谢谢*/void Tm0Isr(void) interrupt 1{ U8 i = 0;TL0 = T0TIMES;TH0 = T0TIMES >> 8;for(i=0; i = timerArray[i].expireTimes){#pragma asmpush ACCpush DPHpush DPL#pragma endasm(*timerArray[i].timerFunc)();#pragma asmpop DPLpop DPHpop ACC#pragma endasmtimerArray[i].curTimes = 0;}}}}
本文中的数据类型都是经过typedef转化过的,为了时时刻刻关于自己的内存使用量,,界说如下
typedef unsigned char U8;typedef unsigned short int U16;typedef unsigned long int U32;typedef signed char S8;typedef signed short int S16;typedef signed long int S32;typedef bit BOOL;
个人认为这个关于项目后边的可以有用快速的进行起到了很大的协助。 典型的用法如下:
Timer pressKeyTimer; /* 这儿的timer请使用全局变量,我们应该懂的,便是变量的生命周期的问题啦 */pressKeyTimer.curTimes = 0;pressKeyTimer.expireTimes = 11;pressKeyTimer.timerFunc = JudgeKeyType;AddTimer(&pressKeyTimer);StartTimer(&pressKeyTimer);
至此,到规则的时刻11msec时,就会调用这儿的JudeKeyType函数,进行轮询发现是否有按键按下,并判别其类型。
望有改善定见,谢谢高手纠正。