; 电子秒表程序 - MASM实现
; 功能: 显示秒和毫秒(1-60秒),支持开始/暂停/复位/退出
.MODEL SMALL
.STACK 100h
.DATA
; 时间变量
start_time DW 0, 0 ; 开始时间的时钟计数(高位:低位)
current_time DW 0, 0 ; 当前时间的时钟计数
paused_duration DW 0, 0 ; 暂停期间的时间累计
paused DB 0 ; 暂停状态(0=运行,1=暂停)
; 显示变量
seconds DW 0 ; 秒数
milliseconds DW 0 ; 毫秒数
time_string DB '00:000', '$' ; 时间显示字符串
; 提示信息
initial_msg DB 'Electronic Stopwatch (MASM)', 0Dh, 0Ah
DB 'Press:', 0Dh, 0Ah
DB 'S - Start/Pause', 0Dh, 0Ah
DB 'R - Reset', 0Dh, 0Ah
DB 'Q - Quit', 0Dh, 0Ah, '$'
running_msg DB 'Running...', 0Dh, 0Ah, '$'
paused_msg DB 'Paused. Press S to continue.', 0Dh, 0Ah, '$'
.CODE
MAIN PROC
MOV AX, @DATA
MOV DS, AX
; 初始化显示
CALL init_proc
; 主循环
main_loop:
; 检查键盘输入
CALL check_keyboard
; 如果暂停则跳过时间更新
CMP paused, 1
JE main_loop
; 获取当前时间
MOV AH, 00h
INT 1Ah
MOV current_time[0], DX
MOV current_time[2], CX
; 计算时间差
CALL calculate_time
; 更新显示
CALL update_display
; 延迟以避免闪烁
MOV CX, 01h
MOV DX, 0FFFFh
MOV AH, 86h
INT 15h
JMP main_loop
; 退出程序
exit_program:
MOV AX, 4C00h
INT 21h
MAIN ENDP
; 初始化过程
init_proc PROC
; 清屏
MOV AX, 0600h
MOV BH, 07h
MOV CX, 0000h
MOV DX, 184Fh
INT 10h
; 设置光标位置(显示提示信息)
MOV AH, 02h
MOV BH, 00h
MOV DH, 10 ; 行
MOV DL, 25 ; 列
INT 10h
; 显示初始信息
LEA DX, initial_msg
MOV AH, 09h
INT 21h
; 设置光标位置(显示时间)
MOV AH, 02h
MOV BH, 00h
MOV DH, 12 ; 行
MOV DL, 35 ; 列
INT 10h
; 显示初始时间
MOV seconds, 0
MOV milliseconds, 0
CALL update_display
RET
init_proc ENDP
; 检查键盘输入
check_keyboard PROC
MOV AH, 01h ; 检查键盘状态
INT 16h
JZ no_key ; 无按键则返回
MOV AH, 00h ; 读取按键
INT 16h
CMP AL, 'S' ; 暂停/继续
JE toggle_pause
CMP AL, 's'
JE toggle_pause
CMP AL, 'R' ; 复位
JE reset_timer
CMP AL, 'r'
JE reset_timer
CMP AL, 'Q' ; 退出
JE exit_program
CMP AL, 'q'
JE exit_program
no_key:
RET
toggle_pause:
CMP paused, 1
JE unpause
; 暂停计时
MOV paused, 1
; 记录暂停开始时间
MOV AH, 00h
INT 1Ah
MOV paused_duration[0], DX
MOV paused_duration[2], CX
; 显示暂停信息
MOV AH, 02h
MOV BH, 00h
MOV DH, 14 ; 行
MOV DL, 25 ; 列
INT 10h
LEA DX, paused_msg
MOV AH, 09h
INT 21h
RET
unpause:
; 继续计时
MOV paused, 0
; 计算暂停持续时间并累加到paused_duration
MOV AH, 00h
INT 1Ah
SUB DX, paused_duration[0]
SBB CX, paused_duration[2]
ADD paused_duration[0], DX
ADC paused_duration[2], CX
; 清除暂停信息
MOV AX, 0600h
MOV BH, 07h
MOV CX, 0E00h
MOV DX, 0E4Fh
INT 10h
RET
reset_timer:
; 复位计时器
MOV seconds, 0
MOV milliseconds, 0
; 重置开始时间
MOV AH, 00h
INT 1Ah
MOV start_time[0], DX
MOV start_time[2], CX
; 重置暂停持续时间
MOV paused_duration[0], 0
MOV paused_duration[2], 0
; 更新显示
CALL update_display
RET
exit_program:
; 退出程序(通过主程序中的跳转实现)
RET
check_keyboard ENDP
; 计算时间差
calculate_time PROC
; 计算当前时间与开始时间的差值
MOV AX, current_time[0]
SUB AX, start_time[0]
MOV DX, current_time[2]
SBB DX, start_time[2]
; 减去暂停期间的时间
SUB AX, paused_duration[0]
SBB DX, paused_duration[2]
; 转换为秒和毫秒
; 时钟计数每秒约18.2次(每个计数约55ms)
; 计算秒数 (DX:AX / 18.2)
; 近似计算: 18.2 ≈ 182/10
; 所以 count / 18.2 ≈ count * 10 / 182
; 保存原始计数
PUSH DX
PUSH AX
; 计算 count * 10
MOV BX, 10
MUL BX ; AX = low * 10
MOV CX, DX ; 保存高位结果
MOV DX, AX ; DX = low * 10
POP AX ; 恢复原始AX
POP BX ; 原始DX在BX中
PUSH DX ; 保存低位结果
MOV AX, BX ; AX = 原始DX
MOV BX, 10
MUL BX ; AX = high * 10
POP DX ; 恢复低位结果
ADD DX, AX ; DX:AX = count * 10
; 现在除以182得到秒数
MOV BX, 182
DIV BX ; AX = 秒数, DX = 余数
; 确保不超过60秒
CMP AX, 60
JLE store_seconds
MOV AX, 60
store_seconds:
MOV seconds, AX
; 计算毫秒数: 余数 * 1000 / 182
MOV AX, DX ; 余数
MOV BX, 1000
MUL BX ; DX:AX = 余数 * 1000
MOV BX, 182
DIV BX ; AX = 毫秒数
MOV milliseconds, AX
RET
calculate_time ENDP
; 更新显示
update_display PROC
; 转换秒数为ASCII
MOV AX, seconds
MOV BX, 10
XOR DX, DX
DIV BX ; AX = 十位, DX = 个位
ADD AL, '0'
MOV time_string[0], AL
ADD DL, '0'
MOV time_string[1], DL
; 转换毫秒数为ASCII
MOV AX, milliseconds
MOV BX, 100
XOR DX, DX
DIV BX ; AX = 百位, DX = 余数
ADD AL, '0'
MOV time_string[3], AL
MOV AX, DX
MOV BX, 10
XOR DX, DX
DIV BX ; AX = 十位, DX = 个位
ADD AL, '0'
MOV time_string[4], AL
ADD DL, '0'
MOV time_string[5], DL
; 设置光标位置
MOV AH, 02h
MOV BH, 00h
MOV DH, 12 ; 行
MOV DL, 35 ; 列
INT 10h
; 显示时间字符串
LEA DX, time_string
MOV AH, 09h
INT 21h
RET
update_display ENDP
END MAIN 我在按键识别上有问题(识别不出来),可能是 INT 16h的问题,能否帮我单独修改这里