#include <stdio.h>
typedef unsigned char uint8; typedef unsigned short uint16;
#define N_TIME8 4 // configure number of 8bit-timer.
uint8 TR8[N_TIME8]; // Timer register
uint16 TR16[8-N_TIME8];
uint8 TER; // timer Enable register
uint8 TFR; // timeout flags.
void Tick(); // decrement every TimerRegister, if 1→0 set TFi.
/* void InitTimers(); void SetTimer(int id,int time); // macro bool IsTimeOut(int id); void DisTimer(int id); */
/* Tick() 由硬件定时器驱动,周期1ms。 8个定时器分为2组,建立一个表用于快速下一个使能了的计数器。这个表只有16字节,可以节省一些时间开销。这对于中断服务程序来说是很宝贵的。
反问:这样真的节省时间了吗? ① 当所有定时器都开启时,这种方式与 for(i=0; i<8; i++)相比,哪个更快? ② 多少定时器开启时,两种方式耗时相当? */
uint8 NextTimerTab[16]={0,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0}; void Tick() { uint8 map; uint8 nextTimer; // group1: timer 0,1,2,3
// 使能了,并且非0的定时器需要倒计时。// 这过滤了为0的定时器,计时单元自减时不需要判断是否为0.
map = (TER & ~TFR) & 0x0f; while(map != 0) { nextTimer = NextTimerTab[map]; map &= ~(1<<nextTimer); if(nextTimer<N_TIME8) { if(--TR8[nextTimer] == 0) TFR |= 1<<nextTimer; } else { if(--TR16[nextTimer-N_TIME8] == 0) TFR |= 1<<nextTimer; } } // group2: timer 4,5,6,7
map = (TER&~TFR) & 0xf0; map >>= 4; while(map != 0) { nextTimer = NextTimerTab[map]; map &= ~(1<<nextTimer); nextTimer += 4; // index
if(nextTimer<N_TIME8) { if(--TR8[nextTimer] == 0) TFR |= 1<<nextTimer; } else { if(--TR16[nextTimer-N_TIME8] == 0) TFR |= 1<<nextTimer; } } }
void InitTimers() { TER = 0; TFR = 0; // TR[]={0}; } /* // void SetTimer(id,time); // macro 可以放心,一般8bit-mcu的编译器不会把它优化掉。这里用do{}while(0)实现了语句块的宏定义 */ #define SetTimer(id, time) do{if(id<N_TIME8)TR8[id]=time;else TR16[id-N_TIME8]=time;}while(0)
#define EnTimer(id) (TER |= 1<<id)
#define DisTimer(id) (TER &= ~(1<<id))
/* // bool IsTimeOut(int id); // macro id的值不会大于7,why? C的原则:信任程序员 & 程序员应该知道自己正在做什么。 */ #define IsTimeOut(id) (TFR & (1<<id))
/* 前面几个操作都是用宏实现的。为什么呢? 不是因为函数调用消耗更多时间,想想你自己吧,一年才在家呆2周,老妈会因为你早日睡懒觉而生气吗? 因为函数调用需要堆栈。8bit-mcu 如holtek函数调用使用硬件堆栈,要严格控制函数层次。 */
// ④ demo
void main() { int i=0;
InitTimers(); SetTimer(0, 3); // 8bits-timer
SetTimer(1, 5); SetTimer(5, 7);// 16bits-timer
EnTimer(0); EnTimer(1); EnTimer(5);
while(1) { Tick(); // Debug in VC6.0. Simulate timer-ISR ~ if(i++>10)break; // End loop. 10 > max(3,5,7)
printf("\n%d====================\n", i); if(!IsTimeOut(0)) printf("0\t"); else { printf("0_%s\t", "time out"); //DisTimer(5); // test DisTimer() } if(!IsTimeOut(1)) printf("1\t"); else printf("1_%s\t", "time out"); if(!IsTimeOut(5)) printf("5\t"); else printf("5_%s\t", "time out"); } printf("End\n"); }
|