接着上一个问题,这要涉及一点硬件知识了,这些书上说得很明白了,咱们长话短说,计算机里有个芯片叫8042,是CPU和键盘之间代理,负责一些工作,不要让CPU太忙了,因为CPU是很珍贵的,好钢要用在刀刃上嘛。每当按下一个键盘,8042收到相应按的键的扫描码,接着8042把这个扫描码转换一下并把这个码放到对应的缓冲区中,并通知8259A一下,让它发出一个键盘中断。如果缓冲区没被清空,那么即使再发生键盘中断,8042也不会接受了。下面是书上的原理图:
这时我们就明白了,因为我们的键盘中断处理程序只是打印了一个星号,并没有做其它的,因为没有清掉缓冲区中的码,所以就不再相应新的键盘中断了。
那么怎么清掉缓冲区中的码呢,就是用in指令从对应的端口中取出值来,下面就是8042的各端口信息:
既然用到in指令,那么就要用到汇编了,我们写一个In_Byte函数,放到kliba.asm中:
global In_Byte
...
;In_Byte==============================================================
;u8 In_Byte(u16 port);
In_Byte:
push ebp
mov ebp,esp
push edx
mov edx,[ebp + 8]
in al,dx
nop
nop
pop edx
pop ebp
ret
;end of In_Byte=======================================================
别忘了在proto.h中添加声明:
- u8 In_Byte(u16 port);
接着修改Keyboard_Handler,做清空缓冲区的工作:
- void Keyboard_Handler(u32 irq_no)
- {
- In_Byte(0x60);
- Disp_Color_Str("*",0xc);
- }
make一下,运行,结果如图所示:
会发现敲一下键盘出现两个星号,这是为什么呢?看看书上怎样说的:因为敲击键盘有两个意义,一个敲击的内容,就是说是你敲的是哪个键,另一个是敲击的动作,分为3类,分别是:按下,保持按住的状态,以及放开。8048既要反映内容,又要反映在动作上。这是通过键盘产生的编码来反映的,这种编码被成为扫描码,分为Make Code,Break Code。当一个键被按下或者保持按下时,将会产生Make Code,当弹起某个键时,会产生Break Code。除了Pause键外,每一个按键对应一个Make Code和一个Break Code。
这下明白了吧,每按一次键,会产生两次中断,一个是Make,另一次是Break。
这下还不够好玩,让我们把从缓冲区中取得的扫描码打印一下:
- void Keyboard_Handler(u32 irq_no)
- {
- Disp_Int(In_Byte(0x60));
- /* Disp_Color_Str("*",0xc); */
- }
运行看看,输入a和9看看,结果如图所示:
分别是a的Make Code,Break Code,9的Make Code。下次再来讨论这些乱七八糟的码吧。