【微机原理作业】从0开始设计RTC系统(一)
【微机原理作业】从0开始设计RTC系统(二)(初步构图和代码子模块)
上两篇博客实现了秒表功能,但我们希望钟表还有调整时钟的功能,所以需要外加一个按键调整时钟电路⭐️。
文章目录
效果演示🔥
思路
仿真硬件
8255A :A、B口输出,C口上部输出,下部输入
重置清零按钮按下后,时钟从0开始计时
秒调整按钮按下后,秒数加1,其余类似
其余硬件不变
汇编程序
主程序
LP:
; 主任务
CALL KEY
CALL DISP ; 显示子程序调用
JMP LP ; 循环
按键
KEY PROC
MOV DX, PORTC
IN AL, DX
TEST AL, 8H
JZ NEXTHOU
TEST AL, 4H
JZ NEXTMIN
TEST AL, 2H
JZ NEXTSEC
TEST AL, 1H
JZ RESET
CALL DISP ; 消抖
CALL DISP
CALL DISP
MOV DX, PORTC
IN AL, DX
TEST AL, 8H
JZ NEXTHOU
TEST AL, 4H
JZ NEXTMIN
TEST AL, 2H
JZ NEXTSEC
TEST AL, 1H
JZ RESET
重置清零
RESET:
; 清零
MOV DX, PORTC
IN AL, DX
TEST AL, 1H
JNZ EXITKEY
CALL DISP
CALL DISP
CALL DISP
MOV DX, PORTC
IN AL, DX
TEST AL, 1H
JNZ EXITKEY
MOV HOU, 0
MOV MIN, 0
MOV SEC, 0
CALL DELAY
调整秒
NEXTSEC:
; 秒调整
MOV DX, PORTC
IN AL, DX
TEST AL, 2H
JNZ EXITKEY
CALL DISP
CALL DISP
CALL DISP
MOV DX, PORTC
IN AL, DX
TEST AL, 2H
JNZ EXITKEY
MOV AL, SEC
ADD AL, 1
DAA
CALL DELAY
MOV SEC, AL
CMP SEC, 60H
JB NEXTSEC
MOV SEC, 0
调整分
NEXTMIN:
; 分调整
MOV DX, PORTC
IN AL, DX
TEST AL, 4H
JNZ EXITKEY
CALL DISP
CALL DISP
CALL DISP
MOV DX, PORTC
IN AL, DX
TEST AL, 4H
JNZ EXITKEY
MOV AL, MIN
ADD AL, 1
DAA
CALL DELAY
MOV MIN, AL
CMP MIN, 60H
JB NEXTMIN
MOV MIN, 0
调整时
NEXTHOU:
; 时调整
MOV DX, PORTC
IN AL, DX
TEST AL, 8H
JNZ EXITKEY
CALL DISP
CALL DISP
CALL DISP
MOV DX, PORTC
IN AL, DX
TEST AL, 8H
JNZ EXITKEY
MOV AL, HOU
ADD AL, 1
DAA
CALL DELAY
MOV HOU, AL
CMP HOU, 24H
JB NEXTHOU
MOV HOU, 0
问题
-
仿真报错:invalid internal memory size == NULL(internal memory mode)
解决:将8086中的参数设置第2项 ,设置 intener memory 为10000 -
时钟最小单位不是1秒
解决:修改分频数和延时 -
调时过快
解决:修改延时 -
字符9和8显示不全
上网查:
(1)延时不够,出现鬼影
(2)显示字符之前没有清零
这些方法我都试过了,但没有解决问题。
问题解决
时隔108天,终于在2020.9.29下午的微机课上解决了这个问题!🙋
老师说,可能是因为内存重叠导致部分字符显示不全。
在原理图中点击 8086 CPU,修改 Advanced Properties 中的参数:
Program Loading Segment:0x0800 → 0x0200
BIN Entry Point:0x00000 → 0x02000
终于能正常显示字符啦!🙏🙏🙏🙏🙏
完整proteus原理图🔥
完整代码🔥
以下就是完整代码了:
;************************************************************************
; file: rtc.asm
; author: Xiaoxiao
; date: 20200929
; blog: https://blog.csdn.net/weixin_43470383/category_10041680.html
;************************************************************************
DATA SEGMENT
; 3-8译码器输出对应端口
IO2 EQU 20H ; 8253A
IO4 EQU 40H ; 8255A
TIME0 EQU IO2 ; T0地址
TIME1 EQU IO2 + 2 ; T1地址
TIME_CTR EQU IO2 + 6 ; 8253A控制口地址
PORTA EQU IO4 ; 8255 A口地址
PORTB EQU IO4 + 2 ; 8255 B口地址
PORTC EQU IO4 + 4 ; 8255 C口地址
PORT_CTR EQU IO4 + 6 ; 8255 控制口地址
CNTVAL EQU 1000H ; 计数初值
LED DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH
;0--9 对应段选码,共阴极
HOU DB 00H ; 时
MIN DB 00H ; 分
SEC DB 00H ; 秒
DATA ENDS
STACK SEGMENT
DW 200 DUP(0) ; 这里不用给太多,一两百就够
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STACK
START:
; 数据段设置
MOV AX, DATA
MOV DS, AX
MOV ES, AX
; NMI中断向量初始化
PUSH ES
XOR AX, AX
MOV ES, AX
MOV AL, 02H ; NMI中断类型号为02H
XOR AH, AH
SHL AX, 1
SHL AX, 1
MOV SI, AX
MOV AX, OFFSET NMI_SERVICE
MOV ES: [SI], AX
INC SI
INC SI
MOV BX, CS
MOV ES: [SI], BX
POP ES
; 初始化8253
MOV AL, 00110101B ; T0 读写16位 方式2 BCD计数
MOV DX, TIME_CTR
OUT DX, AL
MOV DX, TIME0
MOV AX, CNTVAL ; 1000分频
OUT DX, AL
MOV AL, AH ; 高字节
OUT DX, AL
MOV AL, 01110111B ; T1 读写16位 方式3 BCD计数
MOV DX, TIME_CTR
OUT DX, AL
MOV DX, TIME1
MOV AX, CNTVAL ; 1000分频
OUT DX, AL
MOV AL, AH ; 高字节
OUT DX, AL
; 初始化8255
MOV AL, 81H ; A、B输出,C上部输出,下部输入
OUT PORT_CTR, AL
LP:
; 主任务
CALL KEY
CALL DISP ; 显示子程序调用
JMP LP ; 循环
NMI_SERVICE:
; 中断服务
PUSH AX
MOV AL, SEC
ADD AL, 1
DAA ; 校正BCD数加法
MOV SEC, AL
CMP SEC, 60H
JB EXIT
MOV SEC, 0
MOV AL, MIN
ADD AL, 1
DAA
MOV MIN, AL
CMP MIN, 60H
JB EXIT
MOV MIN, 0
MOV AL, HOU
ADD AL, 1
DAA
MOV HOU, AL
CMP HOU, 24H
JB EXIT
MOV HOU, 0
EXIT:
POP AX
IRET ; 中断返回
DISP PROC
; 数码管显示子程序
MOV AL, 0FFH ; 不显示
MOV DX, PORTB
OUT DX, AL ; 位选信号接到8255A的PB口
; 秒个位
MOV AL, 0FEH
MOV DX, PORTB
OUT DX, AL ; 位选
MOV BL, SEC ; 存放8位秒数
AND BX, 000FH
MOV SI, BX
MOV AL, LED[SI]
MOV DX, PORTA
OUT DX, AL ; 段选
CALL DELAY
MOV AL, 0FFH ; 为防止重叠,每次显示之前要清零
MOV DX, PORTB
OUT DX, AL
MOV BL, SEC
AND BX, 00F0H
MOV CL, 4
SHR BX, CL
MOV SI, BX
MOV AL, 0FDH ; 秒十位
MOV DX, PORTB
OUT DX, AL
MOV AL, LED[SI] ; 段码
MOV DX, PORTA
OUT DX, AL
CALL DELAY
MOV AL, 0FFH ; 不显示
MOV DX, PORTB
OUT DX, AL
MOV AL, 40H ; "-"段码
MOV DX, PORTA
OUT DX, AL
MOV AL, 0FBH ; "-"位
MOV DX, PORTB
OUT DX, AL
CALL DELAY
MOV AL, 0FFH ; 不显示
MOV DX, PORTB
OUT DX, AL
MOV BL, MIN
AND BX, 000FH
MOV SI, BX
MOV AL, LED[SI] ; 段码
MOV DX, PORTA
OUT DX, AL
MOV AL, 0F7H ; 分个位
MOV DX, PORTB
OUT DX, AL
CALL DELAY
MOV AL, 0FFH ; 不显示
MOV DX, PORTB
OUT DX, AL
MOV BL, MIN
AND BX, 00F0H
MOV CL, 4
SHR BX, CL
MOV SI, BX
MOV AL, LED[SI] ; 段码
MOV DX, PORTA
OUT DX, AL
MOV AL, 0EFH ; 分十位
MOV DX, PORTB
OUT DX, AL
CALL DELAY
MOV AL, 0FFH ; 不显示
MOV DX, PORTB
OUT DX, AL
MOV AL, 40H ; 段码“-”
AND DX, PORTA
OUT DX, AL
MOV AL, 0DFH ; "-"位
MOV DX, PORTB
OUT DX, AL
CALL DELAY
MOV AL, 0FFH ; 不显示
MOV DX, PORTB
OUT DX, AL
MOV BL, HOU
AND BX, 000FH
MOV SI, BX
MOV AL, LED[SI] ; 段码
MOV DX, PORTA
OUT DX, AL
MOV AL, 0BFH ; 时个位
MOV DX, PORTB
OUT DX, AL
CALL DELAY
MOV AL, 0FFH ; 不显示
MOV DX, PORTB
OUT DX, AL
MOV BL, HOU
AND BX, 00F0H
MOV CL, 4
SHR BX, CL
MOV SI, BX
MOV AL, LED[SI] ; 段码
MOV DX, PORTA
OUT DX, AL
MOV AL, 07FH ; 时十位
MOV DX, PORTB
OUT DX, AL
CALL DELAY
RET ; 子程序返回
DISP ENDP
KEY PROC
MOV DX, PORTC
IN AL, DX
TEST AL, 8H
JZ NEXTHOU
TEST AL, 4H
JZ NEXTMIN
TEST AL, 2H
JZ NEXTSEC
TEST AL, 1H
JZ RESET
CALL DISP ; 消抖
CALL DISP
CALL DISP
MOV DX, PORTC
IN AL, DX
TEST AL, 8H
JZ NEXTHOU
TEST AL, 4H
JZ NEXTMIN
TEST AL, 2H
JZ NEXTSEC
TEST AL, 1H
JZ RESET
NEXTHOU:
; 时调整
MOV DX, PORTC
IN AL, DX
TEST AL, 8H
JNZ EXITKEY
CALL DISP
CALL DISP
CALL DISP
MOV DX, PORTC
IN AL, DX
TEST AL, 8H
JNZ EXITKEY
MOV AL, HOU
ADD AL, 1
DAA
CALL DELAY
MOV HOU, AL
CMP HOU, 24H
JB NEXTHOU
MOV HOU, 0
NEXTMIN:
; 分调整
MOV DX, PORTC
IN AL, DX
TEST AL, 4H
JNZ EXITKEY
CALL DISP
CALL DISP
CALL DISP
MOV DX, PORTC
IN AL, DX
TEST AL, 4H
JNZ EXITKEY
MOV AL, MIN
ADD AL, 1
DAA
CALL DELAY
MOV MIN, AL
CMP MIN, 60H
JB NEXTMIN
MOV MIN, 0
NEXTSEC:
; 秒调整
MOV DX, PORTC
IN AL, DX
TEST AL, 2H
JNZ EXITKEY
CALL DISP
CALL DISP
CALL DISP
MOV DX, PORTC
IN AL, DX
TEST AL, 2H
JNZ EXITKEY
MOV AL, SEC
ADD AL, 1
DAA
CALL DELAY
MOV SEC, AL
CMP SEC, 60H
JB NEXTSEC
MOV SEC, 0
RESET:
; 清零
MOV DX, PORTC
IN AL, DX
TEST AL, 1H
JNZ EXITKEY
CALL DISP
CALL DISP
CALL DISP
MOV DX, PORTC
IN AL, DX
TEST AL, 1H
JNZ EXITKEY
MOV HOU, 0
MOV MIN, 0
MOV SEC, 0
CALL DELAY
EXITKEY:
RET
KEY ENDP
DELAY PROC
; 延时子程序
PUSH BX
PUSH CX
MOV BX, 1
LP1: MOV CX, 1000
LP2: LOOP LP2
DEC BX
JNZ LP1
POP CX
POP BX
RET
DELAY ENDP
CODE ENDS
END START
效果演示🔥
原理图和程序文件下载🔥
下载地址1
下载地址2
(资源能正常使用的!正常运行不会有报错!但如果没有proteus或者不会用proteus进行仿真的话是没法用的哦!!!遇到问题建议多检查原理图)
使用方法可以参考:如何用Proteus仿真8086
源码在本博客已经给出,如果仍然无法实现,可以检查一下原理图,看看有没有问题
等等,还没完…
老师说系统还可以优化,比如用 8259A 管理中断,间隔1s产生中断,按键调节时间产生中断。
反馈
有朋友说代码编译后显示没有堆栈段,不知道是不是编译软件的问题,我用 emu8086 v4.08 编译后是可以正常运行的,如果出现上述情况,可以考虑将 STACK SEGMENT 改为 STACKSG SEGMENT STACK.