单片机定时器之改良版:时间轮定时器
扫描二维码
随时随地手机看文章
前段时间把自己以前用的单片机定时器整理出来,我称之为简单定时器,这种简单定时器比较适合定时器使用量少的程序中,如果定时器数量要求多,精度要求高,效率就会有问题,为此,俺就实现了一个时间轮定时器,简单测试下来效果非常不错。
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 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 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 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 ret