实验内容
基础部分:
1、编写程序,实现如下功能:初始时数码管无显示;第一次按下键盘时,在最右侧数码管对应的十六进制数字;以后每次按下键盘,则将当前显示的数字全部向左移动一位(最左侧的数字移出数码管),并将刚刚键入的数字显示在数码管的最右侧。
拓展部分:
2、编写程序,将按键所对应的数字(0~E)按要求显示在指定的数码管上:
代码
1
A8255_A EQU 0600H
A8255_B EQU 0602H
A8255_C EQU 0604H
A8255_CON EQU 0606H
ROWOUT EQU 200H
DATA SEGMENT
TABLE DB 11101110B
DB 11101101B
DB 11101011B
DB 11100111B
DB 11011110B
DB 11011101B
DB 11011011B
DB 11010111B
DB 10111110B
DB 10111101B
DB 10111011B
DB 10110111B
DB 01111110B
DB 01111101B
DB 01111011B
DB 01110111B
VALUE DB 3FH ;0
DB 06H ;1
DB 5BH ;2
DB 4FH ;3
DB 66H ;4
DB 6DH ;5
DB 7DH ;6
DB 07H ;7
DB 7FH ;8
DB 6FH ;9
DB 77H ;A
DB 7CH ;B
DB 39H ;C
DB 5EH ;D
DB 79H ;E
DB 71H ;F
TEMP DB 0H
POS1 DB 0H
POS2 DB 0H
DATA ENDS
CODE SEGMENT
ASSUME CODE:CS,DS:DATA
KEY PROC FAR ;段间远调用
START:
PUSH DS ;保存DS
MOV AX,0 ;AX清0
PUSH AX ;保存AX
MOV AX,DATA
MOV DS,AX
MOV DX,A8255_CON
MOV AL,80H
OUT DX,AL ;设置8255的工作方式
MOV DX,A8255_B
MOV AL,00H
OUT DX,AL ;开放所有端口
MOV DX,A8255_A
MOV AL,00H
OUT DX,AL ;让所有灯熄灭
X1: MOV DX,ROWOUT ;设置行输出端口
MOV AL,00H
OUT DX,AL ;行输出0000,准备检查是否有任何键按下
INC DX ;设置列输入端口地址ROWOUT+1
IN AL,DX ;输入线状态
AND AL,0FH ;析取D3~D0列信号线
CMP AL,0FH
JZ X1 ;没有任何键按下,继续查询
CALL D20ms ;有键按下,延时消抖
MOV DX,ROWOUT
MOV AL,00H
OUT DX,AL ;消抖后确定是否有任何键按下
INC DX
IN AL,DX ;读入列线状态
AND AL,0FH ;析取D3~D0列信号线
CMP AL,0FH
JZ X1 ;此时,说明延时消抖前的按键判断是源于干扰
;或者,延时消抖时间不足,重新查询
MOV AH,11111110B ;设置行扫描初值,首先扫描第0行
MOV CX,4 ;设置行扫描初值,共4行
X2: MOV DX,ROWOUT ;设置行输出端口地址
MOV AL,AH ;传递行扫描值
OUT DX,AL ;行扫描值输出,准备检查在哪一列
INC DX
IN AL,DX
AND AL,0FH
CMP AL,0FH
JNZ X3 ;找到按键所在的列号,转X3
ROL AH,1
LOOP X2
MOV AX,80H ;4行全部扫描完,却未发现有键安喜爱(可
;能出现了干扰),以80H作为这种情况的标志
;该指令的设置,主要考虑到程序的完备性,
;即可以使程序在任何情况下都能正确执行
JMP XEND
X3: MOV CL,4
SHL AH,CL ;AH逻辑左移4位,将低4位的行号移到高4位
OR AL,AH ;行号与列号'或',形成键的位置码
LEA BX,TABLE ;设置TABLE位置码表的指针
MOV CL,0 ;设置键号初值为0
X4: CMP AL,[BX] ;在TABLE中查找本次形成的键位置码
JZ X5 ;找到则转X5,对应键号就在CL中
INC CL
INC BX
CMP CL,10H
JNZ X4
MOV AH,0FFH ;CL等于10H,说明在TABLE表中没有找到
;对应的键位置吗,其原因可能是出现了重建
;的情况,以0FFH作为这种情况的标志
JMP XEND
X5: MOV AH,CL ;将CL中保存的键号传到AH中
CALL LMOVESHOW
CALL RESET
MOV DX,A8255_A
MOV AL,11011111B
OUT DX,AL
MOV DX,A8255_B
MOV AL,AH
OUT DX,AL
JMP X1
LMOVESHOW: ;将数码管上每个显示灯上的段码移到其左边的显示灯上
PUSH AX
PUSH CX
MOV CX,5
MOV POS1,11111101B ;将显示灯位码放入POS1中
MOV POS2,11111110B ;将上面显示灯左边的位码放入POS2中
X7: CALL RESET
MOV DX,A8255_A
MOV AL,POS1
OUT DX,AL ;选中位码为POS1的显示灯
MOV DX,A8255_B
PUSH AX
IN AL,DX ;读取其段码到TEMP中
MOV TEMP,AL
POP AX
MOV DX,A8255_A
MOV AL,POS2
OUT DX,AL ;选中位码为POS2的显示灯
MOV DX,A8255_B
MOV AL,TEMP
OUT DX,AL ;将POS1处的段码送入POS2处
ROL POS1,1 ;POS1,POS2均循环左移1位
ROL POS2,1
LOOP X7
POP CX
POP AX
RET
RESET: ;保持显示灯状态
PUSH AX
PUSH DX
MOV DX,A8255_A
MOV AL,00H
OUT DX,AL
POP DX
POP AX
RET
XEND:
NOP
RET
D20ms:
PUSH CX
MOV CX,0FH
X: LOOP X
POP CX
RET
KEY ENDP
CODE ENDS
END START
2
A8255 EQU 0600H ;选择数字
B8255 EQU 0602H ;B: 段码
C8255 EQU 0604H
CON8255 EQU 0606H
DATA SEGMENT
TABLELED : ;段码表
DB 3FH ;0的段码
DB 06H
DB 5BH
DB 4FH
DB 66H
DB 6DH
DB 7DH
DB 07H
DB 7FH
DB 6FH ;9的段码
DB 77H
DB 7CH
DB 39H
DB 5EH
DB 79H
DB 71H
TABLEKEY: ;位码表
DB 11101110B ;键码,前四位表示列,后四位表示行,0表示被按下的键的位置
DB 11011110B;1
DB 10111110B;2
DB 01111110B;3
DB 11101101B;4
DB 11011101B;5
DB 10111101B;6
DB 01111101B;7
DB 11101011B;8
DB 11011011B;9
DB 10111011B
DB 01111011B
DB 11100111B
DB 11010111B
DB 10110111B
DB 01110111B;F
TABLEWEI: ;移动的位置
DB 11011111B
DB 11101111B
DB 11110111B
DB 11111011B
DB 11111101B
DB 11111110B
DB 11111110B
DB 11111101B
DB 11111011B
DB 11110111B
DB 11101111B
DUAN DB 00H;要显示的段码
WEI DB 10111111B;要显示的位码
TURN DB 00H
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START:
MOV AX,DATA
MOV DS,AX
MOV AL,81H ;控制字A口输出,B口输出,C口低四位输入
MOV DX,CON8255
OUT DX,AL ;初始化
X1:
CALL SHOW ;显示
CALL SCAN ;扫描是否有键按下
JZ X1 ;没有任何键按下,继续查询
CALL DELAY20;延迟消抖
CALL SCAN
JZ X1
;消除抖动??
CALL CHECK
CMP AH,0FH
JZ XEND;按下F,程序终止
LEA SI,TABLELED
MOV AL,AH ;键值
MOV AH,0
MOV BX,AX
MOV AH,[SI+BX] ;键值对应的段码
MOV DUAN,AH;存段码
;操作位码
LEA SI,TABLEWEI
MOV BL,TURN
;AND BX,00FFH
MOV BH,00H
MOV AH,[SI+BX]
MOV WEI,AH
INC TURN
CMP TURN,0BH
JZ X6
JMP X7
X6:
MOV TURN,00H
X7:
CALL SHOW
CALL SCAN
JNZ X7
JMP X1
;检查哪个键被按下
CHECK:
MOV AH,11111110B
MOV CX,4
X2:
MOV DX,A8255 ;输入,A port stands for row
MOV AL,AH
OUT DX,AL
MOV DX,C8255
IN AL,DX
AND AL,0FH
CMP AL,0FH ;比较指令,如果低四位都是1111的话代表没有输入,继续循环
JNZ X3
ROL AH,1 ;左移一位
LOOP X2
MOV AH,80H
JMP XEND
X3:
MOV CL,4 ;输入
SHL AH,CL ;将AH左移四位
OR AL,AH ;al contribute low digits,ah high digits
LEA BX,TABLEKEY ;BX代表的是键位的起始位置
MOV CL,0 ;offset for correct position
X4:
CMP AL,[BX]
JZ X5
INC CL
INC BX
CMP CL,10H
JNZ X4
MOV AH,0FFH
JMP XEND
X5:
MOV AH,CL;AH保存键值
RET
XEND:
MOV AH,4CH
INT 21H
SHOW:
PUSH AX
MOV DX,A8255
MOV AL,WEI
OUT DX,AL;位码
MOV DX,B8255
MOV AL,DUAN
OUT DX,AL;段码
CALL DELAY
POP AX
RET
;检查是否有键按下
SCAN:
MOV DX,B8255
MOV AL,00H
OUT DX,AL;清空显示缓冲
MOV DX,A8255
MOV AL,00H ;选择所有位,所以要清除显示缓冲
OUT DX,AL
MOV DX,C8255
IN AL,DX
AND AL,0FH
CMP AL,0FH
RET
DELAY:
PUSH CX
MOV CX,0300H
LL:
LOOP LL
POP CX
RET
DELAY20:
PUSH CX
MOV CX,0100H
T1:
MOV AX,009FH
T2:
DEC AX
JNZ T2
LOOP T1
POP CX
RET
CODE ENDS
END START