; 系统端口定义
PORT_8259_OCW EQU 2000H ; 8259A命令端口
PORT_8259_OCW2 EQU 2002H ; 8259A数据端口
PORT_8253_CTL EQU 4006H ; 8253控制寄存器
PORT_8253_1 EQU 4002H ; 8253计数器1
PORT_8255_A EQU 6000H ; 8255端口A
PORT_8255_B EQU 6002H ; 8255端口B
PORT_8255_C EQU 6004H ; 8255端口C
PORT_8255_CTL EQU 6006H ; 8255控制寄存器
; 数据段
DATA SEGMENT
SECONDS DB 0 ; 当前秒数(0-59)
RUN_FLAG DB 0 ; 运行标志(0=暂停,1=运行)
COUNT_10MS DB 0 ; 10ms计数器(100次=1秒)
DISP_BUFFER DB 2 DUP(0) ; 显示缓冲区[十位, 个位]
; 共阴数码管段码表 (0-9, 带小数点关闭)
SEG_CODES DB 3FH, 06H, 5BH, 4FH, 66H, 6DH, 7DH, 07H, 7FH, 6FH
; 按键状态标志
KEY_START_PRESSED DB 0
KEY_PAUSE_PRESSED DB 0
KEY_RESET_PRESSED DB 0
DATA ENDS
; 代码段
CODE SEGMENT
ASSUME CS:CODE, DS:DATA
; ============== 复位入口点 ==============
ORG 0FFFF0H
JMP FAR PTR START ; 跳转到主程序
; ============== 主程序 ==============
START:
CLI ; 关中断
MOV AX, DATA
MOV DS, AX
; 初始化变量
MOV SECONDS, 0
MOV RUN_FLAG, 0
MOV COUNT_10MS, 0
MOV KEY_START_PRESSED, 0
MOV KEY_PAUSE_PRESSED, 0
MOV KEY_RESET_PRESSED, 0
; 初始化硬件
CALL INIT_8255
CALL INIT_8253
CALL INIT_8259
; 设置中断向量(IR0对应中断类型08H)
MOV AX, 0
MOV ES, AX
MOV DI, 08H*4 ; 中断向量地址 = 08H * 4
MOV AX, OFFSET TIMER_ISR
MOV ES:[DI], AX ; 设置IP
MOV AX, CS
MOV ES:[DI+2], AX ; 设置CS
; 初始显示
CALL UPDATE_DISPLAY
STI ; 开中断
; 主循环
MAIN_LOOP:
CALL DISPLAY ; 刷新显示
CALL CHECK_KEYS ; 检测按键
JMP MAIN_LOOP
; ============== 初始化8255 ==============
INIT_8255 PROC
MOV AL, 10000001B ; 控制字: PA/PB输出, PC输入
OUT PORT_8255_CTL, AL
MOV AL, 0FFH ; 关闭数码管显示
OUT PORT_8255_A, AL
MOV AL, 00H
OUT PORT_8255_B, AL
RET
INIT_8255 ENDP
; ============== 初始化8253 ==============
INIT_8253 PROC
; 计数器1: 方式3, 二进制, 先低后高
MOV AL, 01110110B
OUT PORT_8253_CTL, AL
; 写入计数值10000 (0x2710) -> 1MHz/10000=100Hz
MOV AL, 10H ; 低字节
OUT PORT_8253_1, AL
MOV AL, 27H ; 高字节
OUT PORT_8253_1, AL
RET
INIT_8253 ENDP
; ============== 初始化8259A ==============
INIT_8259 PROC
; ICW1: 边沿触发, 单片, 需要ICW4
MOV AL, 00010011B
OUT PORT_8259_OCW, AL
; ICW2: 中断向量基址08H
MOV AL, 08H
OUT PORT_8259_OCW2, AL
; ICW4: 8086模式, 非缓冲, 全嵌套
MOV AL, 00000001B
OUT PORT_8259_OCW2, AL
; OCW1: 开启IR0中断
MOV AL, 11111110B
OUT PORT_8259_OCW2, AL
RET
INIT_8259 ENDP
; ============== 定时中断服务程序 ==============
TIMER_ISR PROC FAR
PUSH AX
PUSH BX
PUSH DS
MOV AX, DATA
MOV DS, AX
; 更新10ms计数器
INC COUNT_10MS
CMP COUNT_10MS, 100 ; 100次中断=1秒
JB END_ISR
; 重置计数器
MOV COUNT_10MS, 0
; 检查运行标志
CMP RUN_FLAG, 1
JNE END_ISR
; 秒计数器递增
INC SECONDS
CMP SECONDS, 60
JB UPDATE_DISP
MOV SECONDS, 0 ; 满60秒归零
UPDATE_DISP:
CALL UPDATE_DISPLAY
END_ISR:
; 发送EOI命令
MOV AL, 20H
OUT PORT_8259_OCW, AL
POP DS
POP BX
POP AX
IRET
TIMER_ISR ENDP
; ============== 更新显示缓冲区 ==============
UPDATE_DISPLAY PROC
MOV AL, SECONDS
MOV AH, 0
MOV BL, 10
DIV BL ; AL=十位, AH=个位
; 十位段码
LEA BX, SEG_CODES
XLAT ; AL = SEG_CODES[AL]
MOV DISP_BUFFER, AL
; 个位段码
MOV AL, AH
XLAT ; AL = SEG_CODES[AL]
MOV DISP_BUFFER+1, AL
RET
UPDATE_DISPLAY ENDP
; ============== 数码管显示 ==============
DISPLAY PROC
; 关闭所有位选
MOV AL, 00H
OUT PORT_8255_B, AL
; 显示十位
MOV AL, DISP_BUFFER
OUT PORT_8255_A, AL
MOV AL, 01H ; PB0=1(选中十位)
OUT PORT_8255_B, AL
CALL DELAY_500US
; 关闭所有位选
MOV AL, 00H
OUT PORT_8255_B, AL
; 显示个位
MOV AL, DISP_BUFFER+1
OUT PORT_8255_A, AL
MOV AL, 02H ; PB1=1(选中个位)
OUT PORT_8255_B, AL
CALL DELAY_500US
RET
DISPLAY ENDP
; ============== 短延时(500μs) ==============
DELAY_500US PROC
PUSH CX
MOV CX, 150
DL1: LOOP DL1
POP CX
RET
DELAY_500US ENDP
; ============== 按键检测 ==============
CHECK_KEYS PROC
; 读取PC口状态
IN AL, PORT_8255_C
AND AL, 07H ; 只取低3位(PC0-PC2)
NOT AL ; 反转(0=按下)
AND AL, 07H ; 保留低3位
; 检测开始键(PC0)
TEST AL, 01H
JZ START_NOT_PRESSED
; 按键按下
CMP KEY_START_PRESSED, 0
JNE START_ALREADY_PRESSED
MOV KEY_START_PRESSED, 1
MOV RUN_FLAG, 1 ; 开始运行
JMP START_HANDLED
START_NOT_PRESSED:
MOV KEY_START_PRESSED, 0
START_ALREADY_PRESSED:
START_HANDLED:
; 检测暂停键(PC1)
TEST AL, 02H
JZ PAUSE_NOT_PRESSED
CMP KEY_PAUSE_PRESSED, 0
JNE PAUSE_ALREADY_PRESSED
MOV KEY_PAUSE_PRESSED, 1
MOV RUN_FLAG, 0 ; 暂停
JMP PAUSE_HANDLED
PAUSE_NOT_PRESSED:
MOV KEY_PAUSE_PRESSED, 0
PAUSE_ALREADY_PRESSED:
PAUSE_HANDLED:
; 检测复位键(PC2)
TEST AL, 04H
JZ RESET_NOT_PRESSED
CMP KEY_RESET_PRESSED, 0
JNE RESET_ALREADY_PRESSED
MOV KEY_RESET_PRESSED, 1
MOV SECONDS, 0 ; 复位秒数
MOV RUN_FLAG, 0 ; 停止运行
CALL UPDATE_DISPLAY
JMP RESET_HANDLED
RESET_NOT_PRESSED:
MOV KEY_RESET_PRESSED, 0
RESET_ALREADY_PRESSED:
RESET_HANDLED:
RET
CHECK_KEYS ENDP
; ============== 20ms延时(按键消抖) ==============
DELAY_20MS PROC
PUSH CX
MOV CX, 6000
DL2: LOOP DL2
POP CX
RET
DELAY_20MS ENDP
CODE ENDS
END START
上述汇编代码基于8086汇编语言设计了一个硬件系统,用于60s循环计时,使用了8259A,8255,8253,74ls373,74ls138,但是在代码编写部分出了错误,比如出现了段超过64k和一些无效指令操作,请你修改这段汇编代码,并尽量减少造成的硬件连接的变化。
最新发布