《30天自制操作系统》笔记----Day12

使用定时器

CPU通过参考机器周期(牢记每一条指令的执行时间。)来计量时间。
在电脑钟管理定时器,只需对PIT(Programmable Interval Timer)进行设定.(PIT与IRQ的0号相连)

IRQ0中断周期变更原理

需要了解的是IRQ0的中断周期变更原理:
①AL =0x34:OUT(0x43,AL);
②AL =中断周期的低8位:OUT(0x40,AL);
③AL =中断周期的高8位:OUT(0x40,AL);

总结:只要执行3次OUT指令就完成了中断周期的设置。
具体操作源码如下:(将中断周期设定为11932(0x2e9c),即中断频率100Hz)

#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;
}

接下来可以编写中断处理程序,同时将中断处理程序注册到IDT
基于上文,我们可以编写基准测试程序(benchmark program)测试电脑性能。

使用多个定时器

为了让实现的功能多样化,我们可以准备多个定时器来控制多个部件。

#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];
};
//这样我们可以通过MAX_TIMER来设定定时器个数,flags用于记录各个定时器状态

加快中断处理

先看原中断处理程序:

void inthandler20(int *esp)
{
	int i;
	io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00信号接收结束的信息通知给PIC*/
	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;
}

运行小慢的原因:

//在中断处理程序中采用:
timerctl.timer[i].timeout--
/*CPU要完成从内存中读取变量减去1,然后又往内存中写入操作,增加运行时间
*/

接下来想办法将中断处理的时间压缩:
①改变timer[i].timeout的含义,将其作为”计数器“,不是作为”倒计时器“。

void inthandler20(int *esp)
{
		int i;
		io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00信号接收结束的信息通知给PIC */
		timerctl.count++;
		for (i = 0; i < MAX_TIMER; i++) {
			if (timerctl.timer[i].flags == TIMER_FLAGS_USING) {
				if (timerctl.timer[i].timeout <= timerctl.count) { /* 这里! */
						timerctl.timer[i].flags = TIMER_FLAGS_ALLOC;
						fifo8_put(timerctl.timer[i].fifo, timerctl.timer[i].data);
				}
			}
		}
		return;
}

②之前每次中断都要执行500次(MAX_TIMER的次数)if语句,而其中定时器有的3s就超时,有的50s就超时,还有的一天后超时,没必要将每个都看完,3s定时器超时后记住该时刻,然后看”下一刻“的定时器(50s)。

/*定义一个结构体*/
struct TIMERCTL {
	unsigned int count, next; /* 这里! */
	struct TIMER timer[MAX_TIMER];
};
//修改后的中断处理程序:
void inthandler20(int *esp)
{
	int i;
	io_out8(PIC0_OCW2, 0x60); /* 把IRQ-00信号接收结束的信息通知给PIC */
	timerctl.count++;
	if (timerctl.next > timerctl.count) {
			return; /* 还不到下一个时刻,所以结束*/
	}
	timerctl.next = 0xffffffff;
	for (i = 0; i < MAX_TIMER; i++) {
		if (timerctl.timer[i].flags == TIMER_FLAGS_USING) {
				if (timerctl.timer[i].timeout <= timerctl.count) {
				/* 超时 */
						timerctl.timer[i].flags = TIMER_FLAGS_ALLOC;
						fifo8_put(timerctl.timer[i].fifo, timerctl.timer[i].data);
				} else {
				/* 还没有超时 */
						if (timerctl.next > timerctl.timer[i].timeout) {
								timerctl.next = timerctl.timer[i].timeout;
						}
					}
				}
		}
	return;
	}

③有一个问题,那就是到达next时刻和没到next时刻的定时器中断,它们的处理时间差别很大。模仿sheet.c的做法。除了定义sheet0[],还定义了*sheets[]。其里面存放的是按某种顺序排好的图层地址,按顺序描绘图层。

struct TIMERCTL {
	unsigned int count, next, using;//using相当于struct SHTCTL中的top
	struct TIMER *timers[MAX_TIMER];
	struct TIMER timers0[MAX_TIMER];
};
//改进后的inthandler20
void inthandler20(int *esp)
{
	int i,j;
	io_out8(PIC0_0CW2,0x60);
	timerctl.count++;
	if(timerctl.next >timerctl.count){
			return;
	}
	for(i=0;i<timerctl.using;i++){
			/* timers的定时器都处于动作中,所以不确认flags */
			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);
	}
	/* 正好有i个定时器超时了。其余的进行移位。 */
	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;
}		
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不吃人的坤坤坤坤坤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值