实验 14 访问 CMOS RAM
编程,以“年/月/日 时:分:秒”的格式,显示当前的日期、时间。
注意:CMOS RAM 中存储着系统的配置信息,除了保存时间信息的单元外,不要向其他的单元中写入内容,否则将引起一些系统错误。
具体代码如下:
assume cs:code
; sysdt 段中 '00/00/00 ' 和 '00:00:00' 的 '00' 部分,是需要写入的数据位置。
; 以 ASCII 码值 0 作为字符串结束符。
sysdt segment
db '20','00/00/00 ','00:00:00',0
sysdt ends
code segment
start: mov ax,sysdt
mov ds,ax
mov si,2 ; ds:si 指向需要写入的首个表示年份的字符地址,即 ds:2
mov al,9 ; 设置年、月、日数据起始参数
mov cx,3 ; 设置 loop s0 循环次数
s0: call rd
add si,2
dec al
loop s0
mov al,4 ; 设置时、分、秒数据起始参数
mov cx,3 ; 设置 loop s1 循环次数
s1: call rd
add si,2
sub al,2
loop s1
; 输出 sysdt 段字符串到屏幕中
mov dh,10 ; 屏幕行
mov dl,10 ; 屏幕列
mov cl,2 ; 字符属性:绿色字符
mov ax,sysdt
mov ds,ax
mov si,0 ; ds:si 指向 sysdt 段字符串首地址
call show_str
mov ax,4c00h
int 21h
; begin rd
; 功能:将 CMOS RAM 中的时间信息写入 sysdt 段字符串中
; 参数:(al) = CMOS RAM 时间信息的单元号
; ds:si 指向需要写入数字字符的 sysdt 段内存单元
; 说明:参数 (al) 为调用 dt 子程序作准备,参数 ds:si 为调用 write 子程序作准备
rd: push ax ; AL 寄存器中存储着要读取的 CMOS RAM 单元号参数,AL 寄存器会在 dat 子程序中被使用而改变其存储的数据,但在主调程序中还需要使用 AL 寄存器存储的参数 —— 自减 1 或自减 2,因此需要在执行 rd 子程序功能代码之前先将其入栈保存。
push cx ; CX 寄存器中存储着主调程序的 loop 循环次数,CX 寄存器在 dat 子程序中会被使用而改变其存储的数据,因此需要在执行 rd 子程序功能代码之前先将其入栈保存。
call dat
call write
pop cx
pop ax
ret
; end rd
; begin dt
; 功能:
; 1. 读取 CMOS RAM 中的时间数据
; 2. 将时间数据的十位数字的数值存储到 AH 寄存器中,个位数字的数值存储到 AL 寄存器中
; 3. 将数字的数值形式转换为字符形式
; 参数:(al) = CMOS RAM 时间信息的单元号
dat: out 70h,al
in al,71h ; 将 CMOS RAM 中的年份数据
mov ah,al ; 年份数据的副本存储到 AH 寄存器中
and al,00001111B ; 截取年份数据的个位码值
mov cl,4 ; 设置移动位值为 4:表示需要逻辑移动 4 位
shr ah,cl ; 逻辑右移 4 位,留存年份数据的十位码值
; 将数字的数值形式转换为字符形式
add ah,30h
add al,30h
ret
; end dat
; begin write
; 功能:写入 sysdt 段空间,以形成字符串形式
; 参数:ds:si 指向需要写入数字字符的 sysdt 段内存单元
write: mov [si],ah ; 将数据的十位数字字符码写入 sysdt 段的相应位置
inc si
mov [si],al ; 将数据的个位数字字符码写入 sysdt 段的相应位置
ret
; end write
; begin show_str
; 功能:通过调用 BIOS 的 int 10h 指令中断例程的 2 号和 9 号子程序来显示字符串。
; 参数:(dh)=行号 (dl)=列号 (cl)=字符属性 ds:si 指向字符串首地址
show_str: push cx ; 由于下面要用到 CX 寄存器,所以需将 CL 寄存器存储的字符属性信息数据入栈
mov bp,sp ; 为下面调用原 CL 寄存器存储的字符属性数据而作的准备,这时 ss:[bp]=(cl)
; 设置 BIOS 的 int 10h 指令中断例程的 2 号子程序参数
; 注意,行、列数据已经作为参数存储在 DX 寄存器中
dis: mov ah,2 ; 设置 BIOS 的 int 10h 指令中断例程子程序为 2 号:设置光标位置
mov bh,0 ; 设置显示缓冲区的第 0 页
int 10h ; 调用 BIOS 的 int 10h 指令以引发其中断,从而调用其中断例程的 2 号子程序
; 设置 BIOS 的 int 10h 指令中断例程的 9 号子程序参数
mov al,[si] ; 将要显示的字符传送到 AL 寄存器
cmp al,0 ; 验证 AL 寄存器所存储的字符 ASCII 码是否为 0 —— 是否到达字符串的结束位置
je showret ; 执行判断字符码
mov ah,9 ; 设置 BIOS 的 int 10h 指令中断例程的子程序为 9 号:在光标位置显示字符
mov bl,[bp] ; 读取字符属性信息到 BL 寄存器
mov cx,1 ; 字符显示的重复次数为 1 次
int 10h ; 调用 BIOS 的 int 10h 指令以引发其中断,从而其中断例程的 9 号子程序
inc si ; 将 ds:[si] 指向要显示字符串的下一个字符
inc dl ; 增加列号,以便让下一个字符显示在屏幕的下一列位置
jmp short dis
showret: pop cx
ret
; end show_str
code ends
end start