我正在编写一个汇编程序来获取系统时间和日期,将其转换为 ASCII,并将其显示在显示器上。我无法让它正确显示,也找不到出错的地方。这是一项作业,如果可能的话,我宁愿有解释而不仅仅是解决方案。 这是我的代码:
TITLE GETDTTM
PAGE 60, 132
; This program retrieve the system date and time,
; converts it to ASCII, and displays it to the screen
; Define constants
;
CR EQU 0DH ;define carriage return
LF EQU 0AH ;define line feed
EOM EQU '$' ;define end of message marker
NULL EQU 00H ;define NULL byte
;
; Define variables
;
JMP START
PROMPT DB CR, LF, "The current time is: ",EOM
PROMPT2 DB CR, LF, "The date is: ",EOM
TIME DB "00:00:00", CR, LF, EOM
DATE DB "00/00/0000", CR, LF, EOM
;
; Program code
;
START:
CALL GET_TIME ;call function to get system time
CALL GET_DATE ;call function to get system date
LEA DX, PROMPT ;print time prompt to screen
MOV AH, 09H
INT 21H
LEA DX, TIME ;print time
MOV AH, 09H
INT 21H
LEA DX, PROMPT2 ;print date prompt to screen
MOV AH, 09H
INT 21H
LEA DX, DATE ;print date
MOV AH, 09H
INT 21H
CVT_TIME: ;converts the time to ASCII
CALL CVT_HR
CALL CVT_MIN
CALL CVT_SEC
RET
CVT_HR:
MOV BH, CH ;copy contents of hours to BH
SHR CH,4 ;convert high char to low order bits
ADD CH, 30H ;add 30H to convert to ASCII
MOV [TIME], CH ;save it
AND BH, 0FH ;isolate lower 4 bits
ADD BH, 30H ;convert to ASCII
MOV [TIME+1], BH ;save it
RET
CVT_MIN:
MOV BH, CL ;copy contents of minutes to BH
SHR CL, 4 ;convert high char to low order bits
ADD CL, 30H ;add 30H to convert to ASCII
MOV [TIME+3], CL ;save it
AND BH, 0FH ;isolate lower 4 bits
ADD BH, 30H ; convert to ASCII
MOV[TIME+4], BH ;save it
CVT_SEC:
MOV BH, DH ;copy contents of seconds to BH
SHR DH, 4 ;convert high char to low order bits
ADD DH, 30H ;add 30H to convert to ASCII
MOV [TIME+6], DH ;save it
AND BH, 0FH ;isolate lower 4 bits
ADD BH, 30H ;convert to ASCII
MOV[TIME+7], BH ;save it
GET_DATE: ;get date from the system
MOV AH, 04H ;BIOS function to read date
INT 1AH ;call to BIOS, run 04H
CALL CVT_DATE
RET
;CH = Century
;CL = Year
;DH = Month
;DL = Day
;CF = 0 if clock is running, otherwise 1
CVT_DATE:
CALL CVT_MO
CALL CVT_DAY
CALL CVT_YR
CALL CVT_CT
RET
CVT_MO: ;convert the month to ASCII
MOV BH, DH ;copy month to BH
SHR BH, 4 ;convert high char to low order bits
ADD BH, 30H ;add 30H to convert to ASCII
MOV [DATE], BH ;save in DATE string
MOV BH, DH ;copy month to BH
AND BH, 0FH ;isolate lower 4 bits
ADD BH, 30H ;convert lower bits to ASCII
MOV [DATE+1], BH;save in DATE string
RET
CVT_DAY: ;convert the day to ASCII
MOV BH, DL ;copy days to BH
SHR BH, 4 ;convert high char to low order bits
ADD BH, 30H ;add 30H to convert to ASCII
MOV [DATE+3], BH ;save in DATE string
MOV BH, DL ;copy days to BH
AND BH, 0FH ;isolate lower 4 bits
ADD BH, 30H ;convert lower bits to ASCII
MOV [DATE+4], BH;save in DATE string
RET
CVT_YR: ;convert the year to ASCII
MOV BH, CL ;copy year to BH
SHR BH, 4 ;convert high char to low order bits
ADD BH, 30H ;convert to ASCII
MOV [DATE+8], BH ;save it
MOV BH, CL ;copy year to BH
AND BH, 0FH ;isolate low order bits
ADD BH, 30H ;convert to ASCII
MOV [DATE+9], BH ;save in DATE string
RET
CVT_CT: ;convert the century to ASCII
MOV BH, CH ;copy century to BH
SHR BH, 4 ;convert high char to low order bits
ADD BH, 30H ;convert to ASCII
MOV [DATE+6], BH ;save it
MOV BH, CH ;copy century to BH
AND BH, 0FH ;isolate low order bits
ADD BH, 30H ;convert to ASCII
MOV [DATE+7], BH ;save it
RET
;
;Program End
;
End
这是我在 2015 年 2 月 19 日上午 9:11 运行它时得到的结果:
The current time is: 09:00:00
The date is: 02/09/0005
我尝试添加很多关于我的意图的注释,以便您可以了解我正在尝试做什么,并且更容易看出是否存在某种逻辑错误。我认为从输出中可以很清楚地看出,我错过了将分钟和秒放入 TIME 的过程,并且对如何解决这个问题有一些想法,但是中午之后,我遇到了一些奇怪的时间,并且我对发生的事情感到困惑我的约会。非常感谢任何帮助。
编辑:通过将其分开并实际处理分钟和秒来工作......哎呀。现在我的输出如下:
2015 年 2 月 19 日上午 9:23 运行
The current time is: 09:23:02
The date is: 02/09/0005
EDIT2:越来越近了!感谢 [DATE] 捕获 - 我修复了该问题并获得了正确的月份和日期值,并且更接近年份值。发现我移动得还不够远,因为年份是 4 个字符长 - 16 位,而不是 8 位! - 所以我不能只用 SHR 4 位得到整个事情!我的输出现在看起来像:
The current time is: 09:43:02
The date is: 02/19/0015
编辑 3:添加了 CVT_CT 将世纪转换为 ASCII 并将其添加到 [DATE] 字符串,但仍然得到相同的输出...
The current time is: 10:06:02
The date is: 02/19/0015
编辑 4:我忘记添加对我的新函数的调用...哇。现在工作了!!!谢谢大家的帮助!
The current time is: 10:09:02
The date is: 02/19/2015
附带问题:知道为什么秒总是 02 吗?
最佳答案
所有这些用于将 BCD 转换为字符的单独(但非常)函数都有些困惑,并且几乎肯定会弄乱一些小事情,例如当您可能不使用寄存器时忘记保留寄存器。稍后在其中添加值。
如果您有兴趣避免这种情况,请研究 DRY(不要重复自己)原则(而不是 WET(将所有内容写两次)。 Wikipedia page for DRY 是一个好的开始.
<小时/>如果您花一些时间思考哪些内容可以移至通用代码(即重构),您最终需要担心的代码就会少得多,因此出现错误的机会也会少得多潜入。
您的情况的主要示例是采用每个 BCD 值并从中创建两个字符的代码。这消耗了大约四十行实际代码(这只是日期位,我假设如果您显示的话,当时还会有另外三十多行)。
如果您查看下面的代码,您会发现我已将其重构为 put_bcd2
,总共有十三行代码 - 即使您将其增加到二十七行,因为调用它所需的额外行数,这仍然是一个巨大的减少。这极大地简化了执行转换的代码和使用它的代码。
; Main program.
call get_date ; get date/time into string.
call get_time
lea dx, output ; then output the string.
mov ah, 09h
int 21h
mov ax, 4c00h ; exit program.
int 21h
; Variables.
output:
db "The current date is: "
date:
db "00/00/0000", 0dh, 0ah
db "The current time is: "
time:
db "00:00:00", 0dh, 0ah, '$'
; Subroutines.
; Gets the date and inlines it into the output.
get_date:
mov ah, 04h ; get date from bios.
int 1ah
mov bx, offset date ; do day.
mov al, dl
call put_bcd2
inc bx ; do month.
mov al, dh
call put_bcd2
inc bx ; do year.
mov al, ch
call put_bcd2
mov al, cl
call put_bcd2
ret
; Gets the time and inlines it into the output.
get_time:
mov ah, 02h ; get time from bios.
int 1ah
mov bx, offset time ; do hour.
mov al, ch
call put_bcd2
inc bx ; do minute.
mov al, cl
call put_bcd2
inc bx ; do second.
mov al, dh
call put_bcd2
ret
; Places two-digit BCD value (in al) as two characters to [bx].
; bx is advanced by two, ax is destroyed.
put_bcd2:
push ax ; temporary save for low nybble.
shr ax, 4 ; get high nybble as digit.
and ax, 0fh
add ax, '0'
mov [bx], al ; store that to string.
inc bx
pop ax ; recover low nybble.
and ax, 0fh ; make it digit and store.
add ax, '0'
mov [bx], al
inc bx ; leave bx pointing at next char.
ret
关于datetime - 程序集 A86 - 获取并显示时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28609924/