[微机实验/TD-PITE] 键盘扫描及数码管显示实验

实验内容

在数码管上显示键盘输入的内容,新输入的内容显示在数码管的最右侧。

当数码管显示空间已满时,删除最左侧的文本。

实验接线

这次的接线和上次是一样的。唯一的不同是不能不连 Y1-Y4 了(笑)

代码

A8255 EQU 0600H
B8255 EQU 0602H
C8255 EQU 0604H
CON8255 EQU 0606H
ROWOUT EQU 200H

SSEG SEGMENT STACK
  DW 20 DUP(?)
SSEG ENDS

DATA SEGMENT
  TBL:
    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
  SEQ:
    DB 00011111B ;; POS 0
    DB 00101111B ;; POS 1
    DB 00110111B ;; POS 2
    DB 00111011B ;; POS 3
    DB 00111101B ;; POS 4
    DB 00111110B ;; POS 5
  VAL:
    DB 6 DUP(0)
  VAL_USED:
    DB 6 DUP(0)
  VAL_HEAD DW 0005H
DATA ENDS

CODE SEGMENT
ASSUME CS:CODE, DS:DATA, SS:SSEG
START PROC
  MOV AX, DATA
  MOV DS, AX

  MOV AL, 81H ;;10001001B ;; A B OUT, C IN
  MOV DX, CON8255
  OUT DX, AL

  MOV AX, 0000H
LO:
  CALL VAL_DISPLAY
  CALL SCAN
  CMP AX, 10H
  JE LO
  CALL VAL_INSERT
WAIT_UP:
  CALL VAL_DISPLAY
  CALL KEY_PRESSED
  CMP AX, 1
  JE WAIT_UP
  JMP LO

  MOV AX, 4C00H
  INT 21H
START ENDP

SCAN PROC
BEGIN:
  CALL KEY_PRESSED ;; EXIT IF NOT PRESSED
  CMP AX, 0
  JE SCAN_NO_KEY

  CALL DELAY
  CALL KEY_PRESSED
  CMP AX, 0
  JE SCAN_NO_KEY
  
  MOV CH, 0FEH
  MOV CL, 0
COLUMN:
  MOV AL, CH
  MOV DX, A8255
  OUT DX, AL
  MOV DX, C8255
  IN AL, DX
L1:
  TEST AL, 1
  JNZ L2
  MOV AL, 00H
  JMP KCODE
L2:
  TEST AL, 2
  JNZ L3
  MOV AL, 04H
  JMP KCODE
L3:
  TEST AL, 4
  JNZ L4
  MOV AL, 08H
  JMP KCODE
L4:
  TEST AL, 8
  JNZ NEXT
  MOV AL, 0CH
KCODE:
  ADD AL, CL
  JMP SCAN_FIN
NEXT:
  INC CL
  MOV AL, CH
  TEST AL, 08H
  JE SCAN_NO_KEY
  ROL AL, 1
  MOV CH, AL
  JMP COLUMN

SCAN_NO_KEY:
  MOV AX, 10H
SCAN_FIN:
  RET
SCAN ENDP

;; RETURN WHETHER KEY PRESSED IN AX
KEY_PRESSED PROC
  MOV DX, A8255
  MOV AL, 00H
  OUT DX, AL   ;; LINE OUTPUT 0000
  
  MOV DX, C8255
  IN AL, DX    ;; GET LINE STATUS
  AND AL, 0FH
  CMP AL, 0FH
  JE KP_NONE

  MOV AX, 1 ;; KEY PRESSED
  RET
KP_NONE:
  MOV AX, 0
  RET
KEY_PRESSED ENDP


;; INSERT AX TO VAL[VAL_HEAD]
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; INDEX: 0 1 2 3 4 5
;; VALUE: A B C D E F
;;  HEAD: |
;; INPUT: 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; INDEX: 0 1 2 3 4 5
;; VALUE: 0 B C D E F
;;  HEAD:   |
;;        (-> 1 BYTE)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
VAL_INSERT PROC
  PUSH BX
  LEA BX, VAL
  MOV SI, VAL_HEAD
  
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;;          !!!CAUTION!!!           ;;
  ;; MAKE SURE TO USE 8-BIT REGISTER  ;;
  ;; IF YOU WANT TO MOVE BYTES        ;;
  ;; BETWEEN MEMORY AND REGISTER!!    ;;
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  MOV [BX+SI], AL   ;; NUMBER BYTE
  MOV DL, 1
  MOV [BX+SI+6], DL  ;; DISPLAY BYTE
  INC SI
  CMP SI, 5 ;; HEAD <= 5, SKIP
  JLE VI_EXIT
  
  SUB SI, 6 ;; MAKE HEAD IN [0, 5]
  
VI_EXIT:
  MOV VAL_HEAD, SI
  POP BX
  RET
VAL_INSERT ENDP


;; DISPLAY VAL ARRAY
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; INDEX: 0 1 2 3 4 5
;; VALUE: A B C D E F
;;  HEAD:           |
;; THIS IS THE SAME DIRECTION AS SCREEN
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
VAL_DISPLAY PROC
  PUSH CX
  MOV CX, 6
  
  LEA BX, VAL
  MOV SI, VAL_HEAD

VD_LO:
  PUSH CX
  MOV AH, [BX+SI]
  MOV AL, CL
  DEC AL
  
  MOV DH, [BX+SI+6]
  CMP DH, 0
  JE VD_SKIP_BIT

  PUSH BX
  PUSH SI
  CALL PUT
  CALL DELAY
  POP SI
  POP BX

VD_SKIP_BIT:
  POP CX
  ;; CALCULATE NEXT SI
  INC SI
  CMP SI, 5 ;; HEAD <= 5, SKIP
  JLE VD_SI_SKIP
  SUB SI, 6
  
VD_SI_SKIP:
  LOOP VD_LO
  
  POP CX
  RET
VAL_DISPLAY ENDP

;; NUM: AH
;; POS: AL
PUT PROC
  PUSH AX

  ;; SELECT POS
  LEA BX, SEQ
  PUSH AX
  MOV AH, 0
  MOV SI, AX

  ;; OUTPUT POS
  MOV DX, A8255
  MOV AL, [BX+SI]
  OUT DX, AL
  POP AX
  
  ;; SELECT NUM
  LEA BX, TBL
  MOV AL, AH
  MOV AH, 0
  MOV SI, AX

  ;; OUTPUT DATA
  MOV DX, B8255
  MOV AL, [BX+SI]
  OUT DX, AL

  POP AX
  RET
PUT ENDP

DELAY PROC
  MOV CX, 0FFH
  LOOP $
  RET
DELAY ENDP

CODE ENDS
END START

选做实验

说明

通过键盘输入 0-E,将刚刚输入的一位数字显示在数码管上。

最开始数码管无显示。在输入新数字后,将输入的数字显示在数码管最右端。之后每次输入数字,数字的显示位置向左移动一格。

当显示的数字已经位于最左时,此时输入的数字并不立即向右移动,而是先在最左停顿一次,下一个输入的数字再向右移动。

到达最右时的处理和最左一致。

键盘输入 F 时程序退出。

效果

上面说的这段话简直就不是人话,还是看一下实际的效果吧(

代码

A8255 EQU 0600H
B8255 EQU 0602H
C8255 EQU 0604H
CON8255 EQU 0606H
ROWOUT EQU 200H

SSEG SEGMENT STACK
  DW 20 DUP(?)
SSEG ENDS

DATA SEGMENT
  TBL:
    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
    DB 00H ;; CLR
  SEQ:
    DB 00011111B ;; POS 0
    DB 00101111B ;; POS 1
    DB 00110111B ;; POS 2
    DB 00111011B ;; POS 3
    DB 00111101B ;; POS 4
    DB 00111110B ;; POS 5
  VAL DB 00H
  VAL_POS DB 00H
  VAL_SHOW DB 00H
  VAL_STEP DB 00H
DATA ENDS

CODE SEGMENT
ASSUME CS:CODE, DS:DATA, SS:SSEG
START PROC
  MOV AX, DATA
  MOV DS, AX

  MOV AL, 81H ;;10001001B ;; A B OUT, C IN
  MOV DX, CON8255
  OUT DX, AL

  MOV AX, 0000H
LO:
  CALL NUM_DISPLAY
  CALL SCAN
  CMP AX, 10H
  JE LO
  CMP AX, 0FH
  JE MA_EXIT
  CALL NUM_SET
WAIT_UP:
  CALL NUM_DISPLAY
  CALL KEY_PRESSED
  CMP AX, 1
  JE WAIT_UP
  JMP LO

MA_EXIT:
  MOV AX, 1000H
  CALL PUT
  MOV AX, 4C00H
  INT 21H
START ENDP

SCAN PROC
BEGIN:
  CALL KEY_PRESSED ;; EXIT IF NOT PRESSED
  CMP AX, 0
  JE SCAN_NO_KEY

  CALL DELAY
  CALL KEY_PRESSED
  CMP AX, 0
  JE SCAN_NO_KEY
  
  MOV CH, 0FEH
  MOV CL, 0
COLUMN:
  MOV AL, CH
  MOV DX, A8255
  OUT DX, AL
  MOV DX, C8255
  IN AL, DX
L1:
  TEST AL, 1
  JNZ L2
  MOV AL, 00H
  JMP KCODE
L2:
  TEST AL, 2
  JNZ L3
  MOV AL, 04H
  JMP KCODE
L3:
  TEST AL, 4
  JNZ L4
  MOV AL, 08H
  JMP KCODE
L4:
  TEST AL, 8
  JNZ NEXT
  MOV AL, 0CH
KCODE:
  ADD AL, CL
  JMP SCAN_FIN
NEXT:
  INC CL
  MOV AL, CH
  TEST AL, 08H
  JE SCAN_NO_KEY
  ROL AL, 1
  MOV CH, AL
  JMP COLUMN

SCAN_NO_KEY:
  MOV AX, 10H
SCAN_FIN:
  RET
SCAN ENDP

;; RETURN WHETHER KEY PRESSED IN AX
KEY_PRESSED PROC
  MOV DX, A8255
  MOV AL, 00H
  OUT DX, AL   ;; LINE OUTPUT 0000
  
  MOV DX, C8255
  IN AL, DX    ;; GET LINE STATUS
  AND AL, 0FH
  CMP AL, 0FH
  JE KP_NONE

  MOV AX, 1 ;; KEY PRESSED
  RET
KP_NONE:
  MOV AX, 0
  RET
KEY_PRESSED ENDP

;; SET AL TO VAL & MOVE POS
NUM_SET PROC
  PUSH AX
  MOV VAL, AL
  MOV AL, VAL_POS
  ADD AL, VAL_STEP
  
  CMP VAL_STEP, 0 ;; REGULAR STATUS: STEP != 0
  JNE NS_REG
  CMP VAL_POS, 5
  JE NS_LMOST
  MOV VAL_STEP, 1 ;; POS == 0, RIGHT MOST
  JMP NS_FIN
NS_LMOST: ;; POS == 5, LEFT MOST
  MOV VAL_STEP, -1
  JMP NS_FIN
  
NS_REG:
  CMP AL, 5
  JE NS_SET0
  CMP AL, 0
  JE NS_SET0
  JMP NS_FIN
NS_SET0:
  MOV VAL_STEP, 0
NS_FIN:
  MOV VAL_SHOW, 1
  MOV VAL_POS, AL
  POP AX
  RET
NUM_SET ENDP

;; DISPLAY VAL AT VAL_POS
NUM_DISPLAY PROC
  ;MOV AL, VAL_SHOW
  CMP VAL_SHOW, 0
  JE ND_SKIP

  MOV AH, VAL
  MOV AL, VAL_POS
  CALL PUT
  CALL DELAY
ND_SKIP:
  RET
NUM_DISPLAY ENDP

;; NUM: AH
;; POS: AL
PUT PROC
  PUSH AX

  ;; SELECT POS
  LEA BX, SEQ
  PUSH AX
  MOV AH, 0
  MOV SI, AX

  ;; OUTPUT POS
  MOV DX, A8255
  MOV AL, [BX+SI]
  OUT DX, AL
  POP AX
  
  ;; SELECT NUM
  LEA BX, TBL
  MOV AL, AH
  MOV AH, 0
  MOV SI, AX

  ;; OUTPUT DATA
  MOV DX, B8255
  MOV AL, [BX+SI]
  OUT DX, AL

  POP AX
  RET
PUT ENDP

DELAY PROC
  MOV CX, 0FFH
  LOOP $
  RET
DELAY ENDP

CODE ENDS
END START
暂无评论

发送评论 编辑评论


				
上一篇
下一篇