编程:在屏幕中间一次显示“A”-“Z”,并可以让人看清。在显示的过程中,按下ESC键后,改变显示的颜色。 代码如下,其中包括了 检测点15.1的内容: DATAS SEGMENT ;此处输入数据段代码 DW 0,0 DATAS ENDS STACKS SEGMENT ;此处输入堆栈段代码 DB 256 DUP (0) STACKS ENDS CODES SEGMENT ASSUME CS:CODES,DS:DATAS,SS:STACKS START: MOV AX,STACKS MOV SS,AX MOV SP,256 MOV AX,DATAS MOV DS,AX MOV AX,0 MOV ES,AX ;将原来的中断例程的入口地址存放到数据段中 PUSH ES:[9*4] POP DS:[0] PUSH ES:[9*4+2] POP DS:[2] ;在中断向量表中设置新的INT9中断例程的入口 ;放置在设置中断例程的入口地址的时候产生键盘中断 CLI ;禁止其他的可屏蔽中断 MOV WORD PTR ES:[9*4],OFFSET INT9 ;如果我们这边突然产生了键盘中断的话,那么我们的键盘中断 ;就会指向偏移地址是我们设置的地址,但是段地址是原来的 ;段地址的一个不同的地址空间,这样就会产生调用了不是我们 ;所设定的中断例程程序代码段,这当然是一个潜在的问题了,这边 ;我们应该怎样解决这样的问题呢,现在是使用STI和CLD的时候了 ;这边我们可以在改变中端例程的入口地址的时候,不允许可屏蔽的 ;中断产生,所以我们在这两行代码的前后加上两条指令就可以了 MOV ES:[9*4+2],CS STI ;解除可屏蔽中断 MOV AX,0B800H MOV ES,AX MOV AH,'A' S: MOV ES:[160*12+40*2],AH CALL DELAY INC AH CMP AH,'Z' JNA S ;程序执行完我们想要的效果后,将原来的中断例程的入口地址放回去 MOV AX,0 MOV ES,AX PUSH DS:[0] POP ES:[9*4] PUSH DS:[2] POP ES:[9*4+2] MOV AH,4CH INT 21H DELAY: PUSH AX PUSH DX MOV DX,1000H MOV AX,0 S1: SUB AX,1 SBB DX,0 CMP AX,0 JNE S1 CMP DX,0 JNE S1 POP DX POP AX RET ;下面是新的INT9中断例程 INT9: PUSH AX PUSH BX PUSH ES IN AL,60H PUSHF ;PUSHF ;POP BX ;AND BH,11111100B ;PUSH BX ;POPF ;上面的这部分说是可以精简的,因为程序在进入调用 ;中断例程的时候,就已经置IF,TF为0了 CALL DWORD PTR DS:[0] ;调用原来的INT 9中断例程, ;这边当然是为了原来的系统中,如果我们按了其他的键盘 ;上面的键的话,可以调用原来的INT 9中断例程,才不会导致 ;混乱 CMP AL,1 ;从60端口中读出的是对应的扫描码 ;如果是想读出控制键或者是切换键 ;的数据的话我们应该访问0040:17H ;端口的状态字节 JNE INT9RET MOV AX,0B800H MOV ES,AX INC BYTE PTR ES:[160*12+40*2+1] INT9RET: POP ES POP BX POP AX IRET ;这边的中断返回具体指的应该是我们 ;按键盘上面的一个键的时候,因为本身调用中断例程的话 ;中断例程是有这样的代码的,它的操作时POP IP,POP CS, ;POPF CODES ENDS END START ;程序最终运行的时候,没有按照我们的想法运行,按下ESC键的 ;时候,出现了错误!相比这个应该是跟堆栈有很大的关系了~~ ;其实现在发现是没有什么关系的,只是因为自己的代码竟然是 ;抄错了,现在改回来,已经是OK了,但是这个真的是很耐研究了 ;因为其中的对我来说很多的一点都是还存在的!首先是我们执行程序的 ;时候,他按照我们代码中的指令执行到现实字符的时候,这是如果我们 ;没有按上键盘上的任何键的时候,他当然是没有调用什么任何的中端例程 ;但是其实这是INT 9的中断例程还是我们代码中新安装的中断例程的,但是 ;在程序执行完后,我们仍然是没有按ESC键,INT 9中断例程改为原来的 ;INT 9 的中断例程这是程序是完整的,如果我们在字符显示的过程中 ;按下了ESC键的话,那么他会是改变字符串的颜色,因为在字符串 ;增变的过程中,我们INT 9的中断例程都一直是我们新安装的代码 ;大概的整体的也就是我们现在的这种思想吧。 ; ;但是这边安装的中断例程和我们之前安装的中断例程又不一样的地方了, ;因为我们之前安装的中端例程是将我们的中断例程存放到一个固定的 ;内存地址空间中,但是这边不是这样的,我们之前安装的中断例程 ;并没有模拟INT 指令,这就是关键了,所以我们这边要搞清楚的是 ;我们在按下一个ESC键的时候,其实内存中会自动的调用我们已经安装的 ;INT 9 的中断例程,直接调用就没有像我们使用INT 9这样指令的功能 ;所以这边我们就是要在中端例程中直接的去模拟我们的INT 指令的功能 ;所以这边其实我们是可以讲程序进行一定的改进的,只是这样的改进就是直接的 ;使用INT 指令,但是这样看来好像又是不合理的,因为我们按下键盘上的一个键 ;的时候,内存就会马上的调用INT 9的中端例程,根本就没有让我们指引的机会了 ;或者这应该就是下一节的内容吧……