[自制简单操作系统] 4、计时器(线性表实现优化中断)
1、第一版:数组方式[09d]
>_<" 在bootpack.h里面的timer.c的声明和结构体:
1 /* timer.c */ 2 #define MAX_TIMER 500 //最多500个定时器 3 struct TIMER{ 4 unsigned int flags;//flags记录各个寄存器状态 5 unsigned int timeout;//用来记录离超时还有多长时间,一旦这个剩余时间为0,程序就往FIFO缓冲区里发送数据,定时器就是用这种方法通知HariMain时间到了 6 struct FIFO8 *fifo;//消息队列 7 unsigned char data;//该定时器标志,用来向消息队列写的标志信息 8 }; 9 struct TIMERCTL{ 10 unsigned int count;//计数 11 struct TIMER timer[MAX_TIMER]; 12 }; 13 extern struct TIMERCTL timerctl; 14 void init_pit(void);//定时器初始化100hz 15 struct TIMER *timer_alloc(void);//分配定时器,遍历所有找到第一个没有使用的分配 16 void timer_free(struct TIMER *timer);//释放定时器 17 void timer_init(struct TIMER *timer, struct FIFO8 *fifo, unsigned char data);//初始化定时器,fifo和标志符data 18 void timer_settime(struct TIMER *timer, unsigned int timeout);//定时器设置,设定剩余时间 19 void inthandler20(int *esp);//定时器中断函数 20 //void settimer(unsigned int timeout, struct FIFO8 *fifo, unsigned char data);//设置定时器
1 /* PIT 定时器 */ 2 3 #include "bootpack.h" 4 5 #define PIT_CTRL 0x0043 6 #define PIT_CNT0 0x0040 7 8 struct TIMERCTL timerctl; 9 //struct TIMERCTL timerctl;//计数器结构体实例化 10 #define TIMER_FLAGS_ALLOC 1 //已配置状态 11 #define TIMER_FLAGS_USING 2 //定时器运行中 12 13 ///////////////////////////////////////////////////////////////////////////////////// 14 //功能:定时器初始化,要3次OUT指令,(0x34->0x34)(中断周期低8位->0x40)(高8位->0x40) 15 //参数: 16 //附加:设置结果为主频/设置数,这里中断周期设置为0x2e9c,大约为100hz,具体搜:IRQ0中断周期变更PIT 17 void init_pit(void) 18 { 19 int i; 20 io_out8(PIT_CTRL, 0x34); 21 io_out8(PIT_CNT0, 0x9c); 22 io_out8(PIT_CNT0, 0x2e); 23 timerctl.count=0;//初始化计数为0 24 // timerctl.timeout=0;//剩余时间为0 25 for(i=0;i<MAX_TIMER;i++){//初始化所有定时器未使用 26 timerctl.timer[i].flags=0;//未使用 27 } 28 return; 29 } 30 ///////////////////////////////////////////////////////////////////////////////////// 31 //功能:分配定时器 32 //参数: 33 struct TIMER *timer_alloc(void) 34 { 35 int i; 36 for (i = 0; i < MAX_TIMER; i++) {//从开始开始找没有使用的定时器,找到后设置为分配状态,反回 37 if (timerctl.timer[i].flags == 0) { 38 timerctl.timer[i].flags = TIMER_FLAGS_ALLOC; 39 return &timerctl.timer[i]; 40 } 41 } 42 return 0; /* 没有找到 */ 43 } 44 ///////////////////////////////////////////////////////////////////////////////////// 45 //功能:释放定时器,直接把标志位设为0即可 46 //参数: 47 void timer_free(struct TIMER *timer) 48 { 49 timer->flags = 0; /* 未使用 */ 50 return; 51 } 52 ///////////////////////////////////////////////////////////////////////////////////// 53 //功能:初始化定时器,赋值fifo,设置标志位 54 //参数: 55 void timer_init(struct TIMER *timer, struct FIFO8 *fifo, unsigned char data) 56 { 57 timer->fifo = fifo; 58 timer->data = data; 59 return; 60 } 61 ///////////////////////////////////////////////////////////////////////////////////// 62 //功能:设置timer 63 //参数:输入剩余时间 64 void timer_settime(struct TIMER *timer, unsigned int timeout) 65 { 66 timer->timeout = timeout; 67 timer->flags = TIMER_FLAGS_USING; 68 return; 69 } 70 71 72 ///////////////////////////////////////////////////////////////////////////////////// 73 //功能:定时器中断处理程序,和键盘鼠标中断类似 74 //参数: 75 void inthandler20(int *esp) 76 { 77 int i; 78 io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00信号接受完了的信息通知给PIC */ 79 timerctl.count++;//计数 80 for (i = 0; i < MAX_TIMER; i++) {//遍历所有的定时器 81 if (timerctl.timer[i].flags == TIMER_FLAGS_USING) {//有正在使用的就剩余时间-- 82 timerctl.timer[i].timeout--; 83 if (timerctl.timer[i].timeout == 0) {//剩余时间为0就直接将标志位改为非使用,将消息写进队列 84 timerctl.timer[i].flags = TIMER_FLAGS_ALLOC; 85 fifo8_put(timerctl.timer[i].fifo, timerctl.timer[i].data);////剩余时间为0就向缓冲区写数据,用这种方法通知main函数 86 } 87 } 88 } 89 return; 90 } 91 ///////////////////////////////////////////////////////////////////////////////////// 92 //功能:定时器设置,因为没有设置好就发生中断就会混乱,所以先关闭中断,然后恢复中断 93 //参数:初始剩余时间,fifo,标志data(向缓冲区写的数据) 94 //void settimer(unsigned int timeout, struct FIFO8 *fifo, unsigned char data) 95 //{ 96 // int eflags; 97 // eflags = io_load_eflags(); 98 // io_cli(); 99 // timerctl.timeout = timeout; 100 // timerctl.fifo = fifo; 101 // timerctl.data = data; 102 // io_store_eflags(eflags); 103 // return; 104 //}
>_<" 这里定义一个计时器结构体和一个管理计时器的结构体,其中TIMERCTL中含有一个timer的数组,用来实现最多MAX_TIMER个计时器的管理。这里:
-
初始化的时候只是将所有的定时器的flags赋值为0
-
分配定时器函数是从开始遍历所有定时器,一旦有未使用的就置标志为TIMER_FLAGS_ALLOC,然后返回~
-
释放计时器只是简单的把标志置0,恢复未使用状态
-
计时器初始化函数是给计时器的fifo,和定时器标志赋值,这里的计时器标志是等计时器计时完毕时向fifo发送的消息,用来区分不同的计时器
-
设置定时器就是给定时器设定一个时间,然后置flags为正在使用
-
中断处理函数每次count++实现时间累加,然后遍历所有正在使用的定时器,让他们的剩余时间--,如果发现剩余时间为0,就向fifo发送对应消息~
PS: 很显然,这种处理速度是很慢很慢的!接下来要一步步的优化~
2、有序数组[09g]
>_<" 在bootpack.h里面的timer.c的声明和结构体:
1 /* timer.c */ 2 #define MAX_TIMER 500 //最多500个定时器 3 struct TIMER{ 4 unsigned int flags;//flags记录各个寄存器状态 5 unsigned int timeout;//用来记录离超时还有多长时间,一旦这个剩余时间为0,程序就往FIFO缓冲区里发送数据,定时器就是用这种方法通知HariMain时间到了 6 struct FIFO8 *fifo;//消息队列 7 unsigned char data;//该定时器标志,用来向消息队列写的标志信息 8 }; 9 struct TIMERCTL { 10 unsigned int count, next, using;//using表示有几个定时器处于活动中,next是下一个设定时间点,count是累加时间轴 11 struct TIMER *timers[MAX_TIMER];//记录按照某种顺序存好的定时器地址 12 struct TIMER timers0[MAX_TIMER]; 13 }; 14 extern struct TIMERCTL timerctl; 15 void init_pit(void);//定时器初始化100hz 16 struct TIMER *timer_alloc(void);//分配定时器,遍历所有找到第一个没有使用的分配 17 void timer_free(struct TIMER *timer);//释放定时器 18 void timer_init(struct TIMER *timer, struct FIFO8 *fifo, unsigned char data);//初始化定时器,fifo和标志符data 19 void timer_settime(struct TIMER *timer, unsigned int timeout);//定时器设置,设定剩余时间 20 void inthandler20(int *esp);//定时器中断函数 21 //void settimer(unsigned int timeout, struct FIFO8 *fifo, unsigned char data);//设置定时器
1 /* PIT 定时器 */ 2 3 #include "bootpack.h" 4 5 #define PIT_CTRL 0x0043 6 #define PIT_CNT0 0x0040 7 8 struct TIMERCTL timerctl; 9 //struct TIMERCTL timerctl;//计数器结构体实例化 10 #define TIMER_FLAGS_ALLOC 1 //已配置状态 11 #define TIMER_FLAGS_USING 2 //定时器运行中 12 13 ///////////////////////////////////////////////////////////////////////////////////// 14 //功能:定时器初始化,要3次OUT指令,(0x34->0x34)(中断周期低8位->0x40)(高8位->0x40) 15 //参数: 16 //附加:设置结果为主频/设置数,这里中断周期设置为0x2e9c,大约为100hz,具体搜:IRQ0中断周期变更PIT 17 void init_pit(void) 18 { 19 int i; 20 io_out8(PIT_CTRL, 0x34); 21 io_out8(PIT_CNT0, 0x9c); 22 io_out8(PIT_CNT0, 0x2e); 23 timerctl.count=0;//初始化计数为0 24 timerctl.next=0xffffffff;//初始时没有计时器所以下一个为无穷大 25 timerctl.using=0;//正在使用的定时器为0 26 27 for(i=0;i<MAX_TIMER;i++){//初始化所有定时器未使用 28 timerctl.timers0[i].flags=0;//未使用 29 } 30 return; 31 } 32 ///////////////////////////////////////////////////////////////////////////////////// 33 //功能:分配定时器 34 //参数: 35 struct TIMER *timer_alloc(void) 36 { 37 int i; 38 for (i = 0; i < MAX_TIMER; i++) {//从开始开始找没有使用的定时器,找到后设置为分配状态,反回 39 if (timerctl.timers0[i].flags == 0) { 40 timerctl.timers0[i].flags = TIMER_FLAGS_ALLOC; 41 return &timerctl.timers0[i]; 42 } 43 } 44 return 0; /* 没有找到 */ 45 } 46 ///////////////////////////////////////////////////////////////////////////////////// 47 //功能:释放定时器,直接把标志位设为0即可 48 //参数: 49 void timer_free(struct TIMER *timer) 50 { 51 timer->flags = 0; /* 未使用 */ 52 return; 53 } 54 ///////////////////////////////////////////////////////////////////////////////////// 55 //功能:初始化定时器,赋值fifo,设置标志位 56 //参数: 57 void timer_init(struct TIMER *timer, struct FIFO8 *fifo, unsigned char data) 58 { 59 timer->fifo = fifo; 60 timer->data = data; 61 return; 62 } 63 ///////////////////////////////////////////////////////////////////////////////////// 64 //功能:设置timer 65 //参数:输入定时时间 66 void timer_settime(struct TIMER *timer, unsigned int timeout) 67 { 68 int e, i, j; 69 timer->timeout = timeout + timerctl.count;//当前时间+定时器定时时间 70 timer->flags = TIMER_FLAGS_USING;//设置成正在使用 71 e = io_load_eflags();//保存寄存器,关中断 72 io_cli(); 73 /* 搜索注册位置 */ 74 for (i = 0; i < timerctl.using; i++) {//把所有timeout从小到大排列,找出新建的定时器插入位置 75 if (timerctl.timers[i]->timeout >= timer->timeout) { 76 break; 77 } 78 } 79 /* i之后的全部后移1位 */ 80 for (j = timerctl.using; j > i; j--) { 81 timerctl.timers[j] = timerctl.timers[j - 1]; 82 } 83 timerctl.using++; 84 /* 插入到空位上 */ 85 timerctl.timers[i] = timer; 86 timerctl.next = timerctl.timers[0]->timeout; 87 io_store_eflags(e);//恢复寄存器 88 return; 89 } 90 91 92 ///////////////////////////////////////////////////////////////////////////////////// 93 //功能:定时器中断处理程序,和键盘鼠标中断类似 94 //参数: 95 void inthandler20(int *esp) 96 { 97 int i,j; 98 io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00信号接受完了的信息通知给PIC */ 99 timerctl.count++;//计数 100 if(timerctl.next>timerctl.count){//如果下一个还没计数完毕就直接返回 101 return; 102 } 103 for(i=0;i<timerctl.using;i++){ 104 if(timerctl.timers[i]->timeout>timerctl.count){ 105 break; 106 }//从前往后遍历,一旦发现有计时未完成的计时器就跳出循环 107 /*除了上面的情况,都是定时已达的定时器*/ 108 timerctl.timers[i]->flags = TIMER_FLAGS_ALLOC; 109 fifo8_put(timerctl.timers[i]->fifo, timerctl.timers[i]->data); 110 } 111 /*从上面循环结束后,i的值就是前面有几个超时的定时器*/ 112 timerctl.using-=i;//所以减去超时的定时器 113 for(j=0;j<timerctl.using;j++){//将后面的定时器前移 114 timerctl.timers[j]=timerctl.timers[i+j]; 115 } 116 if(timerctl.using>0){//判断是否还有正在使用的定时器,有就用下一个剩余时间更新next 117 timerctl.next=timerctl.timers[0]->timeout; 118 }else{//没有,就直接设为无穷大 119 timerctl.next=0xffffffff; 120 } 121 return; 122 }
>_<" 这里和上一个的最大的不同之处是:上一个采用暴力遍历每一个的情况,而这个则采用插入和删除等操作时就事先调整好数组。此外为了方便实现这一数据结构,TIMERCTL里除了用timers0[]数组保存计时器外,还声明一个timers[]数组用来记录按照某种顺序排好的定时器,这里的using是出于活动中的定时器数,next是下一个设定的时间:
-
初始化函数改变比较少,只是加了个using=0,next=0xffffffff等初始化赋值操作
-
分配定时器基本无变化
-
设定时间函数则从前往后遍历查找该新的定时器要插入的位置,因为这里是有序排列的,而且只遍历正在使用中的定时器,所以比上一个纯暴力要快
-
中断函数,是将当前前面的已经超时的定时器发送消息及取消使用状态,然后从有序列表里面删除这些(具体做法就是前移后面的部分覆盖这部分超时的部分)
3、线性表[10h]
>_<" 在bootpack.h里面的timer.c的声明和结构体:
1 /* timer.c */ 2 #define MAX_TIMER 500 //最多500个定时器 3 struct TIMER{ 4 struct TIMER *next;//用来指下一个即将超时的定时器地址 5 unsigned int flags;//flags记录各个寄存器状态 6 unsigned int timeout;//用来记录离超时还有多长时间,一旦这个剩余时间为0,程序就往FIFO缓冲区里发送数据,定时器就是用这种方法通知HariMain时间到了 7 struct FIFO32 *fifo;//消息队列 8 int data;//该定时器标志,用来向消息队列写的标志信息 9 }; 10 struct TIMERCTL { 11 unsigned int count, next, using;//using表示有几个定时器处于活动中,next是下一个设定时间点,count是累加时间轴 12 struct TIMER *t0;//记录按照某种顺序存好的定时器地址,头指针 13 struct TIMER timers0[MAX_TIMER]; 14 }; 15 extern struct TIMERCTL timerctl; 16 void init_pit(void);//定时器初始化100hz 17 struct TIMER *timer_alloc(void);//分配定时器,遍历所有找到第一个没有使用的分配 18 void timer_free(struct TIMER *timer);//释放定时器 19 void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data);//初始化定时器,fifo和标志符data 20 void timer_settime(struct TIMER *timer, unsigned int timeout);//定时器设置,设定剩余时间 21 void inthandler20(int *esp);//定时器中断函数
1 /* PIT 定时器 */ 2 3 #include "bootpack.h" 4 5 #define PIT_CTRL 0x0043 6 #define PIT_CNT0 0x0040 7 8 struct TIMERCTL timerctl; 9 //struct TIMERCTL timerctl;//计数器结构体实例化 10 #define TIMER_FLAGS_ALLOC 1 //已配置状态 11 #define TIMER_FLAGS_USING 2 //定时器运行中 12 13 ///////////////////////////////////////////////////////////////////////////////////// 14 //功能:定时器初始化,要3次OUT指令,(0x34->0x34)(中断周期低8位->0x40)(高8位->0x40) 15 //参数: 16 //附加:设置结果为主频/设置数,这里中断周期设置为0x2e9c,大约为100hz,具体搜:IRQ0中断周期变更PIT 17 void init_pit(void) 18 { 19 int i; 20 io_out8(PIT_CTRL, 0x34); 21 io_out8(PIT_CNT0, 0x9c); 22 io_out8(PIT_CNT0, 0x2e); 23 timerctl.count=0;//初始化计数为0 24 timerctl.next=0xffffffff;//初始时没有计时器所以下一个为无穷大 25 timerctl.using=0;//正在使用的定时器为0 26 27 for(i=0;i<MAX_TIMER;i++){//初始化所有定时器未使用 28 timerctl.timers0[i].flags=0;//未使用 29 } 30 return; 31 } 32 ///////////////////////////////////////////////////////////////////////////////////// 33 //功能:分配定时器 34 //参数: 35 struct TIMER *timer_alloc(void) 36 { 37 int i; 38 for (i = 0; i < MAX_TIMER; i++) {//从开始开始找没有使用的定时器,找到后设置为分配状态,反回 39 if (timerctl.timers0[i].flags == 0) { 40 timerctl.timers0[i].flags = TIMER_FLAGS_ALLOC; 41 return &timerctl.timers0[i]; 42 } 43 } 44 return 0; /* 没有找到 */ 45 } 46 ///////////////////////////////////////////////////////////////////////////////////// 47 //功能:释放定时器,直接把标志位设为0即可 48 //参数: 49 void timer_free(struct TIMER *timer) 50 { 51 timer->flags = 0; /* 未使用 */ 52 return; 53 } 54 ///////////////////////////////////////////////////////////////////////////////////// 55 //功能:初始化定时器,赋值fifo,设置标志位 56 //参数: 57 void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data) 58 { 59 timer->fifo = fifo; 60 timer->data = data; 61 return; 62 } 63 ///////////////////////////////////////////////////////////////////////////////////// 64 //功能:设置timer 65 //参数:输入定时时间 66 void timer_settime(struct TIMER *timer, unsigned int timeout) 67 { 68 int e; 69 struct TIMER *t,*s; 70 timer->timeout = timeout + timerctl.count;//当前时间+定时器定时时间 71 timer->flags = TIMER_FLAGS_USING;//设置成正在使用 72 e = io_load_eflags();//保存寄存器,关中断 73 io_cli(); 74 75 timerctl.using++; 76 if (timerctl.using == 1) { 77 /* 处于运行状态的只有一个 */ 78 timerctl.t0 = timer; 79 timer->next = 0; /* 没有下一个 */ 80 timerctl.next = timer->timeout; 81 io_store_eflags(e); 82 return; 83 } 84 t = timerctl.t0; 85 if (timer->timeout <= t->timeout) { 86 /* 插入最前面 */ 87 timerctl.t0 = timer; 88 timer->next = t; /* 下面是t */ 89 timerctl.next = timer->timeout; 90 io_store_eflags(e); 91 return; 92 } 93 /* 搜寻插入位置 */ 94 for (;;) { 95 s = t; 96 t = t->next; 97 if (t == 0) { 98 break; /* 最后面 */ 99 } 100 if (timer->timeout <= t->timeout) { 101 /* 插入到s和t之间 */ 102 s->next = timer; /* s的先一个是timer */ 103 timer->next = t; /* timer的下一个是t */ 104 io_store_eflags(e); 105 return; 106 } 107 } 108 /* 插入最后面的情况 */ 109 s->next = timer; 110 timer->next = 0; 111 io_store_eflags(e); 112 return; 113 } 114 115 ///////////////////////////////////////////////////////////////////////////////////// 116 //功能:定时器中断处理程序,和键盘鼠标中断类似 117 //参数: 118 void inthandler20(int *esp) 119 { 120 int i,j; 121 struct TIMER *timer; 122 io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00信号接受完了的信息通知给PIC */ 123 timerctl.count++;//计数 124 if(timerctl.next>timerctl.count){//如果下一个还没计数完毕就直接返回 125 return; 126 } 127 timer=timerctl.t0;//把最前面的地址赋址给timer 128 for(i=0;i<timerctl.using;i++){ 129 if(timer->timeout>timerctl.count){ 130 break; 131 }//从前往后遍历,一旦发现有计时未完成的计时器就跳出循环 132 /*除了上面的情况,都是定时已达的定时器*/ 133 timer->flags = TIMER_FLAGS_ALLOC; 134 fifo32_put(timer->fifo, timer->data); 135 timer=timer->next;//下一个定时器的地址赋址给timer 136 } 137 /*从上面循环结束后,i的值就是前面有几个超时的定时器*/ 138 timerctl.using-=i;//所以减去超时的定时器 139 timerctl.t0=timer;//新移位 140 //timectl.next设定 141 if(timerctl.using>0){//判断是否还有正在使用的定时器,有就用下一个剩余时间更新next 142 timerctl.next=timerctl.t0->timeout; 143 }else{//没有,就直接设为无穷大 144 timerctl.next=0xffffffff; 145 } 146 return; 147 }
>_<" 通过上面2个优化的实例发现,用数组避免不了大量数据的前移和后移,于是我们就想到了用指针来构成线性表,这样交换插入都可以在几步之能完成!这里在结构体TIMER里加入了*next指针,用来存放下一个即将超时的定时器地址。
-
这里中断处理函数只是把上面数组实现的有序数组改成用指针实现的有序链表,这样交换和插入数据就不用一块一块的移位了,直接切换一下指针就能够完成了,所以能够优化中断处理能力!
-
这里的settimer函数也类似,这里不做详细介绍,直接看代码就能理解啦!
PS: 在使用线性表之后发现TIMERCTR结构体里的TIMER数组可以只要一个首地址就行了,于是也简化为*t0
4、使用“哨兵”简化程序[10i]
>_<" 在bootpack.h里面的timer.c的声明和结构体:
1 /* timer.c */ 2 #define MAX_TIMER 500 //最多500个定时器 3 struct TIMER{ 4 struct TIMER *next;//用来指下一个即将超时的定时器地址 5 unsigned int flags;//flags记录各个寄存器状态 6 unsigned int timeout;//用来记录离超时还有多长时间,一旦这个剩余时间为0,程序就往FIFO缓冲区里发送数据,定时器就是用这种方法通知HariMain时间到了 7 struct FIFO32 *fifo;//消息队列 8 int data;//该定时器标志,用来向消息队列写的标志信息 9 }; 10 struct TIMERCTL { 11 unsigned int count, next;//next是下一个设定时间点,count是累加时间轴 12 struct TIMER *t0;//记录按照某种顺序存好的定时器地址,头指针 13 struct TIMER timers0[MAX_TIMER]; 14 }; 15 extern struct TIMERCTL timerctl; 16 void init_pit(void);//定时器初始化100hz 17 struct TIMER *timer_alloc(void);//分配定时器,遍历所有找到第一个没有使用的分配 18 void timer_free(struct TIMER *timer);//释放定时器 19 void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data);//初始化定时器,fifo和标志符data 20 void timer_settime(struct TIMER *timer, unsigned int timeout);//定时器设置,设定剩余时间 21 void inthandler20(int *esp);//定时器中断函数
1 /* PIT 定时器 */ 2 3 #include "bootpack.h" 4 5 #define PIT_CTRL 0x0043 6 #define PIT_CNT0 0x0040 7 8 struct TIMERCTL timerctl; 9 //struct TIMERCTL timerctl;//计数器结构体实例化 10 #define TIMER_FLAGS_ALLOC 1 //已配置状态 11 #define TIMER_FLAGS_USING 2 //定时器运行中 12 13 ///////////////////////////////////////////////////////////////////////////////////// 14 //功能:定时器初始化,要3次OUT指令,(0x34->0x34)(中断周期低8位->0x40)(高8位->0x40) 15 //参数: 16 //附加:设置结果为主频/设置数,这里中断周期设置为0x2e9c,大约为100hz,具体搜:IRQ0中断周期变更PIT 17 void init_pit(void) 18 { 19 int i; 20 struct TIMER *t; 21 io_out8(PIT_CTRL, 0x34); 22 io_out8(PIT_CNT0, 0x9c); 23 io_out8(PIT_CNT0, 0x2e); 24 timerctl.count=0;//初始化计数为0 25 for(i=0;i<MAX_TIMER;i++){//初始化所有定时器未使用 26 timerctl.timers0[i].flags=0;//未使用 27 } 28 t=timer_alloc();//取得一个 29 t->timeout=0xffffffff; 30 t->flags=TIMER_FLAGS_USING; 31 t->next=0;//末尾 32 timerctl.t0=t;//现在就一个 33 timerctl.next=0xffffffff;//下一个计时器为哨兵,所以下一个为无穷大 34 return; 35 } 36 ///////////////////////////////////////////////////////////////////////////////////// 37 //功能:分配定时器 38 //参数: 39 struct TIMER *timer_alloc(void) 40 { 41 int i; 42 for (i = 0; i < MAX_TIMER; i++) {//从开始开始找没有使用的定时器,找到后设置为分配状态,反回 43 if (timerctl.timers0[i].flags == 0) { 44 timerctl.timers0[i].flags = TIMER_FLAGS_ALLOC; 45 return &timerctl.timers0[i]; 46 } 47 } 48 return 0; /* 没有找到 */ 49 } 50 ///////////////////////////////////////////////////////////////////////////////////// 51 //功能:释放定时器,直接把标志位设为0即可 52 //参数: 53 void timer_free(struct TIMER *timer) 54 { 55 timer->flags = 0; /* 未使用 */ 56 return; 57 } 58 ///////////////////////////////////////////////////////////////////////////////////// 59 //功能:初始化定时器,赋值fifo,设置标志位 60 //参数: 61 void timer_init(struct TIMER *timer, struct FIFO32 *fifo, int data) 62 { 63 timer->fifo = fifo; 64 timer->data = data; 65 return; 66 } 67 ///////////////////////////////////////////////////////////////////////////////////// 68 //功能:设置timer 69 //参数:输入定时时间 70 void timer_settime(struct TIMER *timer, unsigned int timeout) 71 { 72 int e; 73 struct TIMER *t,*s; 74 timer->timeout = timeout + timerctl.count;//当前时间+定时器定时时间 75 timer->flags = TIMER_FLAGS_USING;//设置成正在使用 76 e = io_load_eflags();//保存寄存器,关中断 77 io_cli(); 78 79 t=timerctl.t0; 80 if (timer->timeout <= t->timeout) { 81 /* 插入最前面的情况 */ 82 timerctl.t0 = timer; 83 timer->next = t; /* 下面是设定t */ 84 timerctl.next = timer->timeout; 85 io_store_eflags(e); 86 return; 87 } 88 /* 搜寻插入位置 */ 89 for (;;) { 90 s = t; 91 t = t->next; 92 if (timer->timeout <= t->timeout) { 93 /* 插入s和t之间 */ 94 s->next = timer; /* s下一个是timer */ 95 timer->next = t; /* timer下一个是t */ 96 io_store_eflags(e); 97 return; 98 } 99 } 100 return; 101 } 102 103 ///////////////////////////////////////////////////////////////////////////////////// 104 //功能:定时器中断处理程序,和键盘鼠标中断类似 105 //参数: 106 void inthandler20(int *esp) 107 { 108 struct TIMER *timer; 109 io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00信号接受完了的信息通知给PIC */ 110 timerctl.count++; 111 if (timerctl.next > timerctl.count) {//如果下一个还没计数完毕就直接返回 112 return; 113 } 114 timer = timerctl.t0; //把最前面的地址赋址给timer 115 for (;;) { 116 if (timer->timeout > timerctl.count) { 117 break; 118 }//从前往后遍历,一旦发现有计时未完成的计时器就跳出循环 119 /*除了上面的情况,都是定时已达的定时器*/ 120 timer->flags = TIMER_FLAGS_ALLOC; 121 fifo32_put(timer->fifo, timer->data); 122 timer = timer->next;//下一个定时器的地址赋址给timer 123 } 124 timerctl.t0 = timer;//新移位 125 timerctl.next = timer->timeout;//timectl.next设定 126 return; 127 }
>_<" “哨兵”听起来高大上,其实就是在10g的线性表的基础上多加一个空结点,这样就能把插入结点时的判断条件减少很多,用来达到精简代码的目的~其实由于多了一个空结点,这种处理虽然代码精简了,但是其速度就没有上面纯的线性表快了~这里就不仔细介绍细节的东西了,相信大家一看就懂~
5、工程代码链接:
包含上面项目工程的所有代码:http://pan.baidu.com/s/1bnEkjWN
LZ主页:http://www.cnblogs.com/zjutlitao/
1 /* 2 同一占用一个fifo,这里: 3 0~1 光标闪烁用定时器 4 3 3秒定时器 5 10 10秒定时器 6 256~511 键盘输入(从键盘控制器读入的值再加上256) 7 512~767 鼠标输入(从键盘控制器读入的值再加上512) 8 */