您好,欢迎访问三七文档
当前位置:首页 > 行业资料 > 其它行业文档 > 30天自制操作系统日志第7天
操作系统实验日志学号20160810520姓名甘昆禄专业年级班级智能1601实验日期2018.11.07实验项目第7天:FIFO与鼠标控制一、实验主要内容1.获取按键编码实现功能:让程序在按一个键后不结束,然后在屏幕上显示出信息。这样就可以切实完成中断处理程序了。(显示按键编码,本来以为会显示按键表示内容,比如按A显示A,还是太天真了哈哈,估计后面还要改)修改int.c程序中的inthandler21函数:#definePORT_KEYDAT0x0060voidinthandler21(int*esp)/*来自PS/2键盘的中断*/{structBOOTINFO*binfo=(structBOOTINFO*)ADR_BOOTINFO;unsignedchardata,s[4];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);return;}io_out8(PIC0_OCW2,0x61);这句话用来通知PIC“已经知道发生了IRQ1中断。如果是IRQ3,则写成0x63.也就是说,将”0x60+IRQ号码”输出给OCW2就可以。执行这句话之后,PIC继续时刻监视IRQ1中断是否发生。反过来,如果忘记了执行这句话,PIC就不在监视IRQ1中断,不管下次由键盘输入什么信息,系统都感知不到了。但事实上,我发现按字母键和其他健还是有些区别的。按其他健后再按另外的健会有反应。但假若你一开始按字母键再按另外的健就没有反应了。2、加快中断处理中断处理是打断CPU本来的工作,加塞要求进行处理。在处理进行期间不再接受别的中断。若中断处理速度太慢会影响CPU的的工作。将处理字符显示内容的功能从中断处理中提出来,将按键编码接收下来保存到变量中,然后由HariMain偶尔去查看这个变量。发现有数据就显示出来。structKEYBUF{unsignedchardata,flag;};#definePORT_KEYDAT0x0060structKEYBUFkeybuf;voidinthandler21(int*esp)/*来自PS/2键盘的中断*/{unsignedchardata;io_out8(PIC0_OCW2,0x61);/*通知PIC*IRQ-01已经受理完毕*/data=io_in8(PORT_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,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和HLT两个指令都要执行,而执行这两个指令的函数就是io_stihlt。执行HLT指令后,如果收到PIC的通知,CPU就会被唤醒。这样,CPU首先回去执行中断程序。中断处理程序执行完之后又回到for语句的开头,再执行io_cli函数。若执行到else语句,说明在keybuf.data里存入了按键编码。先将这个键码(keybuf.data)值保存到变量i中,然后将flag置为0表示把键码值清为空,再通过io_sti语句开放中断。这样一来,在屏蔽中断期间所做的处理非常少,且会加快操作系统的中断处理过程。最后莫忘了在bootpack中添加这一句:externstructKEYBUFkeybuf;以及早for循环中使用的i的声明,还需要将structKEYBUF{unsignedchardata,flag;};添加到.h文件中。右ctrl键的键码值比较特殊,按下会产生两个字节的键码值”E01D”,而松开这个键之后会产生两个字节的键码值”E09D”。在一次产生两个字节键码值的情况下,因为键盘内部电路一次只能发送一个字节,所以一次按键就会产生两次中断,第一次中断时发送E0,第二次中断时发送1D。3、制作、整理缓冲区上一步在按右ctrl键时存入参数应该有两个字节,但只显示了一个字节舍弃了最开始那个。所以设计一个能够存储多字节的缓冲区,就不会马上存满并舍弃较早存入的字节了。在结构体KEYBUF里增加变量,可以定义一个数组:structKEYBUF{unsignedchardata[4];};数组data[4]就是存入字节的缓冲区,这里可以使用先前讲到的FIFO、FILO这种栈,这里需要的是FIFO型,也就是先接收到的字节先显示出来。于是代码可以修改成这样:structKEYBUF{unsignedchardata[32];intnext;};这一段代码还是放在.h文件中,然后在int.c中修改代码如下:voidinthandler21(int*esp)/*来自PS/2键盘的中断*/{unsignedchardata;io_out8(PIC0_OCW2,0x61);/*通知PIC*IRQ-01已经受理完毕*/data=io_in8(PORT_KEYDAT);if(keybuf.flag32){keybuf.data[keybuf.next]=data;keybuf.next++;}return;}keybuf的起始点是“0”,所以最初存储的数据是keybuf.data[0]。下一个数据是keybuf.data[1],接着是[2],一次类推,一共是32个存储位置。下一个存储位置用变量next来管理,这样就能记住32个数据而不会溢出。修改HariMain中代码:for(;;){io_cli();if(keybuf.next==0){io_stihlt();}else{i=keybuf.data[0];keybuf.next--;for(j=0;jkeybuf.next;j++){keybuf.data[j]=keybuf.data[j+1];}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);}}注意里面用到的j还是要先声明。如果next不是0,则说明至少有一个数据。最开始的一个数据肯定是放在data[0]中的,将这个数存入到变量i中去。这样,数就减少了一个,所以讲next减去1。如图:然后遇到的问题就是上面的缓冲区处理需要数据移送,而且还是在中断期间,花时还容易出错。,这时候就需要改善了。主要看代码就可以理解这个缓冲区,相当于定义了两个指针,一个指向下一个要读的地方,一个指向下一个要存的地方。数据读出位置追着数据写入位置,且可以在写入位置到达尽头即缓冲区为空时重新回到0的位置,循环使用缓冲区空间。Bootpack.h的结构体修改:structKEYBUF{unsignedchardata[32];intnext_r,next_w,len;};Int.c中inthandler21函数修改如下:voidinthandler21(int*esp)/*来自PS/2键盘的中断*/{unsignedchardata;io_out8(PIC0_OCW2,0x61);/*通知PIC*IRQ-01已经受理完毕*/data=io_in8(PORT_KEYDAT);if(keybuf.next32){keybuf.data[keybuf.next_w]=data;keybuf.len++;keybuf.next_w++;if(keybuf.next_w==32){keybuf.next_w=0;}}return;}HariMain函数读出数据代码如下:for(;;){io_cli();if(keybuf.len==0){io_stihlt();}else{i=keybuf.data[keybuf.next_r];keybuf.len--;keybuf.next_r++;if(keybuf.next_r==32){keybuf.next_r=0;}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);}}这样修改之后没有任何数据移送操作,这个缓冲区可以记录大量数据,执行速度又快。缓冲区固定为32字节以后改起来就不方便,所以把它定义成可变的。所以采用了指针的方法*buf(data[32]),将缓冲区的总字节保存在变量size(len)中。变量free用于保存缓冲区里没有数据的字节数。缓冲区的地址保存在变量buf里。p代表下一个数据写入地址next_w,q代表写一个数据读出地址next_r。结构体修改之后如下:structKEYBUF{unsignedchar*buf;intp,q,size,free,flags;};为了初始化缓冲区以及实现对缓冲区的相关操作,新建了一个fifo.c的文件。/*FIFO*/#includebootpack.h#defineFLAGS_OVERRUN0x0001//fifo_init是结构的初始化函数,用来设定各种初始值,也就是设定FIFO8结构的地址以及与结构有关voidfifo8_init(structFIFO8*fifo,intsize,unsignedchar*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,没有溢出就返回0intfifo8_put(structFIFO8*fifo,unsignedchardata)/*想FIFO传递数据并保存*/{if(fifo-free==0)/*空余没有了,溢出了*/{fifo-flags|=FLAGS_OVERRUN;return-1;}fifo-buf[fifo-p]=data;fifo-p++;if(fifo-p==fifo-size){fifo-p=0;}fifo-free--;return0;}//fifo8_get函数是从FIFO缓冲区取出1字节的函数intfifo8_get(structFIFO8*fifo)/*从F
本文标题:30天自制操作系统日志第7天
链接地址:https://www.777doc.com/doc-6028500 .html