初学汇编,小白一枚,不知道错在哪里了,求大神带飞,代码是在源码中国下载的,在dosbox显示这样,
;***********************************************************************************************************************
;程序功能:
;完成小车的自动和手动沿轨道行驶的过程,并具有计时功能
;***********************************************************************************************************************
;运行说明:
;程序运行之后,即显示出轨道和小车;
;按键‘a’或‘m’选择自动还是手动(a为自动,m为手动),按‘s’键启动小车;
;手动时,按方向键控制小车方向,撞到轨道时,小车会停止并闪动;
;小车到达终点后会自动停车,之后按‘r’键可使小车回到起点,然后重新选择小车的运行得方式;
;小车行驶过程中,计时器计时,到达终点则停止计时;
;手动时,按‘t’暂停,‘c’键继续,此间计时不停止;
;小车回到起点位置后,按下‘s’键计时清零,并重新进行下一次的计时;
;小车处于未选定模式和手动运行时可按Esc键退出运行。
;***********************************************************************************************************************
stack segment 'stack'
db 256 dup(0)
stack ends
data segment
count dw 0
sec dw 0
min dw 0
save_lc dw 2 dup(?)
car db 0,7,0,0,0,0,0,0,7,0 ;车的图案,10行10列
db 7,0,7,0,0,0,0,7,0,7
db 0,7,9,9,9,9,9,9,7,0
db 0,0,9,0,0,0,0,9,0,0
db 0,0,9,0,0,0,0,9,0,0
db 0,0,9,0,0,0,0,9,0,0
db 0,0,9,0,0,0,0,9,0,0
db 0,7,9,9,9,9,9,9,7,0
db 7,0,7,0,0,0,0,7,0,7
db 0,7,0,0,0,0,0,0,7,0
x dw 180 ;起始位置
y dw 83
start_flag_1 db 0 ;启动标志1
start_flag_2 db 0 ;启动标志2
direc_flag db 0 ;方向标志
touch_flag db 0 ;触轨标志
arrive_flag db 0 ;到达标志
turn_x1 dw 138 ;拐弯点
turn_y1 dw 28
turn_x2 dw 203
turn_y2 dw 133
turn_x3 dw 135
es_save dw 0 ;用于保存图形缓冲区的首地址
mode db ? ;用于保存显示之前显示器的模式
x1 dw ? ;9型轨道的坐标
y1 dw ?
x2 dw ?
y2 dw ?
x3 dw ?
y3 dw ?
x4 dw ?
x_d dw 15 ;轨道的宽度
data ends
code segment ;段设置
assume cs:code,ds:data
start:
mov ax,data
mov ds,ax
mov es,ax
mov ax,0a000h ;图形缓冲区的首地址
mov es,ax
mov es_save,ax ;把图形缓冲区的首地址保存在es_save
mov ah,0fh
int 10h ;获取显示器显示图形之前的显示模式
mov mode,al ;把显示模式保存在mode中
mov ah,35h
mov al,1ch
int 21h ;取中段号为1ch(定时中断)的中段向量(即中断程序的入口地址),并把它放在ES:BX中
mov save_lc,bx
mov save_lc+2,es ;保存中断向量
push ds ;保存ds
mov dx,seg clint ;定时中断服务程序的段地址
mov ds,dx
mov dx,offset clint ;定时中断的中断服务程序的偏移地址
mov al,1ch
mov ah,25h
int 21h ;设置中断向量,入口:DS:DX=中断向量,al=中断类型号。
;即把定时中断的中断服务程序的入口地址放在4*n(其中n为中断类型号)中
pop ds ;ds出栈
in al,21h ;允许键盘和定时器中断
and al,11111100b
out 21h,al
sti ;开中断
mov ax,13h
int 10h ;设置显示器的模式为13h,320×200,256色
call guidao_9 ;画轨道
call picture ;显示小车
input:
mov ah,0
int 16h ;等待按键输入
cmp ax,011bh ;Esc键退出
jz b4
cmp ax,326dh ;选m,则为手动
jne b1
call xiaoche_shou
jmp b2
b1: cmp ax,1e61h ;选a,则为自动
jne input ;都没有选,则重新选择输入
call xiaoche_move
b2: mov ah,0 ;等待按下r键
int 16h
cmp ax,1372h ;r键的扫描码
jnz b2 ;不是r键,则等待至按下r
mov start_flag_1,0 ;是r键,则将起始标志位清零
mov start_flag_2,0
mov arrive_flag,0
b3: call clearpicture ;擦除终点的小车
mov x,180 ;小车回到起始位置
mov y,83
call picture ;显示小车
jmp input
b4: push ds
mov dx,save_lc
mov ax,save_lc+2
mov ds,ax
mov al,1ch
mov ah,25h
int 21h ;重置之前的中断向量,调用lch
pop ds
mov ah,0
mov al,mode
int 10h ;把显示器的模式设置为显示图形之前的模式
mov ax,4c00h ;返回dos
int 21h
;***********************************************************************************************************************
;显示9字型轨道
;***********************************************************************************************************************
guidao_9 proc
mov x1,190
mov y1,95
mov x2,135
mov y2,25
mov x3,215
mov y3,145
mov x4,135
call draw_9_line ;外轨道
mov x1,190
mov y1,80 ;轨道的入口
mov x2,150
mov y2,40
mov x3,200
mov y3,130
mov x4,135 ;轨道的出口
call draw_9_line ;内轨道
ret
guidao_9 endp
;******************************画9字**********************************
draw_9_line proc
mov cx,x1
mov dx,y1
mov di,y2
mov si,x2
call hline
call sline
mov di,y3
mov si,x3
call hline
call sline
mov si,x4
call hline
draw_9_line endp
;*********************画竖线**********************
sline proc
mov al,03h ;设置直线的颜色为青
mov bh,0 ;0页
mov ah,0ch
cmp dx,di
jg a1line
aline:
int 10h ;写图形象素,AL=01h象素值,BH=0页码,(CX、DX)=(0,0)图形坐标列(X)、行(Y)
inc dx
cmp dx,di ;判断是否到di行
jng aline ;没到,则画线
dec dx ;使下一个点与这一个点重合
jmp e3
a1line:
int 10h
dec dx
cmp dx,di
jnl a1line
inc dx
e3: ret ;到了,则退出
sline endp
;*********************画横线**********************
hline proc
mov al,03h ;设置直线的颜色为青
mov bh,0 ;0页
mov ah,0ch
cmp cx,si
jg b1line
bline:
int 10h ;写图形象素,AL=01h象素值,BH=0页码,(CX、DX)=(0,0)图形坐标列(X)、行(Y)
inc cx ;画第一点,并让横坐标加一
cmp cx,si ;判断是否到si列
jng bline ;没到,则画线
dec cx ;使下一条线的起点与这一个点重合
jmp e2
b1line:
int 10h ;写图形象素,AL=01h象素值,BH=0页码,(CX、DX)=(0,0)图形坐标列(X)、行(Y)
dec cx
cmp cx,si
jnl b1line ;没到,则画线
inc cx ;使下一条线的起点与这一个点重合
e2: ret ;到了,则退出
hline endp
;***********************************************************************************************************************
;显示小车(通过向图形显示缓冲区写点)
;***********************************************************************************************************************
picture proc near
mov ax,es_save
mov es,ax
mov dx,y
mov bx,0
again:
cmp dx,0
je over
add bx,320
dec dx
jmp again ;找到小车第一个点所在行
over: mov dx,10
lea si,car
next1:
mov cx,10
mov di,x ;找到小车第一个点
next: mov al,[si]
mov es:[bx+di],al ;往空位填写数据
inc si ;指向下一个待填入的数据
inc di ;指向下一个等待填写的空位
loop next
add bx,320 ;转到下一行
dec dx
jne next1
ret
picture endp
;***********************************************************************************************************************
;计时器(中断号为1ch的中断为计时器中断,每55ms中断一次,每秒发生18.2次中断)
;***********************************************************************************************************************
clint proc far
push ax ;保护寄存器
push bx
push cx
push dx
push si
push di
push bp
push sp
push ds
push es
mov bx,data
mov ds,bx ;设置数据段
assume ds:data
cmp arrive_flag,1 ;判断小车是否到达终点
jne e6 ;没到,则跳至e7
call disptime ;到达,则显示时间
jmp return ;返回
e6: lea bx,count
inc word ptr[bx] ;每产生一次定时中断,count加1
cmp word ptr[bx],18 ;判断是否到1秒
jne e7 ;没到,则跳至e6
call inct ;调整时间
e7: mov al,start_flag_1
and al,start_flag_2
jnz e8
mov al,start_flag_1
or al,start_flag_2
jz return
jmp e9
e8: mov count,0
mov sec,0
mov min,0
mov start_flag_2,0
e9: call disptime ;显示小车
return:
pop es
pop ds
pop sp
pop bp
pop di
pop si
pop dx
pop cx
pop bx
pop ax
iret
clint endp
;******************判断是否进位*******************
inct proc near
mov word ptr[bx],0
add bx,2
inc word ptr[bx]
cmp word ptr[bx],60
jne exit
call inct
exit: ret
inct endp
;*****************************显示时间********************************
disptime proc near
mov ax,min
call bindec
mov dl,':'
mov ah,02h
int 21h
mov ax,sec
call bindec
mov dl,':'
mov ah,02h
int 21h
mov bx,count
mov al,55d
mul bl
call bindec
mov dl,0dh ;输出回车,让光标回到起点
mov ah,02h
int 21h
ret
disptime endp
;************把一个三位十进制数显示出来***********
bindec proc near
mov cx,100d
call decdiv
mov cx,10d
call decdiv
mov cx,1
call decdiv
ret
bindec endp
;********************显示高位*********************
decdiv proc near
mov dx,0
div cx
push dx
mov dl,al
add dl,30h
mov ah,02h
int 21h ;显示一位
pop ax
ret
decdiv endp
;************************************************************************************************************************
;擦除
;************************************************************************************************************************
clearpicture proc near
mov dx,y
mov bx,0
again2:
cmp dx,0
je over2
add bx,320
dec dx
jmp again2
over2:
mov dx,10
next12:
mov cx,10
mov di,x
next2:
mov al,0 ;把该点置为0,即用黑色擦除该点
mov es:[bx+di],al
inc di
loop next2
add bx,320
dec dx
jne next12
ret
clearpicture endp
;***********************************************************************************************************************
;延时程序
;***********************************************************************************************************************
delay proc near
push bx
push cx
mov bx,1234
back:
mov cx,66
push ax
wait1:
in al,61h
and al,10h
cmp al,ah
je wait1
mov ah,al
loop wait1
pop ax
dec bx
jne back
pop cx
pop bx
ret
delay endp
;***********************************************************************************************************************
;小车自动运行
;***********************************************************************************************************************
xiaoche_move proc
call picture ;转移至picture程序段
ag: mov ah,7 ;中断
int 21h
cmp al,'s' ;设置开始键s
jne ag ;判断是否为s,不是则转至ag中断
mov start_flag_1,1
mov start_flag_2,1
start1:
call clearpicture
dec x
call picture
call delay
mov si,x
cmp si,turn_x1 ;遇到第一个拐弯
jg start1
start2:
call clearpicture
dec y
call picture
call delay
mov si,y
cmp si,turn_y1 ;遇到第二个拐弯
jg start2
start3:
call clearpicture
inc x
call picture
call delay
mov si,x
cmp si,turn_x2 ;遇到第三个拐弯
jl start3
start4:
call clearpicture
inc y
call picture
call delay
mov si,y
cmp si,turn_y2 ;遇到第四个拐弯
jl start4
start5:
call clearpicture
dec x
call picture
call delay
mov si,x
cmp si,turn_x3 ;遇到第五个拐弯,即终点
jg start5
mov arrive_flag,1
ret
xiaoche_move endp
;***********************************************************************************************************************
;小车手动运行
;***********************************************************************************************************************
xiaoche_shou proc
j0: call clearpicture ;擦除小车
call saomiao ;键盘扫描
cmp start_flag_1,1 ;判断小车是否启动
jne a8 ;没有,则呆在原地不动
;判断小车运动的方向
cmp direc_flag,1 ;上
jne a1
dec y
a1: cmp direc_flag,2 ;下
jne a2
inc y
a2: cmp direc_flag,3 ;左
jne a3
dec x
a3: cmp direc_flag,4 ;右
jne a4
inc x
a4: call ya_line_do ;检测是否碰到轨道
cmp touch_flag,1
jne a8 ;没有碰到轨道,则继续前进
call guidao_9 ;碰到则重新显示轨道
mov touch_flag,0 ;将触轨标志清零
call back_step ;小车后退一步,回到轨道
a8: call picture
call delay
cmp arrive_flag,1 ;判断小车是否到达终点,到了则退出
jne j0
a9: ret
xiaoche_shou endp
;***********************************************************************************************************************
;键盘扫描程序
;***********************************************************************************************************************
saomiao proc near
mov ah,01h ;从键盘读一个字符,读到的结果为键的扫描码,存放在AH中
int 16h
jz f ;如果无键按下,则退出
mov ah,00h ;若有键按下则中断当前
int 16h
cmp ax,1f73h ;s的扫描码
jne h
mov start_flag_1,1
mov start_flag_2,1
mov direc_flag,0
mov arrive_flag,0
h: cmp ax,1474h ;t的扫描码
jne j
mov start_flag_1,0
mov start_flag_2,1
k: call picture
mov ah,0
int 16h
cmp ax, 2e63h ;c的扫描码
jne k
mov start_flag_1,1
mov start_flag_2,0
call clearpicture
j: cmp ax,4800h ;上键的扫描码
jne a
mov direc_flag,1
a: cmp ax,5000h ;下键的扫描码
jne b
mov direc_flag,2
b: cmp ax,4b00h ;左键的扫描码
jne g
mov direc_flag,3
g: cmp ax,4d00h ;右键的扫描码
jne f
mov direc_flag,4
jmp f
e1: mov al,mode ;一旦有按键输入,则把显示器的模式设置为画直线之前的模式
mov ah,0
int 10h
mov ax,4c00h
int 21h
f: ret
saomiao endp
;***********************************************************************************************************************
;小车触轨判断及处理
;***********************************************************************************************************************
ya_line_do proc
mov ax,y2
mov bx,y1
mov cx,x2
call ya_y_line
sub ax,x_d
add bx,x_d
sub cx,x_d
call ya_y_line
mov ax,y2
mov bx,y3
mov cx,x3
call ya_y_line
sub ax,x_d
add bx,x_d
add cx,x_d
call ya_y_line
mov ax,x2
mov bx,x1
mov cx,y1
call ya_x_line
sub ax,x_d
add cx,x_d
call ya_x_line
mov ax,x2
mov bx,x3
mov cx,y2
call ya_x_line
sub ax,x_d
add bx,x_d
sub cx,x_d
call ya_x_line
mov ax,x4
mov bx,x3
mov cx,y3
call ya_x_line
add bx,x_d
add cx,x_d
call ya_x_line
cmp touch_flag,1
je e4
mov ax,y3 ;判断是否到终点
mov bx,ax
add bx,x_d
mov cx,x4
call ya_y_line
mov al,touch_flag
mov arrive_flag,al
e4: ret
ya_line_do endp
;*****************判断是否触到y线*****************
ya_y_line proc ;ax为y1(起点),bx为y2(终点),cx为x1
cmp x,cx
je n3
mov dx,cx ;注意cx不能变化
sub dx,9
cmp x,dx
jnz n1
n3: mov dx,ax
sub dx,9
cmp y,dx
jl n1
cmp y,bx
jg n1
mov touch_flag,1
n1: ret
ya_y_line endp
;*****************判断是否触到x线*****************
ya_x_line proc ;ax为x1(起点),bx为x2(终点),cx为y1
cmp y,cx
je n5
mov dx,cx ;注意cx不能变化
sub dx,9
cmp y,dx
jnz n2
n5: mov dx,ax
sub dx,9
cmp x,dx
jl n2
cmp x,bx
jg n2
mov touch_flag,1
n2: ret
ya_x_line endp
;************************小车触轨则后退一步***************************
back_step proc
cmp direc_flag,1 ;如果碰到轨道,则后退一步
jne a5
inc y
a5: cmp direc_flag,2
jne a6
dec y
a6: cmp direc_flag,3
jne a7
inc x
a7: cmp direc_flag,4
jne a8
dec x
ret
back_step endp
;***********************************************************************************************************************
;***********************************************************************************************************************
code ends
end start