0%

8086电子时钟折腾小记

大二第二学期的微机原理实验课的期末考核项目之一是做一个以Intel 8086为主控、实现走时和时间(时、分、秒)调节的电子时钟仿真。在前几天就折腾好了,今天来做个记录|・ω・`)。

方案设计

在我的方案中,使用8253的计数通道0作为计时部分,每隔0.8秒,8253发出中断请求信号,中断服务程序执行的自增,由于CPU(时钟频率设定为1MHz)的指令执行时间不可忽略,因此实际显示效果中的自增约为每秒一次,从而实现24小时制的走时。

显示部分则使用3个两位共阴数码管来分别显示,3个数码管的段码控制端均接在8255的PA端,片选端则通过74LS138接入8255;当CPU输出一个数码管段码时,所有(6位)数码管均收到该段码,但只有被片选选中的数码管才会显示该段码对应的数值,CPU每隔一段时间输出一个段码,只要间隔时间足够短,由于视觉暂留现象,就可以看到6位数码管同时显示。

控制部分由走时/暂停开关、'时'设置按键、'分'设置按键、'秒'设置按键组成,分别接入8255的PC0PC1PC2PC3

方案原理

概况

CPU部分

定时器部分

激励源

显示&控制部分

方案源码

;8255的端口地址
AD8255PA EQU 08H
AD8255PB EQU 0AH
AD8255PC EQU 0CH
AD8255CON EQU 0EH

;8253的端口地址
AD82530 EQU 10H
AD8253CON EQU 16H

STACK SEGMENT STACK
DB 200 DUP(0)
STACK ENDS

DATA SEGMENT
LEDS DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH,77H,7CH,39H,5EH,79H,71H ;数码管段码
HOUR DB 0
MINUTE DB 0
SECOND DB 0
DATA ENDS

CODE SEGMENT
ASSUME CS:CODE,DS:DATA

START:

PUSH DS
MOV AX,DATA
MOV DS,AX

;设置中断向量,8253非屏蔽中断初始化
CLI
MOV AX,0
MOV ES,AX
MOV SI,08H
MOV AX,OFFSET TIME_INT
MOV ES:[SI],AX
MOV AX,CS
MOV ES:[SI+2],AX

;初始化8255,端口A和端口B输出,端口C的低四位输入
MOV AL,81H
OUT AD8255CON,AL

;初始化8253,每秒触发一次中断
MOV AL,36H
OUT AD8253CON,AL ;将方式控制字写入控制端口
MOV AX,40000 ;计数初值40000,输入频率50k,定时时长0.8秒
OUT AD82530,AL ;将计数初值的低字节写入计数通道0
MOV AL,AH
OUT AD82530,AL ;将计数初值的高字节写入计数通道0

L:
CALL TIME_CHANGE ;更改时间
CALL DISPLAY_TIME ;显示时间
JMP L

TIME_CHANGE:
PUSH AX
IN AL,AD8255PC ;读取8255的PC端口数据
AND AL,0FH ;高四位清零
CMP AL,06H ;按下按键“秒”
JE ADD_SECOND
CMP AL,0AH ;按下按键“分”
JE ADD_MINUTE
CMP AL,0CH ;按下按键“时”
JE ADD_HOUR
JMP ADD_NULL

ADD_SECOND:
CALL INC_SECOND ;增加“秒”
CALL DELAY_KEY ;按键延时消抖
JMP ADD_NULL

ADD_MINUTE:
CALL INC_MINUTE ;增加“分”
CALL DELAY_KEY ;按键延时消抖
JMP ADD_NULL

ADD_HOUR:
CALL INC_HOUR ;增加“时”
CALL DELAY_KEY ;按键延时消抖

ADD_NULL:
POP AX
RET

INC_SECOND:
PUSH AX
INC SECOND
MOV AL,SECOND
CMP AL,60 ;判断是否等于60
JNE END0
MOV AL,0
MOV SECOND,AL
CALL INC_MINUTE

END0:
POP AX
RET

INC_MINUTE:
PUSH AX
INC MINUTE
MOV AL,MINUTE
CMP AL,60 ;判断是否等于60
JNE END1
MOV AL,0
MOV MINUTE,AL
CALL INC_HOUR

END1:
POP AX
RET

INC_HOUR:
PUSH AX
INC HOUR
MOV AL,HOUR
CMP AL,24 ;判断是否等于24
JNE END2
MOV AL,0
MOV HOUR,AL

END2:
POP AX
RET

WRITE_LEDS: ;写数码管的某一位
MOV BP,SP
PUSH AX
PUSH DX
MOV AX,[BP+4]
OUT AD8255PB,AL
MOV BX,[BP+2]
LEA SI,LEDS
MOV AL,[BX+SI]
OUT AD8255PA,AL
POP DX
POP AX
RET 4

WRITE_TIME: ;写“时”、“分”、“秒”
MOV BP,SP
PUSH AX
PUSH CX
PUSH DX
MOV AX,[BP+2]
MOV DL,10
DIV DL
MOV CL,AH
MOV DX,[BP+4]
PUSH DX
XOR AH,AH
PUSH AX
CALL WRITE_LEDS
CALL DELAY
INC DX
PUSH DX
XOR CH,CH
PUSH CX
CALL WRITE_LEDS
POP DX
POP CX
POP AX
RET 4

DISPLAY_TIME:
PUSH AX
;显示“时”
MOV AX,0
PUSH AX
MOV AL,HOUR
XOR AH,AH
PUSH AX
CALL WRITE_TIME
CALL DELAY
;显示“分”
MOV AX,2
PUSH AX
MOV AL,MINUTE
XOR AH,AH
PUSH AX
CALL WRITE_TIME
CALL DELAY
;显示“秒”
MOV AX,4
PUSH AX
MOV AL,SECOND
XOR AH,AH
PUSH AX
CALL WRITE_TIME
CALL DELAY
POP AX
RET

DELAY:
PUSH BX
PUSH CX
MOV BX,2

DEL0:
MOV CX,100

DEL1:
DEC CX
CMP CX,0
JNE DEL1
DEC BX
CMP BX,0
JNE DEL0
POP CX
POP BX
RET

DELAY_KEY:
PUSH BX
PUSH CX
MOV BX,50

DEL_K0:
MOV CX,300

DEL_K1:
DEC CX
CMP CX,0
JNE DEL_K1
DEC BX
CMP BX,0
JNE DEL_K0
POP CX
POP BX
RET

TIME_INT: ;中断处理函数
CALL INC_SECOND
IRET

CODE ENDS
END START