单片机定时器之改良版:时间轮定时器
前段时间把自己以前用的单片机定时器整理出来,我称之为简单定时器,这种简单定时器比较适合定时器使用量少的程序中,如果定时器数量要求多,精度要求高,效率就会有问题,为此,俺就实现了一个时间轮定时器,简单测试下来效果非常不错。
1 #ifndef __SOFT_TIMER_H__ 2 #define __SOFT_TIMER_H__ 3 4 #define EVENT_TYPE_ONESHOT 0 5 #define EVENT_TYPE_PERIODIC 1 6 7 #define TMR_POOL_SIZE 20 // 定时器池,即可用定时器个数 8 #define TMR_WHEEL_SIZE 8 // 时间轮的粒度 9 10 #define HANDLE int 11 12 typedef void (*pTimerProc)(void*); 13 14 void TimerInit(void); 15 HANDLE SetTimer(unsigned long uElapse,pTimerProc pFunc,void *para,unsigned int Tmr_type); 16 void KillTimer(HANDLE hTmr); 17 void TimerServer(void); // call in main loop 18 void TimerSignal(void); // call it in timer isr 19 unsigned long TmrGetTime(void); 20 21 #endif
简单介绍一下:
SetTimer():
参数uElapse:定时器超时时间. 参数pFunc:定时器超时回调函数. 参数para:定时器超时回调函数参数.参数Tmr_type:定时器类型,EVENT_TYPE_ONESHOT为单次定时器,定时器超时后,会被自动删除.EVENT_TYPE_PERIODIC 表示周期性定时器,使用完后需主动删除。
返回值:返回定时器id,用于删除定时器。
KillTimer(): 删除由SetTimer()创建的定时器。
TimerServer(): 定时器管理函数,需在主循环中调用。
TimerSignal(): 定时器信号函数,提供定时器运行所需节拍数,需在硬件定时器中断中调用,例如,硬件定时器10ms中断一次,在中断中调用TimerSignal(),则时间轮定时器的节拍时间为10ms.
TmrGetTime():记录定时器的节拍数,
1 #include "timer.h" 2 3 typedef struct _tagTimer{ 4 unsigned int elapse; 5 unsigned int interval; 6 void *prev; 7 void *next; 8 TimerProc pFunc; 9 void *para; 10 unsigned char state; 11 unsigned char event_type; 12 unsigned char timeout; 13 }Timer_Typedef; 14 15 typedef struct _tagTimerWheel{ 16 Timer_Typedef *pFirst; 17 unsigned int entries; 18 }TimerWheel_Typedef; 19 20 #define TMR_STATE_FREE 0 21 #define TMR_STATE_STOP 1 22 #define TMR_STATE_RUNNING 3 23 24 static Timer_Typedef _timerArray[TMR_POOL_SIZE]={0}; 25 static TimerWheel_Typedef TmrWheel[TMR_WHEEL_SIZE]={0}; 26 static Timer_Typedef* tmr_free_list; 27 static unsigned tmr_free_slot = 0; 28 static unsigned _tmr_tick = 0; 29 30 31 static Timer_Typedef* Tmr_alloc(void); 32 static void Tmr_free(Timer_Typedef* pTmr); 33 static void Tmr_link(Timer_Typedef* pTmr); 34 static void Tmr_unlink(Timer_Typedef* pTmr); 35 36 37 void TimerInit(void) 38 { 39 int i = 0; 40 for(i=0;i<TMR_POOL_SIZE-1;++i) 41 { 42 _timerArray[i].next = (void*)(&_timerArray[i+1]); 43 } 44 _timerArray[TMR_POOL_SIZE-1].next = (void*)0; 45 tmr_free_list = _timerArray; 46 tmr_free_slot = TMR_POOL_SIZE; 47 48 for(i=0;i<TMR_WHEEL_SIZE;++i) 49 { 50 TmrWheel[i].pFirst = (void*)0; 51 TmrWheel[i].entries = 0; 52 } 53 } 54 55 HANDLE SetTimer(unsigned long uElapse,TimerProc pFunc,void *para,unsigned int Tmr_type) 56 { 57 int unused_slot = -1; 58 Timer_Typedef *pTmr = (Timer_Typedef *)0; 59 60 pTmr = Tmr_alloc(); 61 if(pTmr) unused_slot = pTmr - _timerArray; 62 63 if(unused_slot != -1) 64 { 65 _timerArray[unused_slot].pFunc = pFunc; 66 _timerArray[unused_slot].para = para; 67 _timerArray[unused_slot].interval = uElapse; 68 _timerArray[unused_slot].event_type = Tmr_type; 69 _timerArray[unused_slot].state = 1; 70 Tmr_link(pTmr); 71 } 72 return unused_slot; 73 } 74 75 void KillTimer(HANDLE hTmr) 76 { 77 if((hTmr >= 0)&&(hTmr < TMR_POOL_SIZE)) 78 { 79 switch(_timerArray[hTmr].state) 80 { 81 case TMR_STATE_STOP: 82 Tmr_free(&_timerArray[hTmr]); 83 break; 84 case TMR_STATE_RUNNING: 85 Tmr_unlink(&_timerArray[hTmr]); 86 Tmr_free(&_timerArray[hTmr]); 87 break; 88 default: 89 break; 90 } 91 _timerArray[hTmr].timeout = 0; 92 } 93 } 94 95 void TimerServer(void) 96 { 97 int i = 0; 98 Timer_Typedef* pTmr = _timerArray; 99 for(i = 0;i<TMR_POOL_SIZE;++i) 100 { 101 if((pTmr->timeout)&&(pTmr->pFunc)) 102 { 103 (*(pTmr->pFunc))(pTmr->para); 104 pTmr->timeout = 0; 105 } 106 pTmr++; 107 } 108 } 109 110 111 void TimerSignal(void) 112 { 113 int spoke = 0; 114 Timer_Typedef* pTmr,*pNext; 115 116 ++_tmr_tick; 117 spoke = _tmr_tick%TMR_WHEEL_SIZE; 118 pTmr = TmrWheel[spoke].pFirst; 119 while(pTmr) 120 { 121 pNext = pTmr->next; 122 if(pTmr->elapse == _tmr_tick) 123 { 124 Tmr_unlink(pTmr); 125 if(pTmr->event_type == EVENT_TYPE_PERIODIC) 126 { 127 Tmr_link(pTmr); 128 } 129 else 130 { 131 Tmr_free(pTmr); 132 } 133 pTmr->timeout = 1; 134 } 135 pTmr = pNext; 136 } 137 } 138 139 static void Tmr_link(Timer_Typedef* pTmr) 140 { 141 int spoke; 142 TimerWheel_Typedef *pWhl; 143 pTmr->state = TMR_STATE_RUNNING; 144 pTmr->elapse = pTmr->interval + _tmr_tick; 145 spoke = pTmr->elapse%TMR_WHEEL_SIZE; 146 pWhl = &TmrWheel[spoke]; 147 148 if(pWhl->pFirst) pWhl->pFirst->prev = pTmr; 149 150 pTmr->next = pWhl->pFirst; 151 pWhl->pFirst = pTmr; 152 pWhl->entries++; 153 } 154 155 static void Tmr_unlink(Timer_Typedef* pTmr) 156 { 157 int spoke; 158 TimerWheel_Typedef *pWhl; 159 pTmr->state = TMR_STATE_STOP; 160 spoke = pTmr->elapse%TMR_WHEEL_SIZE; 161 pWhl = &TmrWheel[spoke]; 162 163 if(pWhl->pFirst == pTmr) 164 { 165 pWhl->pFirst = pTmr->next; 166 if(pTmr->next) ((Timer_Typedef*)pTmr->next)->prev = (void*)0; 167 } 168 else 169 { 170 ((Timer_Typedef*)pTmr->prev)->next = pTmr->next; 171 if(pTmr->next) ((Timer_Typedef*)pTmr->next)->prev = pTmr->prev; 172 } 173 pWhl->entries--; 174 } 175 176 177 static Timer_Typedef* Tmr_alloc(void) 178 { 179 Timer_Typedef *pTmr = (Timer_Typedef*)0; 180 if(tmr_free_list) 181 { 182 pTmr = tmr_free_list; 183 tmr_free_list = tmr_free_list->next; 184 tmr_free_slot--; 185 } 186 return pTmr; 187 } 188 189 190 191 static void Tmr_free(Timer_Typedef* pTmr) 192 { 193 pTmr->state = TMR_STATE_FREE; 194 pTmr->prev = (Timer_Typedef*)0; 195 pTmr->next = tmr_free_list; 196 tmr_free_list = pTmr; 197 tmr_free_slot++; 198 } 199 200 unsigned long TmrGetTime(void) 201 { 202 return _tmr_tick; 203 }