思路
仿真硬件
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
效果演示🔥
演示视频
原理图和程序文件下载🔥
下载地址
(资源能正常使用的!正常运行不会有报错!但如果没有proteus或者不会用proteus进行仿真的话是没法用的哦!!!遇到问题建议多检查原理图)
使用方法可以参考:如何用Proteus仿真8086
源码在本博客已经给出,如果仍然无法实现,可以检查一下原理图,看看有没有问题
等等,还没完…
老师说系统还可以优化,比如用 8259A 管理中断,间隔1s产生中断,按键调节时间产生中断。
反馈
有朋友说代码编译后显示没有堆栈段,不知道是不是编译软件的问题,我用 emu8086 v4.08 编译后是可以正常运行的,如果出现上述情况,可以考虑将 STACK SEGMENT 改为 STACKSG SEGMENT STACK.