[自制简单操作系统] 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 //}

timer.c

>_<" 这里定义一个计时器结构体和一个管理计时器的结构体,其中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 }

timer.c

>_<" 这里和上一个的最大的不同之处是:上一个采用暴力遍历每一个的情况,而这个则采用插入和删除等操作时就事先调整好数组。此外为了方便实现这一数据结构,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 }

timer.c

>_<" 通过上面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 }

timer.c

>_<" “哨兵”听起来高大上,其实就是在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 */
时间: 2024-10-09 20:49:04

[自制简单操作系统] 4、计时器(线性表实现优化中断)的相关文章

[自制简单操作系统] 3、内存管理和窗口叠加

1.本次主要进展 >_<" 这次主要学习了系统内存管理和窗口叠加~由于上两篇都做了详细的框架说明和介绍,这里直接上代码! 2.文件及函数构成 >_<" 这里和第二篇相比,把鼠标和键盘的相关函数独立出来放进各自相应的文件中,并主要在内存管理和窗口叠加进行探索,同时还有部分代码整理~ 1 /* In this file, not only have the defination of the function, but also 2 hava the descrip

[自制简单操作系统] 6、多任务(一)

#前言# >_<" 这里主要是多任务的初探~比较简单,主要是尝试保存当前任务.任务切换.恢复当前任务,而真正的多任务要比这个复杂的多,因为包含互不干扰,甚至是高度优化的并行技术! 一.保存当前任务: >_<" 当向CPU发出切换命令的时候,CPU会先把寄存器中的值全部写入内存中,这样当切换回来时,可以从中断的地方继续执行.接下来,为了运行下一个程序,CPU会把所有的寄存器中的值从内存中读取出来,这就完成了一次切换. >_<" 这里的结构TS

[自制简单操作系统] 2、鼠标及键盘中断处理事件[PIC\GDT\IDT\FIFO]

1.大致介绍: >_<" 大致执行顺序是:ipl10.nas->asmhead.nas->bootpack.c PS: 这里bootpack.c要调用graphic.c.dsctbl.c.fifo.c.int.c实现功能,其中有些函数还必须汇编来写,所以单独写一个汇编文件naskfunc.nas,为了方便看全部函数和结构体,所以写一个bootpack.h来写一些结构体和函数声明~ >_<" 下面是编译图解:最终生成的haribote.img可放在软盘

[自制简单操作系统] 1、从0-1到汇编再到c语言的奥秘

目录: 1.用0-1编写最简单的操作系统 2.用汇编改写上面0-1程序 2.1 只用DB的汇编改写版  2.2 加入RESB汇编的改写版  2.3 进一步使用汇编替换0-1文件  2.4 核心程序也用汇编改写  2.5 向汇编程序中加入IPL(启动程序装载器)  2.6 从启动区执行操作系统(读盘的应用) 3.汇编和C语言混合开发 3.1 32位开发及C语言混合开发引入 3.2 汇编引入C语言(用汇编写C语言函数)  3.3 C语言实现内存写入  3.4 C语言指针的强大  3.5 色号设定与调

[自制简单操作系统] 5、杂七杂八(高分辨率和键盘输入)

前言: >_<" 这几天正在研究一个好玩的,准备写<软硬结合第三篇——科班的还是可以修电脑的>,可是当前遇到个技术难点——WHDI,所以操作系统这里就慢了好大一节啦!但是以操作系统多任务的思路,感觉还是把这个优先级并不是太低的进程拿出来做一下吧!毕竟技术难点有时候需要灵感的哈~(不过有大神知道VGA接口的通信原理吗?求给个好一点的链接看看!).回到正题上来,这次学的东西有点杂,主要就是高分辨率和键盘输入相关~对于前者和汇编及硬件联系较多(具体可以查VBE Video El

[自制简单操作系统] 7、多任务(二)——任务管理自动化&amp;任务休眠

前言 >_<" 这里仿照窗口管理的方式将任务管理也修改成相应的管理模式,这样可以灵活的添加多个任务,而不必每次都要修改任务切换函数:此外还在任务休眠做了尝试,通过将任务挂起和唤醒从而加快运行速度~ 一.任务管理自动化 >_<" 为了仿照窗口管理模式对任务进行管理,于是在bootpack.h里做如下定义: 1 /* mtask.c 任务切换相关*/ 2 #define MAX_TASKS 1000 /* 最大任务数量 */ 3 #define TASK_GDT0

线性表实现——双向链表

1 include <stdio.h> 2 #include <stdlib.h> 3 #include <time.h> 4 5 #define OK 1 6 #define ERROR 0 7 typedef int Status; 8 typedef int ElemType; 9 10 typedef struct DNode 11 { 12 ElemType data; 13 struct DNode* next; 14 struct DNode* front

线性表实现——单向循环链表

1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <time.h> 4 5 #define OK 1 6 #define ERROR 0 7 typedef int Status; 8 typedef int ElemType; 9 10 typedef struct Node 11 { 12 ElemType data; 13 struct Node* next; 14 }Node; 15 16 typedef

线性表实现——单链表

1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <time.h> 4 5 #define OK 1 6 #define ERROR 0 7 typedef int Status; 8 typedef int ElemType; 9 10 typedef struct Node 11 { 12 ElemType data; 13 struct Node* next; 14 }Node; 15 16 typedef