实验内容
实现一个以秒为单位的计时器。
使用 1MHz
的时钟源和 8254
、8259
构成周期为 1
秒的计时中断时钟。
通过键盘 0-9
输入计时的分钟数,A
控制计时过程的开始和结束,B
控制暂停和继续,C
退出程序。
具体功能如下:
- 初始状态:无显示。此时通过
0-9
输入计时初值,范围为1-99
分钟,显示在数码管3
和4
上。 A
键(启动/取消):初值设置完成后按A
键,从计数初值开始倒计时。数码管1
和2
显示分,3
和4
显示秒;计时过程中按A
键,停止倒计时,回到初始状态。B
键(暂停/继续):计时过程中按B
键,暂停倒计时,显示停止时间;再次按B
键,从停止时间继续倒计时。- 计时结束:倒计时至
0000
时,闪烁三次后回到初始状态。 C
键(退出):任何时刻按C
键,熄灭数码管,程序退出。
实验接线
正常连接 8254
和 8255
即可。在本实现中,8254
接 IOY0
,8255
接 IOY1
。
代码
不想动了,就这样吧,代码就不解释了(逃
A8255 EQU 0640H B8255 EQU 0642H C8255 EQU 0644H CON8255 EQU 0646H C008254 EQU 0600H C018254 EQU 0602H C028254 EQU 0604H CON8254 EQU 0606H 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 CNT_STARTED DB 00H CNT_PAUSED DB 00H VAL_MIN: DB 2 DUP(10H) VAL_SEC: DB 2 DUP(0) MIR_COUNTER DB 00H DATA ENDS CODE SEGMENT ASSUME CS:CODE, DS:DATA START PROC MOV AX, 0 MOV DS, AX ;; INIT 8255 MOV AL, 81H ;;10001001B ;; A B OUT, C IN MOV DX, CON8255 OUT DX, AL ;; MIR6 MOV AX, OFFSET MIR6 MOV SI, 38H MOV [SI], AX MOV AX, CS MOV SI, 3AH MOV [SI], AX ;; -------------------------------------------------- ;; INIT 8259 CLI MOV AL, 11H OUT 20H, AL MOV AL, 08H OUT 21H, AL MOV AL, 04H OUT 21H, AL MOV AL, 07H OUT 21H, AL MOV AL, 2FH OUT 21H, AL STI ;; -------------------------------------------------- ;; -------------------------------------------------- ;; INIT 8254 MOV AL, 00110110B MOV DX, CON8254 OUT DX, AL MOV DX, C008254 MOV AL, 24H ;; LOWER 8 BYTES OUT DX, AL MOV AL, 0F4H ;; HIGHER 8 BYTES OUT DX, AL ;; -------------------------------------------------- MOV AX, DATA MOV DS, AX LO: CALL NUM_DISPLAY CALL SCAN CMP AX, 10H JE LO CMP AX, 0AH ;; PRESS A TO START/STOP JNE LO_NB ;;;;;; CMP CNT_STARTED, 00H JE COUNTER_START ;; COUNTER_STOP MOV CNT_STARTED, 0 CALL CLR_TIME LEA BX, VAL_MIN MOV [BX], 1010H JMP WAIT_UP COUNTER_START: MOV CNT_STARTED, 1 MOV CNT_PAUSED, 0 JMP WAIT_UP ;;;;;; LO_NB: CMP AX, 0BH ;; PRESS B TO PAUSE/RESUME JNE LO_NC XOR CNT_PAUSED, 1 JMP WAIT_UP LO_NC: CMP AX, 0CH ;; PRESS C TO EXIT JE MA_EXIT CMP AX, 0AH JGE WAIT_UP CALL MIN_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 MIN_SET PROC CMP CNT_STARTED, 1 JE MS_EXIT LEA BX, VAL_MIN MOV AH, [BX] CMP AH, 10H JE MS_SW MOV AH, [BX+1] CMP AH, 10H JE MS_GW JMP MS_EXIT MS_SW: MOV [BX], AL JMP MS_EXIT MS_GW: MOV [BX+1], AL MS_EXIT: RET MIN_SET ENDP TIMER_RESET PROC MOV CNT_STARTED, 0 CALL CLR_TIME MOV CX, 3 TR_LO: PUSH CX CALL ZERO_BLINK CALL DELAY CALL NUM_DISPLAY_CLS CALL DELAY_LONG POP CX LOOP TR_LO CALL CLR_TIME RET TIMER_RESET ENDP CLR_TIME PROC LEA BX, VAL_MIN MOV AH, 10H MOV [BX], AH MOV [BX+1], AH LEA BX, VAL_SEC MOV AH, 00H MOV [BX], AH MOV [BX+1], AH RET CLR_TIME ENDP ZERO_BLINK PROC PUSH CX MOV CX, 0FFH ZB: PUSH CX MOV AX, 0005H CALL PUT CALL DELAY MOV AX, 0004H CALL PUT CALL DELAY MOV AX, 0003H CALL PUT CALL DELAY MOV AX, 0002H CALL PUT CALL DELAY POP CX LOOP ZB POP CX RET ZERO_BLINK ENDP NUM_DISPLAY PROC CMP CNT_STARTED, 1 JE ND_TIMER ;; INPUT MODE LEA BX, VAL_MIN MOV SI, 0 MOV AH, [BX+SI] MOV AL, 03H CALL PUT CALL DELAY LEA BX, VAL_MIN MOV SI, 0 MOV AH, [BX+SI+1] MOV AL, 02H CALL PUT CALL DELAY RET ND_TIMER: ;; TIMER MODE LEA BX, VAL_MIN MOV SI, 0 MOV AH, [BX+SI] MOV AL, 05H CALL PUT CALL DELAY LEA BX, VAL_MIN MOV SI, 0 MOV AH, [BX+SI+1] MOV AL, 04H CALL PUT CALL DELAY LEA BX, VAL_SEC MOV SI, 0 MOV AH, [BX+SI] MOV AL, 03H CALL PUT CALL DELAY LEA BX, VAL_SEC MOV SI, 0 MOV AH, [BX+SI+1] MOV AL, 02H CALL PUT CALL DELAY RET NUM_DISPLAY ENDP NUM_DISPLAY_CLS PROC MOV CX, 5 ND_CLS: MOV AH, 10H MOV AL, AL CALL PUT LOOP ND_CLS RET NUM_DISPLAY_CLS ENDP ;; DECREASE SECOND & MIN WHEN NECESSARY DEC_SEC PROC CMP CNT_STARTED, 0 ;; NOT STARTED JE DEC_EXIT CMP CNT_PAUSED, 1 ;; PAUSED JE DEC_EXIT LEA BX, VAL_SEC MOV AH, [BX+1] CMP AH, 0 JE DS_JW_S DEC AH MOV [BX+1], AH JMP DEC_EXIT DS_JW_S: MOV AH, 9 MOV [BX+1], AH MOV AH, [BX] CMP AH, 0 JE DS_JW_MG DEC AH MOV [BX], AH JMP DEC_EXIT DS_JW_MG: MOV AH, 5 MOV [BX], AH LEA BX, VAL_MIN MOV AH, [BX+1] CMP AH, 0 JE DS_JW_MS DEC AH MOV [BX+1], AH JMP DEC_EXIT DS_JW_MS: MOV AH, 9 MOV [BX+1], AH MOV AH, [BX] CMP AH, 0 JE DS_FIN DEC AH MOV [BX], AH JMP DEC_EXIT DS_FIN: CALL TIMER_RESET DEC_EXIT: RET DEC_SEC ENDP MIR6 PROC STI INC MIR_COUNTER CMP MIR_COUNTER, 10H JNE MIR6_FIN MOV MIR_COUNTER, 0 CALL DEC_SEC MIR6_FIN: IRET MIR6 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 ;; 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 DELAY_LONG PROC MOV CX, 0FFFFH LOOP $ RET DELAY_LONG ENDP CODE ENDS END START