;各种地址
nCS5 EQU 0DE28H
PA8255 EQU nCS5+0
PB8255 EQU nCS5+2
PC8255 EQU nCS5+4
CTL8255 EQU nCS5+6
DISPBUFF EQU 3000H
;按键抖动时间
KeyShock EQU 06FFFH
DATAS SEGMENT
;此处输入数据段代码
;数码管段码 0 1 2 3 4 5 6 7 8 9 A B C D E F
SegCode DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH,77H,7CH,39H,5EH,79H,71H
;矩阵键盘按键码 0 1 2 3 4 5 6 7 8 9 A B C D E F
KeyCode DB 11H,21H,41H,81H,12H,22H,42H,82H,14H,24H,44H,84H,18H,28H,48H,88H
DATAS ENDS
STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
;将8086控制总线拉到确定电平
MOV DX,00H
OUT DX,AL
IN AL,DX
;此处输入代码段代码
;初始化数码管显示缓冲区
InitBuff:
MOV SI,DISPBUFF
MOV CX,4
Loop1:
MOV [SI],CL
INC SI
LOOP Loop1
;主函数...
MOV DI,03H
Loop3:
CALL Disp
CALL MatrixKeyboard
JMP Loop3
;矩阵键盘扫描子函数
MatrixKeyboard PROC
Begin:
;初始化8255控制字
MOV DX,nCS5 + 6
MOV AL,10001000B ;PC高4位作键盘扫描列信号,PC低4位作键盘扫描行信号
OUT DX,AL
Scan:
;PC口
MOV DX,nCS5 + 4 ;PC行扫描给出全低电平
MOV AL,00H
OUT DX,AL
WaitKey:
IN AL,DX ;读出PC列扫描电平
AND AL,0F0H ;去除低4位,保留高4位
CMP AL,0F0H ;将得到的列电平和F0H比较,如果相等说明列线全高,没有按键按下
JZ ExtiKeyboard ;如果没有按键按下,直接返回
MOV CX,KeyShock ;如果有按键按下,先延时一会,去抖动
LOOP $
;开始正反向扫描
IN AL,DX ;读取列值
AND AL,0F0H
CMP AL,0F0H
JZ ExtiKeyboard ;如果再次读到的结果是高电平,表明前次按下是抖动,不予理会
MOV CL,AL ;如果确实有按键按下则记录列地址
MOV DX,nCS5 + 6 ;重新设置控制字
MOV AL,10000001B ;PC行列翻转,高4位做键盘扫描行信号,低4为作键盘扫描行信号
OUT DX,AL
MOV DX,nCS5 + 4 ;PC行扫描给出全低电平
MOV AL,00H
OUT DX,AL
IN AL,DX
AND AL,0FH ;取低4位
OR AL,CL ;将正向和反向的合成按键码
MOV BX,OFFSET KeyCode
MOV SI,00H
NOT AL ;AL取反,完全只是为了计算按键码方便
ScanKey:
CMP AL,[BX][SI] ;将读到的键码和键码表比较
JE FindKey ;如果相等(找到),调到找到处理部分
INC SI ;如果不相等,再跟下一个比较
CMP SI,10H
JZ Begin ;找到第16个还没找到表示按键非法,重新从头开始扫描
JMP ScanKey ;与键码表中下一个键码比较
FindKey:
CALL PutBuff
;MOV BX,DISPBUFF
;MOV [BX],SI
ExtiKeyboard:
RET
MatrixKeyboard ENDP
PutBuff PROC
MOV BX,DISPBUFF
ADD BX,DI
MOV AX,SI
MOV [BX],AL
DEC DI
JNC Finish
MOV DI,03H
Finish:
RET
PutBUff ENDP
;数码管显示子函数
Disp PROC
MOV SI,DISPBUFF
MOV CL,0FEH
Loop2:
MOV AL,CL
MOV DX,PB8255 ;位选
OUT DX,AL
MOV BX,OFFSET SegCode
MOV AX,0
MOV AL,[SI]
ADD BX,AX
MOV AL,[BX]
MOV DX,PA8255
OUT DX,AL
CALL DelayMs
CALL ClearDig
CMP CL,0F7H ;判断有没有一遍扫完
JZ ExitDisp
INC SI
ROL CL,1
JMP Loop2
ExitDisp:
RET
DISP ENDP
;清除数码管显示子函数
ClearDig PROC
MOV DX,PA8255
MOV AL,00H
OUT DX,AL
RET
ClearDig ENDP
;延时子函数
DelayMs PROC
PUSH AX ;保护原先的寄存器内容
PUSH BX
MOV AX,00FFH
L2: MOV BX,000FH
L3: DEC BX
JNZ L3
DEC AX
JNZ L2
POP BX ;恢复原先的寄存器内容,注意这里的弹栈顺序
POP AX
RET
DelayMs ENDP
;收尾工作
JMP $
MOV AH,4CH
INT 21H
CODES ENDS
END START