ToC

实验内容

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

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

实验接线

这次的接线和上次是一样的。唯一的不同是不能不连 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