1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
| ;======================= 端口地址 PORT_A EQU 280H ;A口地址 PORT_B EQU 281H ;B口地址 PORT_C EQU 282H PORT_CTL EQU 283H ;控制口地址 ;=======================
;======================= 键盘扫描码表 DATA SEGMENT TABLE_A DB 77H,7BH,7DH,7EH,0B7H,0BBH,0BDH,0BEH ;=========0===1===2===3===4=====5====6===7========= DB 0D7H,0DBH,0DDH,0DEH,0E7H,0EBH,0EDH,0EEH ;=========8====9====10===11===12===13===14===15==== TABLE_C DB 3FH,06H,5BH,4FH,66H,6DH,7DH,0FH DB 7FH,67H,77H,7CH,39H,5EH,79H,71H DATA ENDS
;======================== 堆栈段 STACK SEGMENT STACK DW 50 DUP(0) TOP_STACK LABEL WORD STACK ENDS ;========================
;======================== 代码段 CODE SEGMENT ASSUME CS:CODE,DS:DATA,SS:STACK START: MOV AX,STACK MOV SS,AX ;给堆栈段赋地址 LEA SP,TOP_STACK ;sp指向堆栈栈顶 MOV AX,DATA MOV DS,AX ;给数据段赋地址
;======================== 初始化,方式0,A口输出,B,C口输入 MOV DX,PORT_CTL ;指向控制口 MOV AL,10001011B ;方式0,A口输出,C口高位输入,B口方式0,B口输入,C口低四位输入 OUT DX,AL ;写入控制字
;======================== 向所有行送0 MOV DX,PORT_A ;指向A口 MOV AL,00H OUT DX,AL ;向A口各位输出0
;======================== 读列,查看是否所有键均松开 MOV DX,PORT_B ;指向B口 WAIT_OPEN: IN AL,DX ;键盘状态读入B口 AND AL,0FH ;保留低四位(只查看低4位,列值) CMP AL,0FH ;低四位是否均为1?(各键均松开) JNE WAIT_OPEN ;低四位不均为1,则继续循环这个函数,直到低四位均为1
;======================== 各键均已松开,再查看列是否有0,即是否有键按下 WAIT_PRES: IN AL,DX AND AL,0FH CMP AL,0FH JE WAIT_PRES ;低四位均为1时(没有键按下),循环这个函数,直到有键按下
;======================== 有键按下,延时20ms,防止抖动 MOV CX,16EAH DELAY: LOOP DELAY ;循环16EAH次(按照指令时间,这么多次,大概是20ms)
;======================== 再查列,看键是否被压着(如果还被压着,则不是抖动问题,而是真的按下) IN AL,DX AND AL,0FH CMP AL,0FH JE WAIT_PRES ;如果没有键按下,则说明之前是抖动,就跳回到等待到按键函数
;======================== 若键依旧被压着,就确定是哪一个键被压下 MOV AL,0FEH ;AL=1111 1110 B MOV CL,AL ;CL=1111 1110 B NEXT_ROW: MOV DX,PORT_A OUT DX,AL ;先让第一行全部置0(低电平) MOV DX,PORT_B IN AL,DX ;读B口状态 AND AL,0FH ;取低4位(列值) CMP AL,0FH ;查看低4位(列值)看是否有键按下(是否均为1) JNE ENCODE ;否,说明有键按下,则转去编码函数 ROL CL,01 ;左移一次,让下一行都变为0 MOV AL,CL JMP NEXT_ROW ;再次循环函数,查看第二行
;========================= 找到一列为低电平,对压键的行列值编码 ENCODE: MOV BX,000FH ;建立地址指针,先指向F键(15)对应的地址 IN AL,DX ;读B口状态(行列号) NEXT_TRY: CMP AL,TABLE_A[BX] ;读入的行列值与表中查的相等吗? JE DONE ;相等,转出到完成函数 DEC BX ;不相等,则转到下一个地址(往小的慢慢转) JNS NEXT_TRY ;BX还大于0时,继续跳回到NEXT_TRY函数 MOV AH,01 ;一直查到地址为负数都没查到,置出错码01→AH JMP EXIT ;直接跳到退出程序 DONE: MOV AL,BL ;BL中存有键的16进制代码(按下的键是几) MOV BX,OFFSET TABLE_C XLAT MOV DX,PORT_C OUT DX,AL MOV CX,0FFH JMP DELAY2 DELAY2:LOOP DELAY2 JMP START EXIT: HLT CODE ENDS END
|