发布于 

30天自制操作系统(12)

DAY12_定时器(1)

1.使用定时器

介绍定时器的作用,添加定时器实现中断。

  • 定时器(Timer)对于操作系统十分重要,每隔一段时间就发送一个中断信号给CPU。有了定时器,CPU就不用辛苦地计量时间。
  • 没有定时器,我们就没法使用HLT指令,意味着要浪费很多电能。
  • 有了定时器中断,程序只需要以自己的步调处理自己的问题就可以了。至于到底经过了多少时间,只要在中断处理程序中数一数定时器中断发生的次数就可以了。

  • 要在电脑中管理定时器,只需要对PIT(Programmable Interval Timer可编程的间隔型定时器)进行设定就可以了。通过设定PIT,让定时器每隔多少秒就产生一次中断。
  • 在电脑中PIT连接着IRQ(interrupt request)的0号,所以只要设定了PIT就可以设定IRQ0的中断间隔。
  • 我们不清楚其中的详细原理,只知道只要执行3次OUT指令设定就完成了。将中断周期设定为11932的话,中断频率好像就是100Hz,也就是说1秒钟会发生100次中断。
  • IRQ0发生时所调用的中断处理程序几乎和键盘的中断处理程序一样。

2.计量时间

==加入计时器显示时间==

  • 让中断执行下面的程序
struct TIMERCTL { 
unsigned int count;
};
  • 实现方法
    • 定义struct TIMERCTL结构体,在结构体内定义一个计数变量。
    • 初始化PIT时,计数变量为0,每次发生定时器中断时,计数变量就以1递增。
    • 即计数变量在HariMain中不进行加算,每1s也会增加100.

3.超时功能

==超时功能的定义,添加超时功能==

  • 我们可以计量处理所花费的时间。具体做法:处理前看一下时间并把它存放到一个变量变量里,处理结束后再看一下时间,做差即可。根据这个可以编制==基准测试程序==
  • 超时(timeout):过了一段时间,定时器提示操作系统。
struct TIMERCTL { 
unsigned int count;
unsigned int timeout;
struct FIFO8 *fifo;
unsigned char data;
};

timeout用于记录离超时还有多长时间,当剩余时间到达0时,程序就往IFIFO缓冲区里发送数据。

4.设定多个定时器

  • 在上一节做的超时功能,超时结束后如果再设定1000的话,那我们就可以让它每10秒显示一
    次,或是让它一闪一灭地显示。
  • 开发操作系统时,超时功能非常方便,所以在很多地方都可以使用它。比如可以让电子时钟
    每隔1秒重新显示一次;演奏音乐时,可以用它计量音符的长短;也可以让它以0.1秒1次的频率来监视没有中断功能的装置;另外,还可以用它实现光标的闪烁功能。
    为了简单地实现这些功能,我们要准备很多能够设定超时的定时器。

5.加快中断处理(1)

  • 问题:inthandler20中断花费了很长的时间
  • 优化部分:现每次进行定时器中断处理的时候,都会对所有活动中的定时器进行“timerctl.timer[i].timeout—;”处理。也就是说,CPU要完成从内存中读取变量值,减去1,然后又往内存中写入的操作。
  • time[i].timeout不再是“所剩时间”而是“予定时刻”,将timerctl.count和timer[i].timeout进行比较,不用再经过内存计算。
  • 问题:count设定成最大值,一段时间后需要重新启动操作系统。

6.加快中断处理(2)

==优化if语句==
解决方案:添加timerctl.next,让它记住下一个时刻

7.加快中断处理(3)

  • 问题:到达next时刻和没到next时刻的定时器中断,它们的处理时间差别很大。
    这样的程序结构不好。因为平常运行一直都很快的程序,会偶尔由于中断处理拖得太长,而搞得像是主程序要停了似的。