从本篇内容开始讲解定时器。本篇内容比较简单,首先介绍定时器的概念与设置方法,然后介绍超时的中断处理,并对中断处理函数进行了优化。
1. 定时器
定时器是操作系统中十分重要的功能。它的原理很简单,只是每隔一段时间发送一个中断给CPU。如果想要知道过了多长时间,只需要在中断处理程序中记录中断的次数就可以计算得到。
管理定时器也很简单,只需要对PIT(Programmable Interval Timer的缩写)进行设置即可。通过对PIT的设置,可以设置定时器每隔多长时间发送一次中断。PIT连接着IRQ的0号中断。设置PIT需要的命令如下:
- AL = 0x34;OUT(0x43, AL);
- AL = 中断周期的低8位;OUT(0x40, AL)
- AL = 中断周期的高8位;OUT(0x40, AL)
实际设置的中断频率 = 单位时间时钟周期数(主频)/设定的数值
根据当前的主频,如果设定11932,则中断频率位100Hz,即10ms发生一次中断。把11932换算为16进制,则是0x2e9c。
设置PIT相关程序如下:
#define PIT_CTRL 0x0043
#define PIT_CNT0 0x0040
void init_pit(void)
{
io_out8(PIT_CTRL, 0x34);
io_out8(PIT_CNT0, 0x9c);
io_out8(PIT_CNT0, 0x2e);
return;
}
在主程序中调用init_pit函数:
struct BOOTINFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO;
char s[40], keybuf[32], mousebuf[128];
int mx, my, i;
unsigned int memtotal, count = 0;
struct MOUSE_DEC mdec;
struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDR;
struct SHTCTL *shtctl;
struct SHEET *sht_back, *sht_mouse, *sht_win;
unsigned char *buf_back, buf_mouse[256], *buf_win;
init_gdtidt();
init_pic();
……
涉及到了中断,则需要将中断处理函数注册到IDT中,这些也是前面讲过的内容了。
/* 注册IDT*/
set_gatedesc(idt + 0x20, (int) asm_inthandler20, 2 * 8, AR_INTGATE32);
set_gatedesc(idt + 0x21, (int) asm_inthandler21, 2 * 8, AR_INTGATE32);
set_gatedesc(idt + 0x27, (int) asm_inthandler27, 2 * 8, AR_INTGATE32);
set_gatedesc(idt + 0x2c, (int) asm_inthandler2c, 2 * 8, AR_INTGATE32);
_asm_inthandler20:
PUSH ES
PUSH DS
PUSHAD
MOV EAX,ESP
PUSH EAX
MOV AX,SS
MOV DS,AX
MOV ES,AX
CALL _inthandler20
POP EAX
POPAD
POP DS
POP ES
IRETD
void inthandler20(int *esp)
{
io_out8(PIC0_OCW2, 0x60); /* 通知PIC, IRQ-00中断受理完毕 */
/* 暂时无内容 */
return;
}
这样定时器的中断处理就完成了。接下来就在中断处理中进行计时:
struct TIMERCTL {
unsigned int count;
};
struct TIMERCTL timerctl;
void inthandler20(int *esp)
{
io_out8(PIC0_OCW2, 0x60);
timerctl.count++;
return;
}
新建了timerctl结构体,每次进入中断处理函数时就对其中的count变量增加1。在主程序中将count实时显示出来,根据之前的设置,每秒钟显示的数值会增加100。
for (;;) {
sprintf(s, "%010d", timerctl.count);
boxfill8(buf_win, 160, COL8_C6C6C6, 40, 28, 119, 43);
putfonts8_asc(buf_win, 160, 40, 28, COL8_000000, s);
sheet_refresh(sht_win, 40, 28, 120, 44);
……
这样就可以测量一段