ImageVerifierCode 换一换
格式:DOCX , 页数:20 ,大小:538.76KB ,
资源ID:9071607      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/9071607.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(30天自制操作系统日志第7天.docx)为本站会员(b****7)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

30天自制操作系统日志第7天.docx

1、30天自制操作系统日志第7天操作系统实验日志学号20160810520姓名甘昆禄专业年级班级智能1601实验日期2018.11.07实验项目第7天:FIFO与鼠标控制一、实验主要内容1. 获取按键编码实现功能:让程序在按一个键后不结束,然后在屏幕上显示出信息。这样就可以切实完成中断处理程序了。(显示按键编码,本来以为会显示按键表示内容,比如按A显示A,还是太天真了哈哈,估计后面还要改)修改int.c程序中的inthandler21函数:#define PORT_KEYDAT 0x0060void inthandler21(int *esp)/*来自PS/2键盘的中断*/ struct BOOT

2、INFO *binfo = (struct BOOTINFO *) ADR_BOOTINFO; unsigned char data, s4; io_out8(PIC0_OCW2, 0x61); /*通知PIC*IRQ-01已经受理完毕*/ data = io_in8(PORT_KEYDAT); sprintf(s, %02X, data); boxfill8(binfo-vram, binfo-scrnx, COL8_008484, 0, 16, 15, 31); putfonts8_asc(binfo-vram, binfo-scrnx, 0, 16, COL8_FFFFFF, s); r

3、eturn;io_out8(PIC0_OCW2, 0x61); 这句话用来通知PIC“已经知道发生了IRQ1中断。如果是IRQ3,则写成0x63.也就是说,将”0x60+IRQ号码”输出给OCW2就可以。执行这句话之后,PIC继续时刻监视IRQ1中断是否发生。反过来,如果忘记了执行这句话,PIC就不在监视IRQ1中断,不管下次由键盘输入什么信息,系统都感知不到了。但事实上,我发现按字母键和其他健还是有些区别的。按其他健后再按另外的健会有反应。但假若你一开始按字母键再按另外的健就没有反应了。2、加快中断处理中断处理是打断CPU本来的工作,加塞要求进行处理。在处理进行期间不再接受别的中断。若中断处

4、理速度太慢会影响CPU的的工作。将处理字符显示内容的功能从中断处理中提出来,将按键编码接收下来保存到变量中,然后由HariMain偶尔去查看这个变量。发现有数据就显示出来。struct KEYBUF unsigned char data, flag;#define PORT_KEYDAT 0x0060struct KEYBUF keybuf;void inthandler21(int *esp)/*来自PS/2键盘的中断*/ unsigned char data; io_out8(PIC0_OCW2, 0x61); /*通知PIC*IRQ-01已经受理完毕*/ data = io_in8(PO

5、RT_KEYDAT); if (keybuf.flag = 0) keybuf.data = data; keybuf.flag = 1; return;在函数中用到了两个变量:data和flag,所以可以建一个结构体把两个变量集中起来。将bootpack.c中MariMain函数中的io_halt()函数更改如下:for(;) io_cli(); if (keybuf.flag = 0) io_stihlt(); else i = keybuf.data; keybuf.flag = 0; io_sti(); sprintf(s, %02X, i); boxfill8(binfo-vram,

6、 binfo-scrnx, COL8_008484, 0, 16, 15, 31); putfonts8_asc(binfo-vram, binfo-scrnx, 0, 16, COL8_FFFFFF, s); 即将最初的inthandler21()函数拆解成了inthandler21()和for循环函数。开始先用io_cli指令屏蔽中断(是为了防止被另外的指令中断),然后去看一看keybuf.flag的值是什么。如果flag是0说明键还没有按下,就去执行io_hlt指令。但是由于已经执行io_cli屏蔽了中断,所以就这样去之心HLT指令的话,即使有键按下,程序也不会有任何反应。所以STI和H

7、LT两个指令都要执行,而执行这两个指令的函数就是io_stihlt。执行HLT指令后,如果收到PIC的通知,CPU就会被唤醒。这样,CPU首先回去执行中断程序。中断处理程序执行完之后又回到for语句的开头,再执行io_cli函数。若执行到else语句,说明在keybuf.data里存入了按键编码。先将这个键码(keybuf.data)值保存到变量i中,然后将flag置为0表示把键码值清为空,再通过io_sti语句开放中断。这样一来,在屏蔽中断期间所做的处理非常少,且会加快操作系统的中断处理过程。最后莫忘了在bootpack中添加这一句:extern struct KEYBUF keybuf;以

8、及早for循环中使用的i的声明,还需要将struct KEYBUF unsigned char data, flag;添加到.h文件中。右ctrl键的键码值比较特殊,按下会产生两个字节的键码值”E0 1D”,而松开这个键之后会产生两个字节的键码值”E0 9D”。在一次产生两个字节键码值的情况下,因为键盘内部电路一次只能发送一个字节,所以一次按键就会产生两次中断,第一次中断时发送E0,第二次中断时发送1D。3、制作、整理缓冲区上一步在按右ctrl键时存入参数应该有两个字节,但只显示了一个字节舍弃了最开始那个。所以设计一个能够存储多字节的缓冲区,就不会马上存满并舍弃较早存入的字节了。在结构体KEY

9、BUF里增加变量,可以定义一个数组:struct KEYBUF unsigned char data4;数组data4就是存入字节的缓冲区,这里可以使用先前讲到的FIFO、FILO这种栈,这里需要的是FIFO型,也就是先接收到的字节先显示出来。于是代码可以修改成这样:struct KEYBUF unsigned char data32; int next;这一段代码还是放在.h文件中,然后在int.c中修改代码如下:void inthandler21(int *esp)/*来自PS/2键盘的中断*/ unsigned char data; io_out8(PIC0_OCW2, 0x61); /

10、*通知PIC*IRQ-01已经受理完毕*/ data = io_in8(PORT_KEYDAT); if (keybuf.flag 32) keybuf.datakeybuf.next = data; keybuf.next+; return;keybuf的起始点是“0”,所以最初存储的数据是keybuf.data0。下一个数据是keybuf.data1,接着是2,一次类推,一共是32个存储位置。下一个存储位置用变量next来管理,这样就能记住32个数据而不会溢出。修改HariMain中代码:for (;) io_cli(); if (keybuf.next = 0) io_stihlt();

11、 else i = keybuf.data0; keybuf.next-; for (j = 0; j vram, binfo-scrnx, COL8_008484, 0, 16, 15, 31); putfonts8_asc(binfo-vram, binfo-scrnx, 0, 16, COL8_FFFFFF, s); 注意里面用到的j还是要先声明。如果next不是0,则说明至少有一个数据。最开始的一个数据肯定是放在data0中的,将这个数存入到变量i中去。这样,数就减少了一个,所以讲next减去1。如图:然后遇到的问题就是上面的缓冲区处理需要数据移送,而且还是在中断期间,花时还容易出错。

12、,这时候就需要改善了。主要看代码就可以理解这个缓冲区,相当于定义了两个指针,一个指向下一个要读的地方,一个指向下一个要存的地方。数据读出位置追着数据写入位置,且可以在写入位置到达尽头即缓冲区为空时重新回到0的位置,循环使用缓冲区空间。Bootpack.h的结构体修改:struct KEYBUF unsigned char data32; int next_r, next_w, len;Int.c中inthandler21函数修改如下:void inthandler21(int *esp)/*来自PS/2键盘的中断*/ unsigned char data; io_out8(PIC0_OCW2,

13、 0x61); /*通知PIC*IRQ-01已经受理完毕*/ data = io_in8(PORT_KEYDAT); if (keybuf.next vram, binfo-scrnx, COL8_008484, 0, 16, 15, 31); putfonts8_asc(binfo-vram, binfo-scrnx, 0, 16, COL8_FFFFFF, s); 这样修改之后没有任何数据移送操作,这个缓冲区可以记录大量数据,执行速度又快。缓冲区固定为32字节以后改起来就不方便,所以把它定义成可变的。所以采用了指针的方法*buf(data32),将缓冲区的总字节保存在变量size(len)

14、中。变量free用于保存缓冲区里没有数据的字节数。缓冲区的地址保存在变量buf里。p代表下一个数据写入地址next_w,q代表写一个数据读出地址next_r。结构体修改之后如下:struct KEYBUF unsigned char *buf; int p, q, size , free, flags;为了初始化缓冲区以及实现对缓冲区的相关操作,新建了一个fifo.c的文件。/* FIFO */#include bootpack.h#define FLAGS_OVERRUN 0x0001/fifo_init是结构的初始化函数,用来设定各种初始值,也就是设定FIFO8结构的地址以及与结构有关vo

15、id fifo8_init(struct FIFO8 *fifo, int size, unsigned char *buf)/*初始化FIFO缓冲区*/ fifo-size = size; fifo-buf = buf; fifo-free = size; /*缓冲区的大小*/ fifo-flags = 0; fifo-p = 0; /*下一个数据写入位置*/ fifo-q = 0; /*下一个数据读出位置*/ return;/fifo8_put是往FIFO缓冲区存储1字节信息的函数。如果一出返回-1,没有溢出就返回0int fifo8_put(struct FIFO8 *fifo, uns

16、igned char data)/*想FIFO传递数据并保存*/ if (fifo-free = 0) /*空余没有了,溢出了*/ fifo-flags |= FLAGS_OVERRUN; return -1; fifo-buffifo-p = data; fifo-p+; if (fifo-p = fifo-size) fifo-p = 0; fifo-free-; return 0;/fifo8_get函数是从FIFO缓冲区取出1字节的函数int fifo8_get(struct FIFO8 *fifo)/*从FIFO取得一个数据*/ int data; if (fifo-free = f

17、ifo-size) /如果缓冲区为空,则返回-1 return -1; data = fifo-buf(fifo-q); fifo-q+; if (fifo-q = fifo-size) fifo-q = 0; fifo-free+; return data;/报告一下到底积攒了多少数据int fifo8_status(struct FIFO8 *fifo) return fifo-size - fifo-free;然后根据fifo.c中的函数在int.c中修改 inthandler21函数如下struct FIFO8 keyfifo;void inthandler21(int *esp)/*

18、来自PS/2键盘的中断*/ unsigned char data; io_out8(PIC0_OCW2, 0x61); /*通知PIC*IRQ-01已经受理完毕*/ data = io_in8(PORT_KEYDAT); fifo8_put(&keyfifo, data); return;该函数中的&是取地址运算符,用它可以取得结构或变量的地址值。Fifo8_put接受的第一个参数是内存地址,与之匹配,这里调用时传递的第一个参数也要是内存地址。HariMain函数内容如下: char s40, mcursor256, keybuf32; for (;) io_cli(); if (fifo8_

19、status(&keyfifo) = 0) io_stihlt(); else i = fifo8_get(&keyfifo); io_sti(); sprintf(s, %02X, i); boxfill8(binfo-vram, binfo-scrnx, COL8_008484, 0, 16, 15, 31); putfonts8_asc(binfo-vram, binfo-scrnx, 0, 16, COL8_FFFFFF, s); 4、鼠标中断分配给鼠标的中断号码是IRQ12,与键盘的IRQ1比起来差了好多代。要让鼠标信号得到处理,要让下面两个装置有效,一个是鼠标控制电路,一个是鼠标本

20、身。关于控制电路的设定:鼠标控制电路包含在键盘控制电路里,如果键盘控制电路的初始化正常完成,鼠标电路控制器的激活也就完成了。在bootpack.c后添加如下代码:#define PORT_KEYDAT 0x0060#define PORT_KEYSTA 0x0064#define PORT_KEYCMD 0x0064#define KEYSTA_SEND_NOTREADY 0x02#define KEYCMD_WRITE_MODE 0x60#define KBC_MODE 0x47/让键盘控制电路(KBC)做好准备动作,等待控制指令的到来。void wait_KBC_sendready(voi

21、d) /等待键盘控制电路准备完毕 for (;) if (io_in8(PORT_KEYSTA) & KEYSTA_SEND_NOTREADY) = 0) break; /*break语句是从for循环中强制退出*/ return;void init_keyboard(void) /初始化键盘控制电路,然后在HariMain函数调用init_keyboard函数,鼠标控制电路的准备就完成了 wait_KBC_sendready(); io_out8(PORT_KEYCMD, KEYCMD_WRITE_MODE); wait_KBC_sendready(); io_out8(PORT_KEYDA

22、T, KBC_MODE); return;/然后开始发送激活鼠标的指令。归根结底还是要向键盘控制器发送指令#define KEYCMD_SENDTO_MOUSE 0xd4#define MOUSECMD_ENABLE 0xf4/这个函数与init_keyboard函数非常相似,不同点在于写入的数据不同。如果往键盘控制电路发送指令0xd4,下一个数据就会自动发送给鼠标void enable_mouse(void) /*激活鼠标*/ wait_KBC_sendready(); io_out8(PORT_KEYCMD, KEYCMD_SENDTO_MOUSE); wait_KBC_sendready

23、(); io_out8(PORT_KEYDAT, MOUSECMD_ENABLE); return; /*顺利的话,键盘控制器会返送回ACK(0xfa)*/鼠标中断现在已经有了,接下来是取出中断数据,int.c中添加代码:struct FIFO8 mousefifo;void inthandler2c(int *esp)/* 来自PS/2鼠标的中断 */ unsigned char data; io_out8(PIC1_OCW2, 0x64); /*通知PIC1 IRQ-12的受理已经完成*/ io_out8(PIC0_OCW2, 0x62); /*通知PIC0 IRQ-02的受理已经完成*/

24、 data = io_out8(PORT_KEYDAT); fifo8_put(&mousefifo, data); return;鼠标和键盘的原理几乎相同,所以程序也就非常相似。不同之处只有送给PIC的中断受理通知。IRQ-12时从PIC的第4号(从PIC相当于IRQ-08IRQ-15),首先要通知IRQ-12受理已完成,然后再通知主PIC。这是因为主/从PIC的协调不能够自动完成,如果程序不交给主PIC该怎么做,它就会忽视从PIC的下一个中断请求。鼠标数据取得方法如下:ifo8_init(&mousefifo, 128, mousebuf);for (;) io_cli(); if (fi

25、fo8_status(&keyfifo) + fifo8_status(&mousefifo) = 0) io_stihlt(); else if (fifo8_status(&keyfifo) != 0) i = fifo8_get(&keyfifo); io_sti(); sprintf(s, %02X, i); boxfill8(binfo-vram, binfo-scrnx, COL8_008484, 0, 16, 15, 31); putfonts8_asc(binfo-vram, binfo-scrnx, 0, 16, COL8_FFFFFF, s); else if (fifo8

26、_status(&mousefifo) != 0) i = fifo8_get(&mousefifo); io_sti(); sprintf(s, %02X, i); boxfill8(binfo-vram, binfo-scrnx, COL8_008484, 32, 16, 47, 31); putfonts8_asc(binfo-vram, binfo-scrnx, 32, 16, COL8_FFFFFF, s); 因为鼠标往往会比键盘更快地送出大量数据,所以我们将它的FIFO缓冲区增加到了128字节,避免溢出。取得数据的程序中,如果键盘和鼠标的FIFO缓冲区都为空了,就执行HLT。如果不

27、是两个都空,就先检查keyinfo,如果有数据就取出一个显示出来。如果keyinfo是空,就再去检查mouseinfo,如果有数据,就取出一个显示出来。二、遇到的问题及解决方法1、弄了很久还是对键盘的中断有很多问题,第一个就是作者说的按一下键有两个字节信息,即会产生两个中断,这两个中断究竟怎么处理的。因为就算到了今天的第四个工程,作者说要搞个聪明的缓冲区,但还是觉得怪怪的,按键的前面那个字节编码一直就没有显示出来,这样做的缓冲区真的聪明吗,还是说真的只要这两个字节编码的后面那个就够了。 在网上查询的资料是说我们按下按键一般会持续50ms左右,我们知道计算机1S达到10的9次方数量级的处理能力,

28、那么这按一下键我们CPU指令的处理至少都有106数量级了,这样说这个中断都不知道产生了多少次了。而事实是我们看见画面只显示了按键的后面那个编码,所以有理由相信,如果持续有中断,那么CPU会优先处理后来的中断,再处理后面那个字节的中断,所以我们缓冲区就会存的是后面那个字节的编码。2、关于字母的按键信息 还有一个问题就是发现字母的按键信息和其他的真的不同,按键似乎怎么样都只显示一个字符的编码没有出现过其他的,在右Ctrl键可以显示前面那个字节编码(即E0)的情况下,按下A,你仍然见到的是编码1E。而且字母按键很霸道,按下去再按其他的键就没有反应了,只有按下shift键才行,我猜这个应该就是编辑键和功能键的差别吧。(后面补充,后来和同学讨论时发现有的键盘的字母键是可以显示两个字节编码的,就可以顺利显示出按下按键表示的内容,且只显示一个。然后我发现我的电脑有时候按了很多次shift键后再按字母键也可以看见按下和松开的区别了,但一般都是不行的。然后还发现作者写的是PS/2标准键盘的中断,同学的键盘是的,而我的是增强型,不知道是不是这

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1