单片机定时器之改良版:时间轮定时器
前段时间把自己以前用的单片机定时器整理出来 , 我称之为简单定时器 , 这种简单定时器比较适合定时器使用量少的程序中 , 如果定时器数量要求多 , 精度要求高 , 效率就会有问题 , 为此 , 俺就实现了一个时间轮定时器 , 简单测试下来效果非常不错 。
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{
4unsigned int elapse;
5unsigned int interval;
6void *prev;
7void *next;
8TimerProc pFunc;
9void *para;
10unsigned char state;
11unsigned char event_type;
12unsigned char timeout;
13 }Timer_Typedef;
14
15 typedef struct _tagTimerWheel{
16Timer_Typedef *pFirst;
17unsigned 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 {
39int i = 0;
40for(i=0;i41{
42_timerArray[i].next = (void*)(&_timerArray[i+1]);
43}
44_timerArray[TMR_POOL_SIZE-1].next = (void*)0;
45tmr_free_list = _timerArray;
46tmr_free_slot = TMR_POOL_SIZE;
47
48for(i=0;i49{
50TmrWheel[i].pFirst = (void*)0;
51TmrWheel[i].entries = 0;
52}
53 }
54
55 HANDLE SetTimer(unsigned long uElapse,TimerProc pFunc,void *para,unsigned int Tmr_type)
56 {
57int unused_slot = -1;
58Timer_Typedef *pTmr = (Timer_Typedef *)0;
59
60pTmr = Tmr_alloc();
61if(pTmr) unused_slot = pTmr - _timerArray;
62
63if(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;
70Tmr_link(pTmr);
71}
72return unused_slot;
73 }
74
75 void KillTimer(HANDLE hTmr)
76 {
77if((hTmr >= 0)&&(hTmr < TMR_POOL_SIZE))
78{
79switch(_timerArray[hTmr].state)
80{
81case TMR_STATE_STOP:
82Tmr_free(&_timerArray[hTmr]);
83break;
84case TMR_STATE_RUNNING:
85Tmr_unlink(&_timerArray[hTmr]);
86Tmr_free(&_timerArray[hTmr]);
87break;
88default:
89break;
90}
91_timerArray[hTmr].timeout = 0;
92}
93 }
94
95 void TimerServer(void)
96 {
97int i = 0;
98Timer_Typedef* pTmr = _timerArray;
99for(i = 0;i100{
101if((pTmr->timeout)&&(pTmr->pFunc))
102{
103(*(pTmr->pFunc))(pTmr->para);
104pTmr->timeout = 0;
105}
106pTmr++;
107}
108 }
109
110
111 void TimerSignal(void)
112 {
113int spoke = 0;
114Timer_Typedef* pTmr,*pNext;
115
116++_tmr_tick;
117spoke = _tmr_tick%TMR_WHEEL_SIZE;
118pTmr = TmrWheel[spoke].pFirst;
119while(pTmr)
120{
121pNext = pTmr->next;
122if(pTmr->elapse == _tmr_tick)
123{
124Tmr_unlink(pTmr);
125if(pTmr->event_type == EVENT_TYPE_PERIODIC)
126{
127Tmr_link(pTmr);
128}
129else
130{
131Tmr_free(pTmr);
132}
133pTmr->timeout = 1;
134}
135pTmr = pNext;
136}
137 }
138
139 static void Tmr_link(Timer_Typedef* pTmr)
140 {
141int spoke;
142TimerWheel_Typedef *pWhl;
143pTmr->state = TMR_STATE_RUNNING;
144pTmr->elapse = pTmr->interval + _tmr_tick;
145spoke = pTmr->elapse%TMR_WHEEL_SIZE;
146pWhl = &TmrWheel[spoke];
147
148if(pWhl->pFirst) pWhl->pFirst->prev = pTmr;
149
150pTmr->next = pWhl->pFirst;
151pWhl->pFirst = pTmr;
152pWhl->entries++;
153 }
154
155 static void Tmr_unlink(Timer_Typedef* pTmr)
156 {
157int spoke;
158TimerWheel_Typedef *pWhl;
159pTmr->state = TMR_STATE_STOP;
160spoke = pTmr->elapse%TMR_WHEEL_SIZE;
161pWhl = &TmrWheel[spoke];
162
163if(pWhl->pFirst == pTmr)
164{
165pWhl->pFirst = pTmr->next;
166if(pTmr->next) ((Timer_Typedef*)pTmr->next)->prev = (void*)0;
167}
168else
169{
170((Timer_Typedef*)pTmr->prev)->next = pTmr->next;
171if(pTmr->next) ((Timer_Typedef*)pTmr->next)->prev = pTmr->prev;
172}
173pWhl->entries--;
174 }
175
176
177 static Timer_Typedef* Tmr_alloc(void)
178 {
179Timer_Typedef *pTmr = (Timer_Typedef*)0;
180if(tmr_free_list)
181{
182pTmr = tmr_free_list;
183tmr_free_list = tmr_free_list->next;
184tmr_free_slot--;
185}
186return pTmr;
187 }
188
189
190
191 static void Tmr_free(Timer_Typedef* pTmr)
192 {
193pTmr->state = TMR_STATE_FREE;
194pTmr->prev = (Timer_Typedef*)0;
195pTmr->next = tmr_free_list;
196tmr_free_list = pTmr;
197tmr_free_slot++;
198 }
199
200 unsigned long TmrGetTime(void)
201 {
202ret
推荐阅读
- 单片机逻辑电路与逻辑运算
- 第八节:PIC系列单片机I/O口结构
- 基于AVR单片机的AT24C01-512eeprom读写程序
- 51单片机之I^2C总线
- ARM Linux S3C2440 之UART分析
- 单片机小小常识
- WPF与51单片机之间的串口通信
- 基于51单片机的实时操作系统的实现
- 卫生间装修之装出时尚卫浴样板间
- 卫浴洁具谋求取胜之道 品质与服务力达到出奇制胜
