30天自制操作系统(day13)

第13天:定时器

1、内容1:简化字符串显示,a文件夹

将类似于这种三步操作:
1)涂上背景色
2)在上面写字符
3)完成刷新
因为bootpack.c中出现了很多次如下代码,因此可以制作一个显示函数来使得bootpack.c中的内容进一步的简化,使得这个功能更更方便使用。
在这里插入图片描述
改写函数:
在这里插入图片描述
X、y是显示位置的坐标,c是字符颜色,b是背景颜色,s是字符串,l是字符串的长度。这样改写之后,虽然缩短了两行,但还是缩短了,挺好的。

2、内容2:重新调整FIFO缓冲区(1)b文件夹

在前一天中,所使用的定时器都是各占一个FIFO缓冲区,但是一个定时器可以不需要一个FIFO缓冲区,多个定时器可以用一个FIFO缓冲区。
修改代码如下:
在这里插入图片描述
可以看到,三个定时器共用了一个FIFO缓冲区,除此以外,修改if语句,使得程序更加精简。
在这里插入图片描述

3、内容3:测试性能,c文件夹

之前已经对程序不断的做了相应的改善,但如果想要知道程序究竟改善到了什么样的程度的话,还需要测试其性能。
先对HariMain进行一定的修改,恢复变量count,然后完全不显示计数,全力执行count++语句。当到了10秒后超时的时候,再显示这个count值。
在进入循环的时候添加count++,完全不显示计数,到了10秒后超时的时候再显示这个count值,在启动3秒的时候把count复位为0。这里的原理是用定时器计时到10秒输出循环的次数,但是每次要做中断处理(鼠标键盘)都会占用时间,那么循环的次数就会因此变小,越小说明处理的时间越长,这不是我们想要的。因为我们做的这个操作系统启动(初始化)的时候只要有些条件发生了变化,电脑花费的时间就会不稳定,这就导致开始的时间存在误差,所以统一在3秒后复位,保证时间统一开始。
修改程序如下:
在这里插入图片描述
在这里插入图片描述
运行后的结果如下:
在这里插入图片描述
需要注意的是,在测试的10秒内,不要动鼠标或者按键,因为如果触碰到了鼠标或者按键的话,那么程序就需要进行光标的显示处理,这样会减缓count的增长。5次的结果相差比较大,为什么会这样呢,是因为使用了模拟器而收到了windows的影响。根据以上趋势,每次优化之后count的值会变大,count的值越大说明每次的性能变好。
真机显示的数值收敛的很好,但还是出现了一定的误差,是因为电脑内部的温度变化或时钟频率的微妙变化。但是在我的电脑上面,是无法用make install出结果的,因为系统的不兼容。
在这里插入图片描述
除此以外,需要在启动3秒后,将count重置为0,是因为,如果不这样做的话,在真机的指定过程中,只要某些条件稍微有些变化,电脑初始化所花费的时间就会有很大的变化。因此在一开始的几秒内,不进行计数,这样便可以减去开始时的误差了。

4、内容4:重新调整FIFO缓冲区(2),g文件夹

在前面的内容中,已经能够把3个定时器归纳到一个FIFO缓冲区里,那么同样的道理,键盘和鼠标都可以归纳起来,用一个FIFO缓冲区进行管理。
代码如下:
在这里插入图片描述
同时因为存储数据的范围扩大,没有修改之前的FIFO参数类型为Char,最大只能达到256,对鼠标这种767的数值就不能指定,所以要修改FIFO中的参数类型(修改为int型以前的8位变成32位),只能将参数改为int型。
在这里插入图片描述
只需要简单的将char改为int即可。
在这里插入图片描述
初始化修改(实际上只修改了函数名和参数类型buf):
在这里插入图片描述
之后对键盘和鼠标的相关程序进行修改,不再使用FIFO8,而是使用FIFO32。
在这里插入图片描述
在这里插入图片描述
同时修改定时器的结构体,使得其也能使用FIFO32。
在这里插入图片描述
经过这样的修改之后,程序又再次简化,减少了8行。
因为在这次的修改之后,FIFO缓冲区的查询能够更快的完成,从而使得count++语句执行的次数更加的多了。这次的改善定时器处理还是一样的原理,但是在主函数里我们修改了只查询一个缓冲区,在没有修改之前我们要多次进行查询,所以这次要加速完成查询,使得“count++”在相同的时间内,执行的次数更多。

5、内容5:加快中断处理(4),h文件夹

虽然之前已经对中断处理进行了改良,但还是远远不够的,因为timer_settime虽然不是中断处理程序,但是依然是在中断禁止期间进行的,因此要快速的完成。现在使用的定时器比较少,只有3个,但如果任务增加,并且同时进行,需要更加多的定时器,并且还需要使用移位处理,这样便浪费了时间。
在FIFO中有一个取代移位处理的方法,便是在读取一个数据以后不让后面的数据向前靠齐,而是改变下一次的数据读取地址,虽然这个方法不错,但不适用于定时器。因为用timer_settime登陆中断时,后面的中断必须后移。
因此,采用另一种方法,加入一个next指针,其是一个地址变量,用来存放下一个即将超时的定时器的地址。
在这里插入图片描述
Next表示下一个即将超时的定时器地址,图示如下:
在这里插入图片描述
按照这样的结构,修改定时器的中断处理程序。修改定时器的中断处理程序(只改写timers[0]):
在这里插入图片描述
在这里插入图片描述
和以前不一样的是,对于timer[]数组来说,出了timer[0]以外其他都是完全没用的。如果不需要超时处理的话,也就没必要认真的去做移位处理,因此在移位处理中只改写timers[0]。
修改timer_settimer函数:
在这里插入图片描述
在这里插入图片描述
一共有4种情况,当运行的定时器只有一个时,那么就将next指向结束时的定时。如果插入的定时器的定时比之后的都要小,就将其放在第一个,如果是在两个中间的话,那么就如下图所示:
在这里插入图片描述
仅仅改变s->next和timer->next即可,这样就不需要进行移位了,就算使用很多的定时器,速度也不会变慢。如果最后的情况,直接将next赋为0即可。
变量t是从头开始对timers[]进行遍历用的,而s用来保存前一个t值。其实整个的timers[]已经不需要了,不过并不是全都不要,只需要最前面的timers[0]即可。
在这里插入图片描述

6、内容6:使用“哨兵”简化程序,i文件夹

使用哨兵简化程序,首先timer.c在去除移位处理后,其中的timer_settime函数还是比较繁琐的,就需要简化该程序。之前是按照4中可能来进行分类处理的。
在这里插入图片描述
在进行初始化的时候,将时刻0xffffffff的定时器连到最后一个定时器上。但其实无论如何都不可能到达这个时刻,因此不会发生超时问题,它一直处在后面,便是所谓的哨兵。将哨兵加入到程序中,
在这里插入图片描述
如果使用需要调整的程序(一年调整一次)必须保证不改变哨兵时刻,哨兵的时刻调整:
在这里插入图片描述
因为加入了所谓的哨兵,settime的状况便发生了变化,只剩下两种情况会发生。
在这里插入图片描述
因此程序便可以简化:
在这里插入图片描述
在这里插入图片描述
将程序修改到这样的情况后,Using便失去了它的用处,之前它是对运行中的定时器进行计数,那时候还是用数组timers[],其帮主记录timers[]已经被使用到了哪个位置,但在不使用数据timers[]之后,现在又有了哨兵的情况下,便不会出现Using为0的情况,至少还有1个,因此便可以删去Using了。这样程序更加的简化了。

发布了205 篇原创文章 · 获赞 110 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_40851744/article/details/103444641