16位汇编课程设计
来源:互联网 发布:广电网络20m宽带怎么样 编辑:程序博客网 时间:2024/04/27 07:45
编写一个可以自行启动的计算机,不需要在现有操作系统环境中运行的程序
-----王爽汇编语言 课程设计2
一、相关资料
二、设计思路
(1)首先思考引导程序是干什么的?
答:引导计算机找到用户代码(引导程序就是把用户代码读到相应内存中,因为软(硬)盘的第一个扇区只有512个字节,有些稍大的程序不可能一次性就能放到第一扇区里面的,更多的是放在其它扇区,然后由引导程序(第一扇区的程序)负责把其它扇区的代码读到内存中,所以我们写的引导程序任务就是利用int13中断把我们的主程序读到内存中,然后跳转并执行)
(2)怎么把程序写入软盘?
答:首先我们利用int 13把引导程序写入软盘第一扇区,然后再把主程序写入其它扇区(引导程序应该知道在哪些扇区,好读取代码)
(3)怎么完成代码编写?
答:知道我们可以先编写功能3,4,(4的改时间功能在虚拟8086模式下不能真正改时间),然后在写功能1,2,当完成一个
小任务(或函数)时就及时测试,减少后面的负担,最后在真正真机测试,修改,测试。。。成功!
三、测试环境
虚拟机+win7 32位+一个u盘+dos系统
说明:因为虚拟机里装了一个win7所以就直接用它来测试了,首先我从网上下载了一个U盘dos系统制作工具,将下载的msdos7.1写入了u盘,然后制作一个软盘镜像,可以网上下载工具进行制作,我用的是自带的软盘镜像,准备工作做好后就可以开始了(当然还有写好的程序),设置虚拟机从u盘启动,然后进入dos系统,在纯dos系统下,运行编写好的程序(exe文件),将程序写入软盘扇区,最后设置虚拟机从软盘启动,如果一切顺利,那么就会进入的写的程序的主界面,当然也许运气不好,没法一次性成功,那么就只有检查程序,有可能把软盘写“坏”了,没关系,格式化一下就好,重复以上工作就好了。
(当然也可以不用win7系统,直接在虚拟硬盘里面装dos,这样就不需要u盘了,在dos下写扇区,这样引导的也就是dos系统了而不是win7系统)
注:不能在windos系统下直接运行程序写扇区,因为此时运行在虚拟8086模式,在windos系统保护下,没法写软盘。
下图节选自Windows环境下32位汇编语言程序设计.罗云彬.第三版
我的程序运行效果如下:
(1)写软盘(从u盘启动)
(2)从软盘启动后的主界面
(3)功能3(显示时间)
(4)功能3--q功能(改变颜色)
(5)功能4(设置时间)
修改后的效果
功能4中的数据合法性检测
1号功能就是重启,再次出现主程序界面(应该太快,没有截图)
2号功能就会引导win7系统,进入win7系统
四:程序源码参考
.model small.dataerror db 'fail' ;写入软盘是否成功ok db 'success'.codestart: mov ax,cs mov es,ax ;es:bx指向要写的数据开始位置 ;==================================把引导程序写入磁盘的程序 lea bx,boot ;引导程序的偏移地址 mov al,1;写入的扇区数 mov ch,0;磁道号 mov cl,1;扇区号 mov dl,0;驱动器号(软驱从0开始,0:软驱A,1:软驱B,硬盘从80h开始,80h:硬盘C,81h:硬盘D) mov dh,0;磁头号(面) mov ah,3;int 13h的功能号,3表示写入扇区 int 13h cmp ah,0 jne showerror ;============================把主程序写入磁盘的程序=============== ;算出需要写入的写入的扇区数 lea bx,Main lea ax,MainEnd sub ax,bx xor dx,dx mov bx,512 div bx add ax,1 lea bx,Main ;引导程序的偏移地址 mov ch,0;磁道号 mov cl,2;扇区号 mov dl,0;驱动器号(软驱从0开始,0:软驱A,1:软驱B,硬盘从80h开始,80h:硬盘C,81h:硬盘D) mov dh,0;磁头号(面) mov ah,3;int 13h的功能号,3表示写入扇区 int 13h cmp ah,0 jne showerror ;================写入软盘成功 mov ax,@data mov ds,ax mov si,offset ok mov di,160*7+26*2 mov cx,7 call print over: mov ax,4c00h int 21h;===============写入软盘失败 showerror: mov ax,@data mov ds,ax mov si,offset error mov di,160*7+26*2 mov cx,4 call print jmp over ;==================================引导程序=========================== org 7c00hboot: jmp BootStart no db 'failure'BootStart: xor ax,ax mov es,ax mov bx,7e00h mov al,4;读入的扇区数 (前面计算所得) mov ch,0;磁道号 mov cl,2;扇区号 mov dl,0;驱动器号 mov dh,0;磁头号(面) mov ah,2;int 13h的功能号,2表示从扇区读进内存 int 13h cmp ah,0 je continue call fail jmp $ ;无限循环 continue: jmp bx ;================================磁盘读写失败显示===========================fail proc push ax push es push si push bx push cx mov ax,0b800h mov es,ax xor si,si lea bx,no mov cx,7 ;字符串长度FailStart: mov al,cs:[bx] mov es:[si],al add si,2 inc bx loop FailStart pop cx pop bx pop si pop es pop ax retfail endp lea ax,boot db 510-($- boot) dup(0) dw 0aa55h ;以aa55结尾 ;=========================================主程序=========================== ORG 7e00h Main: jmp MainStart ;子功能直接定址表 keyNum dw resetPC,startSys,Clock,SetClock ;菜单字符串 str0 db ' System Startup Options: Made By ztgreat 2015/02/1 ',0 str1 db ' ===================================================',0 str2 db ' 1. Restart The Computer ',0 str3 db ' 2. Guide The Current System ',0 str4 db ' 3. Into Clock Program ',0 str5 db ' 4. Set Time ',0 str6 db 'Please input the number of the menu: ',0 stringtable dw offset str0,offset str1,offset str2,offset str3,offset str4,offset str5,offset str6MainStart: call clearScreen ;清屏 mov ax,cs mov ds,ax mov cx,68 xor bx,bx mov di,160*2 ;提示信息首句,第2行第7列起 printf: mov si,cs:[stringtable+bx] call print add bx,2 add di,160+160;换两行 cmp bx,14 jne printf ;设置光标位置 mov ah,2 mov bh,0 ;页号 mov dh,13 ;行号 mov dl,116 ;列号 int 10h ; --------接收键盘输入 checkKey : mov ah,0 int 16h mov bx,0b800h mov es,bx mov es:[14*160+36*2],al ;显示输入结果 call delay ;便于看到输入结果 ;----------------数据合法性判断------------ cmp al,31h jb checkKey cmp al,34h ja checkKey xor bx,bx mov bl,al sub bl,30h ;将数字1~4的ASCII码转换为0~3 dec bl add bx,bx ;bx=bx*2 换算出定址表地址 call clearScreen call word ptr cs:keyNum[bx] ;根据直接定址表跳转到相应功能区 ;若调用返回则重新生成菜单 jmp near ptr MainStart ;从头开始 ;================字符串显示函数===========================;入口参数说明:;ds:si指向字符串地址;di显存偏移地址;cx字符长度print procpush di push cx push ax push es mov ax,0b800h mov es,ax @@ : mov al,[si] mov byte ptr es:[di],al inc si inc di mov byte ptr es:[di],00000010b inc di loop @B pop es pop ax pop cx pop di ret print endp ;=======================================重启计算机=============================== resetPC: jmp reset p dw 0,0ffffh reset: jmp dword ptr p;========================================引导现有操作系统===========================startSys: mov ax,0 mov es,ax mov bx,7c00h mov al,1 mov ch,0 mov cl,1 mov dl,80h ;硬盘C mov dh,0 mov ah,2 int 13h push es push bx retf ;跳转到操作系统引导程序所在内存区:0:7c00h ;=================================循环显示时钟===========================Clock proc push ax xor al,al call setframe C_S: call showClock ;显示时钟函数 in al,60h ;读取60h端口的键盘输入 cmp al,10h ;q键的扫描码为10h (因为电脑原因,改为q键) je setcolor cmp al,01h ;Esc键的扫描码为01h jne C_S pop ax ret setcolor: push bx push cx mov ax,0b800h mov es,ax mov bx,160*12+30*2+1 mov cx,17 @@:inc byte ptr es:[bx] add bx,2 loop @B pop cx pop bx jmp C_S Clock endp ;=================================设置显示时间边框============================;al=0 时钟显示边框,否则为时钟设置时的边框setframe proc push cx push ds push di push bx push si push cs pop ds xor bx,bx mov cx,8 mov di,160*7+26*2 ;定位边框显示位置 lea bx,frametable ;时钟显示时的边框地址偏移 cmp al,0 je frame lea bx,frametable2 ;时钟设置时的显示边框地址偏移 add cx,2 mov di,160*5+26*2 ;定位边框显示位置 jmp frame framea db ' [<--] move left ',0 frameb db ' [-->] move right ',0 framec db ' [Esc] return menu ',0 framed db ' [Enter] set over ',0 frame0 db ' [q] change color ',0 frame1 db ' [Esc] return menu ',0 frame2 db ' ',0 frame3 db '=========================',0 frame4 db '== ==',0 frame5 db '== ==',0 frame6 db '== ==',0 frame7 db '=========================',0 frametable dw offset frame0,offset frame1,offset frame2,offset frame3,offset frame4,offset frame5,offset frame6,offset frame7 frametable2 dw offset framea,offset frameb,offset framec,offset framed,offset frame2,offset frame3,offset frame4,offset frame5,offset frame6,offset frame7 frame:push cx mov cx,25 mov si,[bx] call print add bx,2 add di,160 pop cx loop frame pop si pop bx pop di pop ds pop cx ret setframe endp showClock proc push ax push si push bx push dx push di push cx jmp ShowStart ;日期时间单元号列表 cmos db 9,8,7,4,2,0 ;年,月,日,时,分,秒 signs db '/','/',' ',':',':',' ' ;分隔符 ShowStart: xor si,si xor di,di mov ax,0b800h mov es,ax xor bx,bx mov cx,6 show: push cx mov al,cmos[si] out 70h,al in al,71h ;将BCD码转换为相应字符的ASCII码 mov ah,al mov cl,4 shr ah,cl;右移4位让高4位变为第4位(得到0-9之间的数) and al,00001111b ;获得低4位 add ah,30h ;获得各字相应的ASCII码 add al ,30h mov byte ptr es:[160*12+30*2+bx],ah mov byte ptr es:[160*12+30*2+bx+2],al mov ah,signs[di] mov byte ptr es:[160*12+30*2+bx+4],ah add bx,6 inc di inc si pop cx loop show ShowRet: pop cx pop di pop dx pop bx pop si pop ax retshowClock endp;===================================时间设置================================ SetClock proc near push ax push si push es push dx push di mov al,1 call setframe call showclock jmp set bit db 0,2,6,8,12,14,18,20,24,26,30,32 set: mov si,0 mov ax,0b800h mov es,ax xor dh,dh settime: mov di,160*12+30*2 mov dl,bit[si] add di,dx ;es:dx指向屏幕要修改的日期和时间的单元地址 mov byte ptr es:[di+1],97h ;控制移动当前要修改的日期和时间的单元地址,背景色为蓝色闪烁 mov ah,0 int 16h ;读取键盘缓冲区第一个字单元中的键盘输入 cmp ah,01h ;Esc键的扫描码为01h jne next jmp clockretnext: cmp ah,1ch ;enter键的扫描码为1ch jne next_left jmp befor_enter next_left: cmp ah,4bh ;←键的扫描码为4bh jne next_right jmp left next_right: cmp ah,4dh ;→键的扫描码为4dh jne next_1 jmp right next_1: cmp al,30h ;数字0的ASCⅡ码为30h jb settime cmp al,39h ;数字9的ASCⅡ码为39h ja settime next_2: mov byte ptr es:[di],al ;修改当前的日期和时间的单元内容 mov al,0 ;清空al值,防止right重复检测al jmp right ;修改完成自动跳向下一个修改字单元 jmp settime clockret:pop di pop dx pop es pop si pop ax ret ;------------------------方向键向左移动-------------------------------- left: cmp al,34h ;判断是否为数字键盘4,数字键盘ah=4bh,al=34h jne lefts jmp next_2 lefts: mov byte ptr es:[di+1],02h ;恢复当前字节的背景色 cmp si,0 je lefte dec si jmp settimelefte: mov si,11 ;移动超界跳到最右边 jmp settime;------------------------方向键向右移动-------------------------------- right: cmp al,36h ;判断是否为数字键盘6,数字键盘ah=4dh,al=36h jne rights jmp next_2rights: mov byte ptr es:[di+1],02h ;恢复当前字节的背景色 cmp si,11 je righte inc si jmp settimerighte: mov si,0 ;移动超界跳到最左边 jmp settime befor_enter: mov si,0 mov cx,6 mov ax,0b800h mov es,ax xor dh,dh xor bx,bxenters: push cx mov di,160*12+30*2 mov dl,bit[si] add di,dx mov ah,byte ptr es:[di] sub ah,30h ;十位显示字符转化为数字 mov al,byte ptr es:[di+2] sub al,30h ;个位显示字符转化为数字 mov ch,cmos[bx] ;ch指向CMOS RAM中要修改的单元地址 mov cl,4 shl ah,cl add ah,al ;ah指向CMOS RAM中要修改的单元数据 call checktime ;时间设置错误检测 cmp cl,1 je setagain ;如果数据不合法则重新输入 mov al,ch out 70h,al ;向地址端口70h写入要访问的单元地址 mov al,ah out 71h,al ;向数据端口71h写入指定单元的数据 inc bx add si,2 pop cx loop enters jmp clockretsetagain:pop cx ;把刚刚push的cx出栈,否则没有平衡栈,将会出错 jmp set SetClock endp ;------------------------范围检测函数---------------------------------- ;功能:(1) (bx)=9,代表年份,ah代表数据,不需要检测 ; (2) (bx)=8,代表月份,ah取值范围(01-12) ; (3) (bx)=7,代表天数,ah取值范围(01-31) ; (4) (bx)=4,代表小时,ah取值范围(00-23) ; (5) (bx)=2,代表分钟,ah取值范围(00-59) ; (6) (bx)=0,代表秒钟,ah取值范围(00-59) bcd_12 equ 00010010b bcd_23 equ 00100011b bcd_31 equ 00110001b bcd_59 equ 01011001b checktime proc push bx xor bh,bh mov bl,ch mov cl,0 ;0表示没有问题,1表示出现问题 cmp bx,8 je checkmouth ;检测月 cmp bx,7 je checkday ;检测日 cmp bx,4 je checkhour ;检测时 cmp bx,2 je checkminute ;检测分 cmp bx,0 je checksecond ;检测秒 jmp checkret checkmouth: ;检查月份 cmp ah,1 jb moutherror cmp ah,bcd_12 ja moutherror jmp checkret checkday: ;检查日合法性 cmp ah,1 jb dayerror cmp ah,bcd_31 ja dayerror jmp checkret checkhour: ;检查时合法性 cmp ah,0 jb hourerror cmp ah,bcd_23 ja hourerror jmp checkret checkminute:;检查分合法性 cmp ah,1 jb minerror cmp ah,bcd_59 ja minerror jmp checkret checksecond: ;检查秒合法性 cmp ah,1 jb secerror cmp ah,bcd_59 ja secerror jmp checkret moutherror: mov bx,0 ;月份出现问题,bx对应月份错误代码号 mov cl,1 ;标志置1 call error2 ;显示错误 jmp checkret dayerror: mov bx,2 mov cl,1 call error2 jmp checkret hourerror: mov bx,4 mov cl,1 call error2 jmp checkret minerror: mov bx,6 mov cl,1 call error2 jmp checkret secerror: mov bx,8 mov cl,1 call error2 checkret: pop bx ret checktime endp;==========================时间错误提示==============================error2 proc jmp errorstarterrort db 'mouth error,please change again! ',0 errord db 'day error,please change again! ',0 errorh db 'hour error,please change again! ',0 errorm db 'minute error,please change again! ',0 errors db 'second error,please change again! ',0 errorkey dw offset errort,offset errord,offset errorh,offset errorm,offset errors errorstart: push ax push ds push si push cx push di push cs pop ds mov si,cs:[errorkey+bx] mov cx,34 mov di,160*17+23*2 call print pop di pop cx pop si pop ds pop ax ret error2 endp ;=======================================清屏函数===========================clearScreen procpush ax push es push di push cx mov ax,0b800h mov es,ax mov di,0 mov cx,2000 clear: mov byte ptr es:[di],' ' add di,2 loop clear pop cx pop di pop es pop ax retclearScreen endp ;===============================延时程序============================== delay proc push ax push dx mov dx,10h mov ax,0 s1: sub ax,1 sbb dx,0 cmp ax,0 jne s1 cmp dx,0 jne s1 pop dx pop ax retdelay endp MainEnd:nopend start
0 0
- 16位汇编课程设计
- 16位汇编笔记
- 16位汇编指令
- 正在汇编课程设计中
- 王爽《汇编》课程设计一
- 汇编课程设计 时钟
- 王爽 汇编 课程设计1
- 微机原理课程设计32位汇编学习之一(显示消息框)
- 微机原理课程设计32位汇编学习之二(创建简单的窗口)
- 微机原理课程设计32位汇编学习之三(显示字符串)
- 微机原理课程设计32位汇编学习之四(显示字符串之特殊字体)
- 16位汇编(asm) helloWorld
- 16位汇编 loop循环
- 学生成绩管理(汇编课程设计)
- 汇编课程设计--数的运算
- 16位汇编与WIN32汇编的主要区别
- 16位汇编第六讲汇编指令详解第二讲
- 16位汇编 我校神州数码客户端解密
- 从零开始学习OpenCL开发(四)shader
- mac中配置ice3.3.1环境
- linux select函数用法
- 计算机视觉论文
- c_基础_定义泛型时注意事项
- 16位汇编课程设计
- oracle_12c ORA-00119和ORA-00132
- 使用nginx+nginx-rtmp-module+ffmpeg搭建流媒体服务器笔记(八)
- struts2 实战 登陆验证
- gsoap 中文乱码问题
- bokeceshi
- 获取应用的当前版本号&获取当前android系统的版本号
- Android中GridView使用
- 蓝桥杯 角谷猜想 深搜