30天自制操作系统第七天

操作系统实验日志7

第7天:FIFO与鼠标控制

一、实验主要内容

1、 内容1:获取按键编码

功能: 实现在键盘上按下一个键,屏幕就会显示信息,让程序按下一个键之后不结束,在屏幕输出按键的编码的功能。

在这里插入图片描述
在这里插入图片描述

从编号为0X0060的设备输入的8位信息是按键编码,0X0060的设备就是键盘。

运行结果: 下或者松开一个键就会显示出对应的编码。

2、 内容2:加快中断处理

加快中断处理的原因: 中断程序处理的过慢,可能会出现鼠标运动不连贯、无法接收网上的数据等情况。

方法: 将原来写在中断处理程序中的显示部分的代码移出去,然后判断前面的中断是否有被处理,如果位处理就把这个中断的数据扔掉,否则处理该数据。

在这里插入图片描述

主函数中对获取的端口号的处理:

在这里插入图片描述

(至于为什么要在开始屏蔽总中断,请看问题一)

注意: 在执行hlt指令前一定要将终端打开,否则停机后就无法接受中断了。

注释:在使用io_stihlt时,不能用sti、hlt两个指令来代替,因为如果这样的话,sti后产生的中断写到keybuf中的数据就会因为停机不被察觉到。而根据CPU规范,STI后紧接着HLT指令,那么就不会受理两条指令之间的中断,使用io_stihlt就可以解决这一问题。

运行发现在按右ctrl时:

加快中断之前:按下显示1D,松开显示9D;

加快中断之后:按下、松开都开始显示E0。

原因: 当按下右Crl键时,会产生两个字节的键码值“E0 ID",而松开这个键之后,会产生两个字节的键码值“E09D"。 在一次产生两个字节键码值的情况下,因为键盘内部电路1次只能发送一个字节,所以1次按键就会产生两次中断,第一次中断时发送E0,第二次中断时发送ID。

在加快中断之前,两次中断所发送的值都能收到,瞬间显示E0之后,紧接着又显示1D或是9D。在加快中断之后,在收到E0之后,又收到按键产生的1D或者9D,而这个字节被舍弃了。

注释:电脑的按键一直按下会不停的触发中断,松开按键又会触发一次中断。我们小学期做的实验中对按键中断的处理是借助定时器,定时器时间到了就会进行中断,中断会根据有关按键的一些标志位进行函数处理,这是这两边的一些区别。

3、 内容3:制作FIFO缓冲区

上面会出现错误,是因为之前只能接收一个中断发来的数据,所以中断发生的太快,有超过一个字节的数据就会被忽略,有两个解决方案:

解决方案1:增加变量

在这里插入图片描述

解决方案2:data用数组存储

在这里插入图片描述

显然,用数组更方便一些,我们在使用这些缓冲数据时,要采取FIFO策略,也就是先入先出策略,程序实现:

缓存区定义:

在这里插入图片描述

中断处理:

在这里插入图片描述

输出部分:

在这里插入图片描述

4、 内容4:改善FIFO缓冲区

第三部分的缓冲区的实现是通过每读出一个数据,就将剩余的所有数据整体向前移动一位,这样在数据较多的情况下,时间开销比较大。

因此就要想到一种办法来解决,第一种是不移动数据,而是记录要读取的数据的位置,每次就在数据最后写入,但是这样会出现这样一个问题:当写入的位置变为最后一个位置,就无法继续写入。

为了解决这个问题,就是当写入位置变为了最后一个,就让它去数组首部继续写入,当读取位置到了最后一个,就让它去首部去读。

PS:现在的缓冲区是用数组来实现的,其实用一个链表或者是循环链表来实现更佳,每读取一个数据就释放一部分空间,或者就直接采用容器中的队列。

关键代码:

在这里插入图片描述

5、 内容5:整理FIFO缓冲区

为了使缓冲区具有通用性,对FIFO缓冲区做出整理:

(1)定义一个结构体,对缓冲区进行封装:

在这里插入图片描述

(2)对上面定义的结构体初始化:

在这里插入图片描述

(3)存入1字节信息

在这里插入图片描述

(4)从FIFO中读取一个数据,与写入类似

(5)观察缓冲区状态

在这里插入图片描述

然后键盘中断函数变为:

在这里插入图片描述

6、 内容6:鼠标

使鼠标可以正常中断,需要使①鼠标控制电路②鼠标本身有效。

①鼠标控制电路包含在键盘控制电路中,键盘控制带电路初始化完成,鼠标控制电路也就能正常激活。

在这里插入图片描述
在这里插入图片描述

在主函数中调用init_keyboard函数后,鼠标控制电路的准备就完成了。

②激活鼠标

在这里插入图片描述

然后在主函数中调用enable_mouse()函数,就能进行鼠标中断了。

在这里插入图片描述

鼠标不动也会触发鼠标中断,在这个代码f中,我们再按下键盘屏幕上也不会显示任何号码了,而下一个代码就可以,这是为什么呢?

7、 内容7:从鼠标接收数据

存入鼠标中断的数据:

在这里插入图片描述

鼠标和键盘的原理几乎相同,不同之处只有送给PIC的中断受理通知。IRQ-12时从PIC的第4号(从PIC相当于IRQ-08~IRQ-15),首先要通知IRQ-12受理已完成,再通知主PIC。这是因为主/从PIC的协调不能够自动完成,如果程序不告诉主PIC该怎么做,它就会忽视从PIC的下一个中断请求。

取出鼠标数据:

鼠标数据取得方法与键盘完全一致,唯一区别就是传送到这个设备的数据是来自键盘还是鼠标要靠中断号码来区别。

二、遇到的问题及解决方法

1.描述问题1:在第二部分,笔者在主函数中的io_halt函数中的for循环中,作者说要将io_cli来先屏蔽中断,否则会乱套,但是我举了好多个例子也没有发现会出问题,反而是假如我屏蔽了总中断,在flag为0的时候,发生了中断却被屏蔽了.

解决方法:经过思考,以及io_stihlt函数的作用,假如不加这一条语句的话,在进入第一个if语句后发生了中断,但是紧接着就会停机,keybuf存的数据就不会被察觉到,然后发生下次中断的时候,显示的是第一次出现的数据,就会乱套。

2.描述问题2:在代码f中,当我们激活了鼠标后,这时候会源源不断地触发鼠标中断。这时候按下键盘后,编码不会在屏幕上显示,我有两种推测:第一种推测是在激活鼠标控制电路的时候,把键盘控制电路中的模式设置成了鼠标模式;第二种推测是鼠标中断太频繁,来不及处理键盘中断。但是在代码g中,鼠标和键盘的数据都可以接收,然后我把代码f中的鼠标中断函数里的内容都注释掉也还是接收不到键盘的数据。

解决方法:尚未找到答案,依然有疑惑。

3.描述问题3:长按按键是否会不停产生中断,怎么验证?

解决方法:最开始我的目的是在创新的时候,如果一下一下的按键就是慢速移动,长按就是快速移动。所以就有一个问题,如何判断按键是否被长按。因为长按时圆会连续移动,这就说明了不止中断一次,否则会进入停机状态。我然后利用这个特性,试了很多方法都不成功,然后我就对长按一直产生中断这个结论产生了怀疑。我在函数中加了一个打印值,打印现在的端口号还有缓存区的数据的多少,然后我还加了一个延迟(不加延迟的话,中断处理的很快,看不出来个所以然),因为我是在测试上下左右四个键,我发现:①按上下左右四个键时,也是每按一次产生两个中断,第一次产生的数据是0xE0,第二次产生的数据就是我们正常看到的数据。②运行时,长按上键,可以看到0xE0、0x48不停交替出现,因此可以得知长按会不停的产生中断。

三、程序设计创新点

1、描述创新点1: 在这次的考核中,同时按下两个键,比如说同时按上和左键,圆会向左上角的方向移动,这里显示一下它的运动轨迹。

以上和左搭配为例,关键代码:

在这里插入图片描述

在这里插入图片描述

2、描述创新点2:在移动圆的过程中,如果是一下一下的按,就将以为1的速度移动;如果是在长按,就以4个像素点的速度移动。关键代码:

在这里插入图片描述

不足之处:因为中断的频率是根据电脑的状态的不同而不同,所以代码中的延迟有时候会有问题,所以功能有时候会失效。

四、实验心得体会

在这次实验中,主要实现了对中断后获取的数据的处理,最终我们用了FIFO策略,引入了缓存区的概念,实现的时候使用了数组这个数据结构,但是如果我们直接使用队列这个数据结构的话会更高效一些。

然后还有一个要注意的是,在对程序的编写中,还要注意对硬件的控制,比如PIC、键盘的端口等等,这样才能确保可以接收到硬件发来的数据。

在实验中,我还发现对中断的处理和处理时对下一个中断的到来以及处理安排上是很重要的,需要我们严加设计的,应该也是系统设计的重要部分,还有书中出现的各种编号(像不同端口的地址什么的),不知道具体去哪找,不同的cpu也不知道有没有什么区别。

最开始感觉这天的实验比较简单没啥东西,但是静下心来思考的时候,还是能够发现一些问题的。因此我觉得要设计好一个操作系统真的是太困难了,需要逻辑非常的缜密,然后对整个计算机系统都要非常的了解,然后想起来最近开源的鸿蒙os,开源的话应该会让它能够发展的更快一些,尽早的完整,不在被别人嘲笑。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值