Appearance
2023-8-23-day12定时器
使用定时器
计算机获得准确时间的方式, 使用电脑的定时器, 需要对PIT(Prongrammable Interval Timer)进行设置, 连接IRQ的0号
实际的操作
- 设置AL=0x43, OUT 0x43, AL
- 设置AL=中断周期的低八位, OUT 0x40, AL
- 设置AL=中断周期的高八位, OUT 0x40, AL
c
//初始化定时器, 依次对寄存器写入对应的数据
#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;
}
void inthandler20(int *esp)
{
io_out8(PIC0_OCW2, 0x60); /* IRQ-00接收到了信号 */
/* 暂时什么也不做 */
return;
}
c
_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
c
void HariMain(void)
{
...
init_gdtidt();
init_pic();
io_sti(); /* 解除CPU的所有中断 */
fifo8_init(&keyfifo, 32, keybuf);
fifo8_init(&mousefifo, 128, mousebuf);
init_pit();
io_out8(PIC0_IMR, 0xf8); /* 在这里打开端口0的屏蔽(11111000) */
io_out8(PIC1_IMR, 0xef); /* (11101111) */
...
}
c
void init_gdtidt(void)
{
struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;
struct GATE_DESCRIPTOR *idt = (struct GATE_DESCRIPTOR *) ADR_IDT;
int i;
/* GDTの初期化 */
for (i = 0; i <= LIMIT_GDT / 8; i++) {
set_segmdesc(gdt + i, 0, 0, 0);
}
set_segmdesc(gdt + 1, 0xffffffff, 0x00000000, AR_DATA32_RW);
set_segmdesc(gdt + 2, LIMIT_BOTPAK, ADR_BOTPAK, AR_CODE32_ER);
load_gdtr(LIMIT_GDT, ADR_GDT);
/* IDT */
for (i = 0; i <= LIMIT_IDT / 8; i++) {
set_gatedesc(idt + i, 0, 0, 0);
}
load_idtr(LIMIT_IDT, ADR_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);
return;
}
添加进中断向量表
添加时间的计算标志位
c
struct TIMERCTL {
unsigned int count;
};
struct TIMERCTL timerctl;
初始化为0, 中断中每次加一
添加超时
c
struct TIMERCTL {
unsigned int count;
unsigned int timeout;
struct FIFO8 *fifo;
unsigned char data;
};
在处理的时候同时进行count++, 以及timeout--
c
void inthandler20(int *esp)
{
io_out8(PIC0_OCW2, 0x60); /* 清除中断 */
timerctl.count++;
if (timerctl.timeout > 0) { /* 检测是否开启了时钟超时 */
timerctl.timeout--;
if (timerctl.timeout == 0) {
fifo8_put(timerctl.fifo, timerctl.data);
}
}
return;
}
void settimer(unsigned int timeout, struct FIFO8 *fifo, unsigned char data)
{
int eflags;
eflags = io_load_eflags();
io_cli();
timerctl.timeout = timeout;
timerctl.fifo = fifo;
timerctl.data = data;
io_store_eflags(eflags);
return;
}
设置多个定时器
c
#define MAX_TIMER 500
struct TIMER {
unsigned int timeout, flags;
struct FIFO8 *fifo;
unsigned char data;
};
struct TIMERCTL {
unsigned int count;
struct TIMER timer[MAX_TIMER];
};
c
#define TIMER_FLAGS_ALLOC 1 /* 已经配置了的状态 */
#define TIMER_FLAGS_USING 2 /* 定时器运行中 */
void init_pit(void)
{
int i;
io_out8(PIT_CTRL, 0x34);
io_out8(PIT_CNT0, 0x9c);
io_out8(PIT_CNT0, 0x2e);
timerctl.count = 0;
for (i = 0; i < MAX_TIMER; i++) {
timerctl.timer[i].flags = 0; /* 未使用 */
}
return;
}
struct TIMER *timer_alloc(void)
{
int i;
for (i = 0; i < MAX_TIMER; i++) {
if (timerctl.timer[i].flags == 0) {
timerctl.timer[i].flags = TIMER_FLAGS_ALLOC;
return &timerctl.timer[i];
}
}
return 0; /* 申请失败 */
}
void timer_free(struct TIMER *timer)
{
timer->flags = 0; /* 未使用 */
return;
}
void timer_init(struct TIMER *timer, struct FIFO8 *fifo, unsigned char data)
{
timer->fifo = fifo;
timer->data = data;
return;
}
void timer_settime(struct TIMER *timer, unsigned int timeout)
{
timer->timeout = timeout;
timer->flags = TIMER_FLAGS_USING;
return;
}
void inthandler20(int *esp)
{
int i;
io_out8(PIC0_OCW2, 0x60); /* 清除中断 */
timerctl.count++;
for (i = 0; i < MAX_TIMER; i++) {
if (timerctl.timer[i].flags == TIMER_FLAGS_USING) {
timerctl.timer[i].timeout--;
if (timerctl.timer[i].timeout == 0) {
timerctl.timer[i].flags = TIMER_FLAGS_ALLOC;
fifo8_put(timerctl.timer[i].fifo, timerctl.timer[i].data);
}
}
}
return;
}
再次加快中断处理
c
void inthandler20(int *esp)
{
int i, j;
io_out8(PIC0_OCW2, 0x60); /* IRQ-00受付完了をPICに通知 */
timerctl.count++;
if (timerctl.next > timerctl.count) {
return;
}
for (i = 0; i < timerctl.using; i++) {
/* 获得时间结束的所有时钟的个数 */
if (timerctl.timers[i]->timeout > timerctl.count) {
break;
}
/* 处理时间到的时钟 */
timerctl.timers[i]->flags = TIMER_FLAGS_ALLOC;
fifo8_put(timerctl.timers[i]->fifo, timerctl.timers[i]->data);
}
/* 获取下一次的时钟提示时间 */
timerctl.using -= i;
for (j = 0; j < timerctl.using; j++) {
timerctl.timers[j] = timerctl.timers[i + j];
}
if (timerctl.using > 0) {
timerctl.next = timerctl.timers[0]->timeout;
} else {
timerctl.next = 0xffffffff;
}
return;
}
c
void timer_settime(struct TIMER *timer, unsigned int timeout)
{
int e, i, j;
timer->timeout = timeout + timerctl.count;
timer->flags = TIMER_FLAGS_USING;
e = io_load_eflags();
io_cli();
/* 获得插入的位置 */
for (i = 0; i < timerctl.using; i++) {
if (timerctl.timers[i]->timeout >= timer->timeout) {
break;
}
}
/* 重新排序 */
for (j = timerctl.using; j > i; j--) {
timerctl.timers[j] = timerctl.timers[j - 1];
}
timerctl.using++;
/* 设置下一次的时间 */
timerctl.timers[i] = timer;
timerctl.next = timerctl.timers[0]->timeout;
io_store_eflags(e);
return;
}