汇编语言课程设计2完整代码及详细解析、动态显示时间

汇编语言课程设计2完整代码及详细解析

建议先自己思考问题的答案,不懂则返回看书
思考点:
程序逻辑部分:
1、这也是程序,需要首先在MSdos下运行。但是运行后并不执行此程序。就是说该程序的执行时机是进入MSDos操作系统之前,进行四个功能的选择。进入MSDos操作系统之后,就不在执行此程序了。所以在MSDos下只是将该程序安装到磁盘上
2、重启虚拟机后,在进入操作系统前就需要执行本程序,则它不能保存在内存中,需要保存在磁盘上,这样才能进入操作系统之前,将该程序调入内存然后运行。
函数部分:
3、功能2是进入操作系统。则可以从硬盘C 启动。
4、功能3若要动态显示时间,则参考 实验15的思路方法,重写int 9中断例程,只是该中断例程不能安装到0:200处,需要仔细思考。此外还存在键盘缓冲区满的问题[当按了若干次 F1 后,若听到蜂鸣声,则是缓冲区已满,],此时不再响应键盘中断,类似于死机的现象。所以需要利用 int 16h 清空缓冲区。
5、功能3若不使用int 9中断,则可能会产生按一次F1按键,颜色变化多次,因为CPU执行速度非常快,在键盘缓冲区还未清除的时候,CPU已经读了多次,所以会造成此现象。所以用int 9中断,会避免产生此种情况。
6、功能4考察字符串的处理,参考 第十七章字符串的输入。之前已经做过处理,此处不再赘述。

代码参考如下:[关键点处已做详细注释]

assume cs:anzhuang
anzhuang segment
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx安装程序开始
anzhuang_start:
	mov ax,init_yindaoprogram	;将引导程序 [init] 放置在1扇区
	mov es,ax
	mov bx,0

	mov al,1
	mov ch,0
	mov cl,1
	mov dl,0
	mov dh,0

	mov ah,3
	int 13h


	mov ax,main	;将主程序 [main] 放置在2-18扇区
	mov es,ax
	mov bx,0

	mov al,17
	mov cl,2
	mov ch,0
	mov dl,0
	mov dh,0

	mov ah,3
	int 13h

	mov ax,4c00h
	int 21h
anzhuang ends
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx安装程序结束


;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx引导程序
assume cs:init_yindaoprogram	;初始化(引导)程序段将主程序从磁盘复制到内存中
init_yindaoprogram segment
init_start:
	mov ax,2000h	;将实现功能的主程序从磁盘复制到2000:0开始的内存中
	mov es,ax
	mov bx,0

	mov al,17
	mov ch,0
	mov cl,2
	mov dl,0
	mov dh,0

	mov ah,2
	int 13h

	mov ax,2000h	;CS先入栈
	push ax
	mov ax,0
	push ax
	retf		;跳转到2000:0处,执行主程序
init_yindaoprogram ends
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx引导程序
结束

;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx实现四个功能的主程序开始
;主程序——main,实现四个功能
assume cs:main
main segment
menu:
	jmp display_menu
	menu_list_offset dw offset menu0,offset menu1,offset menu2,offset menu3
	menu0 db "  1) reset pc",0
	menu1 db "  2) start system",0
	menu2 db "  3) clock",0
	menu3 db "  4) set clock",0
	menu_function dw reset_pc,start_system,show_clock,set_clock
	
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx显示四个功能的菜单开始
display_menu:		;进入主程序,先显示功能列表
	mov dh,5		;dh 行
	mov dl,30		;dl 列
	mov bp,0
	mov ax,cs
	mov ds,ax
	mov cx,4
  display_menu_s:
	push cx
	mov si,menu_list_offset[bp]	;ds:si指向要显示的字符串的首地址
	mov cl,02h	;color
	call display_showstr
	add bp,2
	add dh,2
	pop cx
	loop display_menu_s

wait_input:		;显示功能列表完毕后,等待输入功能号
	mov ah,0
	int 16h
	sub al,30h		;读取到的al中存放的是ASCII,得到1,2,3,4
	dec al		;1,2,3,4对应的功能号是0,1,2,3,所以需要再减一得到0,1,2,3
	mov ah,0
	
	cmp al,0
	jb invalue_reinput
	cmp al,3
	ja invalue_reinput
	add ax,ax
	mov bx,ax
	call word ptr menu_function[bx]
 invalue_reinput:
	jmp wait_input
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx显示四个功能的菜单结束

;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1号功能开始
;功能1,reset pc
reset_pc:
	mov ax,0FFFFH
	push ax
	mov ax,0
	push ax
	retf
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1号功能结束

;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx2号功能开始
;功能2,start system
start_system:
	call clear_screen

	mov ax,0
	mov es,ax
	mov bx,7c00h		;es:bx指向读位置

	mov al,1
	mov dh,0
	mov ch,0
	mov cl,1
	mov dl,80h		;硬盘C,001

	mov ah,2
	int 13h

	mov ax,0
	push ax
	mov ax,7c00h
	push ax
	retf
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx2号功能结束

;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx3号功能开始
;功能3,clock
show_clock:
	call clear_screen
	jmp short clock_start
clockdata:
	clocklist dw offset clock1,offset clock2,offset clock3
	clockcolor db 02h
	clock1 db '00/00/00 00:00:00',0		;采用填表的方法,先计算存储,再输出
	clock2 db 'ESC :  return menu',0
	clock3 db 'F1 : change color',0
	clocktable db 9,8,7,4,2,0
	clockint9address dw 0,0			;保存int 9 源地址的段
	clock_ESC db 0					;检测是否是ESC按键的标志

clock_start:
	mov ax,0
	mov ds,ax
	mov bx,offset clockint9address

	push ds:[9h*4]	;保存int 9 源地址
	mov ax,cs
	mov ds,ax
	pop ds:[bx]

	mov ax,0
	mov ds,ax
	push ds:[9h*4+2]
	mov ax,cs
	mov ds,ax
	pop ds:[bx+2]
	
	mov ax,0
	mov ds,ax
	cli		;设置新的int 9入口地址
	mov word ptr ds:[9h*4],offset int9
	mov word ptr ds:[9h*4+2],cs
	sti

 waitint9:
	call get_clock_s0
	mov ax,cs
	mov ds,ax
	mov bx,offset clock_ESC
	mov al,ds:[bx]
    cmp al,01H
    je clockend
	jmp waitint9

  clockend:
	mov bx,offset clockint9address
    cli
	mov ax,cs
	mov ds,ax
    push ds:[bx]
	mov ax,0
	mov ds,ax
    pop ds:[9*4]

	mov ax,cs
	mov ds,ax
    push ds:[bx+2]
	mov ax,0
	mov ds,ax
    pop ds:[9*4+2]
    sti
	mov clock_ESC[0],0
	call clear_screen
	jmp display_menu

int9:
	push ax
	push bx
	push ds

	in al,60h

	pushf
	pushf
	pop bx
	and bh,11111100b
	push bx
	popf

	mov bx,cs
	mov ds,bx
	mov bx,offset clockint9address
	call dword ptr ds:[bx]

	cmp al,01h	;	ESC
	jne maybeF1
	mov bx,cs
	mov ds,bx
	mov bx,offset clock_ESC
	mov ds:[bx],al

	pop ds
	pop bx
	pop ax
	iret

 maybeF1:
	cmp al,3Bh
	jne int9ret
	mov ah,0h
	int 16h		;缓冲区满,会产生溢出,用int 16h清除缓冲区,放置溢出
	inc clockcolor
 int9ret:
	pop ds
	pop bx
	pop ax
	iret


color_change:
    get_clock_s0:
	mov si,0		;clock1
	mov di,0		;clocktable
	mov cx,6
    get_clock_s:
	mov al,clocktable[di]

	out 70h,al
	in al,71h
	mov ah,al
	shr ah,1
	shr ah,1
	shr ah,1
	shr ah,1
	and al,00001111b
	add ah,30h
	add al,30h

	mov byte ptr clock1[si],ah	;先将时间存储,再最后将三个clock一起显示
	mov byte ptr clock1[si+1],al

	add si,3
	inc di
    loop get_clock_s
					;得到时间后,显示时间及ESC,F1
clock_print:
	mov dh,6		;行
	mov dl,30		;列
	mov bp,0
	mov ax,cs
	mov ds,ax		;
	mov cx,3
     clock_print_s:
	push cx
	mov si,clocklist[bp]		;ds:si指向要显示的字符串的起始地址
	mov cl,clockcolor[0]		;颜色
	call display_showstr
	add bp,2
	add dh,2
	pop cx
      loop clock_print_s
	ret
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx3号功能结束

;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx4号功能开始
;功能4,set clock
set_clock:
	jmp short setclock
	setclockdata db 'input time like "yy/mm/dd hh:mm:ss"',0
	setsuccess db 'successful! Press any key return...',0
	setclock_input db 17 dup ( ),0
 setclock:
	call clear_screen
	mov dh,6
	mov dl,20
	mov cl,02h
	mov ax,cs
	mov ds,ax
	mov si,offset setclockdata
	call display_showstr		;先输出提示信息,输入的格式

	mov si,offset setclock_input
	call getstr			;读取输入的内容,ds:si指向输入的时间
	
	call settime		;设置时间到CMOS RAM中
	
	mov dh,10
	mov dl,20
	mov cl,02h
	mov ax,cs
	mov ds,ax
	mov si,offset setsuccess	;提示设置成功的信息,然后按任意键返回
	call display_showstr
	
	mov ah,0
	int 16h			;仅接受,不做处理

	call clear_screen
	jmp display_menu



getstr:	push ax
	push si
	push ds
	push dx
	push bx
getstrs:	mov ah,0
	int 16h

	cmp al,20h
	jb nochar		;ASCII小于零,则不是字符
	mov ah,0
	call charstack
	
	mov dh,8
	mov dl,25		;添加行列值
	mov ah,2
	call charstack

	jmp getstrs

 nochar:	
	cmp ah,0eh	;退格键扫描码
	je backspace
	cmp ah,1ch	;回车键扫描码
	je enter
	jmp getstrs

 backspace:
	mov ah,1
	call charstack	;字符出栈
	mov ah,2
	call charstack	;显示栈中字符
	jmp getstrs

 enter:
	mov al,0
	mov ah,0
	call charstack	;0入栈
	mov ah,2
	call charstack
	pop bx
	pop dx
	pop ds
	pop si
	pop ax
	ret


charstack:
	jmp short charstart
	table dw charpush,charpop,charshow
	top dw 0
charstart:
	push bx
	push dx
	push di
	push es
	push si

	cmp ah,2
	ja sret
	mov bl,ah
	mov bh,0
	add bx,bx
	jmp word ptr table[bx]

charpush:
	mov bx,top
	mov [si][bx],al
	inc top
	jmp sret
charpop:
	cmp top,0
	je sret
	dec top
	mov bx,top
	mov al,[si][bx]
	jmp sret
charshow:
	mov bx,0b800h
	mov es,bx
	mov al,160
	mov ah,0
	mul dh
	mov di,ax
	add dl,dl
	mov dh,0
	add di,dx
	mov bx,0
 charshow_s:
	cmp bx,top
	jne noempty
	mov byte ptr es:[di],' '
	mov byte ptr es:[di+1],02h
	jmp sret
 noempty:
	mov al,[si][bx]
	mov es:[di],al
	mov byte ptr es:[di+2],' '
	mov byte ptr es:[di+1],02h
	inc bx
	add di,2
	jmp charshow_s
sret:	
	pop si
	pop es
	pop di
	pop dx
	pop bx
	ret


settime:
	push ax
	push bx
	push cx
	push dx
	push ds
	push si

	jmp short settimeRAM
	settable db 9,8,7,4,2,0
 settimeRAM:
	mov si,offset setclock_input
	mov bx,0
	mov cx,6
 settimeRAM_s:
	mov dh,ds:[si]        ;取值
	inc si
	mov dl,ds:[si]
	add si,2

	mov al,30h        ;设置CMOS RAM    
	sub dl,al
	sub dh,al
	shl dh,1
	shl dh,1	
	shl dh,1
	shl dh,1
	or dl,dh

	mov al,settable[bx]
	out 70h,al
	mov al,dl
	out 71h,al
	
	inc bx
    loop settimeRAM_s
	
	pop si
	pop ds
	pop dx
	pop cx
	pop bx
	pop ax
	ret
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx4号功能结束

;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx显示字符传串函数开始
;此子程序为显示以零结束的任意长的字符串
;dh 行,dl 列,cl 颜色,ds:si 字符串首地址
display_showstr:
	push ax
	push cx
	push dx
	push si
	push es
	push di
	push ds

	mov ax,0b800h
	mov es,ax
	mov al,160	;由行列值计算具体的偏移地址
	mul dh
	mov dh,0
	add dx,dx
	add ax,dx
	mov di,ax		;dh  dl  对应的偏移地址
 display_showstr_s:
	mov ch,ds:[si]
	cmp ch,0
	je display_showstr_over
	mov es:[di],ch	;颜色在ch时才可mov cx
	mov es:[di+1],cl
	add di,2
	inc si
	jmp short display_showstr_s
display_showstr_over:
	pop ds
	pop di
	pop es
	pop si
	pop dx
	pop cx
	pop ax
	ret
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx显示字符传串函数结束

;清屏函数
clear_screen:
	push ax
	push es
	push di
	push cx
	
	mov ax,0b800h
	mov es,ax
	mov di,0
	mov ah,7h
	mov al,0
	mov cx,80*25
clear:
	mov es:[di],ax
	add di,2
	loop clear

	pop cx
	pop di
	pop es
	pop ax
	ret
	
;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx实现四个功能的主程序结束

main ends
end anzhuang_start

此代码在MSDos下的运行结果部分截图:
开启虚拟机后先显示菜单:
在这里插入图片描述
3号功能动态显示时间且颜色正常变化
在这里插入图片描述

4号功能修改时间:
在这里插入图片描述
显示修改后的时间:
在这里插入图片描述

  • 9
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
阅读下面的材料 : 开机后, CPU 自动进入到 FFF0:0 单元处执行,此处有一条跳转指令。 CPU 执行该指令后,转去执行 BIOS 中的硬件系统检测和初始化程序。 初始化程序将建立 BIOS 所支持的中断向量,即将 BIOS 提供的中断历程的入口地址登记在中断向量表中。 硬件系统检测和初始化完成后,调用 INT 19H 进行操作系统的引导。 如果设为从软盘启动操作系统,则 INT 19H 将主要完成一下工作: ( 1 )控制 0 号软驱,读取软盘 0 道 0 面 1 扇区的内容到 0 : 7C 00 。 ( 2 )将 CS:IP 指向 0 : 7C 00 。 软盘的 0 道 0 面 1 扇区中装有操作系统引导程序。 INT 19H 将其装到 0 : 7C 00 处后,设置 CPU 从 0 : 7C 00 开始执行此处的引导程序,操作系统被激活,控制计算机。 如果在 0 号软驱中没有软盘,或发生软盘 I/O 错误,则 INT 19H 将主要完成以下工作 ; (1) 读取硬盘 C 的 0 道 0 面 1 扇区的内容到 0 : 7C 00 ; (2) 将 CS:IP 指向 0 : 7C 00 。 这次课程设计的任务是编写一个可以自行启动计算机,不需要在现有操作系统环境中运行的程序。 改程序的功能如下: ( 1 )列出功能选项,让用户通过键盘进行选择,界面如下: 1 ) reset pc ; 重新启动计算机 2 ) Start system ; 引导现有的操作系统 3 ) Clock ; 进入时钟程序 4 ) Srt clock ; 设置时间 ( 2 )用户输入“ 1 ”后重新启动计算机。(提示:考虑 FFFF:0 ) ( 3 )用户输入“ 2 ” 后引导现有的操作系统。(提示:考虑硬盘 C 的 0 道 0 面 1 扇区) ( 4 )用户输入“ 3 ”后,执行动态现实当前日期,时间的程序。 现实格式如下:年 / 月 / 日 时:分:秒 进入此项功能后,一直动态现实当前的时间,在屏幕上将出现时间按秒变化的效果。(提示:循环读取 CMOS ) 当按下 F1 键后,改变现实颜色;按下 ESC 键后,返回到主选单。(提示:利用键盘中断) ( 5 )用户输入“ 4 ”后可更改当前的日期,时间,更改后返回到主选单。(提示:输入字符串) 下面给出的几点建议: ( 1 )在 DOS 下编写安装程序,在按转程序中包含任务程序; ( 2 )运行安装程序,将任务程序写到软盘上; ( 3 )若要任务程序可以在开机后自行执行,要将它写到软盘的 0 道 0 面 1 扇区上。如果程序长度大于 512B ,则需要用多个扇区存放,这种情况下,处于软盘 0 道 0 面 1 扇区中的程序就必须负责将其他扇区中的内容读入内存。 这个程序较为复杂,它用到了我们所学到的所有技术,需要进行仔细地分析和耐心地调试。这个程序对于我们的整个学习过程是具有总结性的,希望读者能够尽力完成。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值