通过Proteus实现8层楼电梯:
8层楼的电梯,
可以实现内部和外部的按键的功能,
以及通过的算法实现楼层的选择。
有数码管显示和lcd显示,
以及到达楼层后的铃声提示。
具体实现见代码注释:
DATAS SEGMENT
;此处输入数据段代码
IOY0 equ 0E000h
IOY1 equ 0E040h
IOY2 equ 0E080h
IOY3 equ 0E0C0h
IOY4 equ 0E100h
First_A equ IOY0+00H*4
First_B equ IOY0+01H*4
First_C equ IOY0+02H*4
First_MODE equ IOY0+03H*4
Seq db 20 dup(?);记录按下的三个序号
Ordered db 20 dup(?);记录下排序之后的seq数组
ordered_num db 00h
num db 0
LED db 01h,02h,04h,08h,10h,20h,40h,80h;点亮对应的部分
Out_LED db 0feh,0fdh,0fbh,0f7h,0efh,0dfh,0bfh,7fh;熄灭对应的部分
Current_LED db ?
Row_disp db 0feh,0fdh,0fbh,0f7h
Stop_flag db 00h;停止标志
Stop_mode db 00h;存储当前的停止运行标志
;-------------------------------------------
Second_A equ IOY1+00h*2
Second_B equ IOY1+01h*2
Second_C equ IOY1+02h*2
Second_MODE equ IOY1+03h*2
buf1 db 'Welcome'
length1 db $-buf1
buf2 db 'Up'
length2 db $-buf2
buf3 db 'Down'
length3 db $-buf3
buf4 db 'Close'
length4 db $-buf4
buf5 db 'Open'
length5 db $-buf5
buf6 db 'Run'
length6 db $-buf6
buf7 db 4 dup(' ')
length7 db $-buf7
Row db ?
Line db ?
;----------------------------------
MY8253_COUNT0 equ IOY2+00H*4
MY8253_COUNT1 equ IOY2+01H*4
MY8253_COUNT2 equ IOY2+02H*4
MY8253_MODE equ IOY2+03H*4
;----------------------------------
current_floor db 01h;当前楼层
aim_floor db ?;输入的目标楼层
;----------------------------------
Third_A equ IOY3+00h*2
Third_B equ IOY3+01h*2
Third_C equ IOY3+02h*2
Third_Mode equ IOY3+03h*3
;----------------------------------
TFREQ dw 264,264,396,396,0
TDLY dw 6000,6000,6000,6000
;----------------------------------
Fourth_A equ IOY4+00h*4
Fourth_B equ IOY4+01h*4
Fourth_C equ IOY4+02h*4
Fourth_Mode equ IOY4+03h*4
Outside db 20 dup(?);外部输入楼层
Out_num db 00h
Current_up_led db 00h
Current_down_led db 00h
Current_dir db 01h;00h表示下行,01h表示上行
;----------------------------------
max db ?;放入当前数据的最大值
dir db ?;表示运行的方向,1是上行,0是下行
sort_dir db ?;表示冒泡排序的方向,0表示正向排序,1表示反向排序
tmp db 20 dup(?);用于暂存的数据
tmp_num db 00h
DATAS ENDS
STACKS SEGMENT
;此处输入堆栈段代码
dw 50 dup(?)
top label byte
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
mov ax,stacks
mov ss,ax
mov sp,offset top
MOV AX,DATAS
MOV DS,AX
;此处输入代码段代码
;call Lcd_main
;call Running
;初始化当前楼层显示1
mov dx,Third_mode
mov al,10000010B;A口输出,B口输入,C口第四位输出
out dx,al;设置当前8255的模式
mov al,current_floor
mov dx,Third_A
out dx,al
;------------------------------------
;设置外部键盘8255的模式
mov dx,Fourth_Mode
mov al,10001000B;A,B都为输出信号,C的高位为输入信号,D的高位为输出信号
out dx,al
call Lcd_main
Again:
call keyboard
jmp again
;-------------------------------------
Keyboard proc near
mov al,10001000B;A为输出信号,C的高位为输入信号列,低位为输出信号行
mov dx,First_mode
out dx,al
mov bh,00h;从第零行开始扫描
mov bl,00h
Restart:
call disp
Detect_row:
mov dx,First_C
mov al,row_disp[bx]
out dx,al
in al,dx
and al,0f0h
cmp al,0f0h
jnc next_line;无输入直接转到下一行
mov cx,4000h
loop $
in al,dx
and al,0f0h
cmp al,0f0h
jnc next_line
mov dl,0;用于记录该行中列的数据
mov cx,4
Find_line:
shl al,1
jnc record_line;无进位说明是列
inc dl
loop Find_line
Record_line:
mov al,bl;行的数据保存在bl中,列的数据保存在dl中
shl al,1
shl al,1
mov dh,03h
sub dh,dl
add al,dh
call xiaodou
;记录之后继续扫描下一行
Next_line:
call delay
add bl,01h
;test bl,04h
;jz Detect_row;没有扫描完继续扫描下一行
and bl,0fbh
jmp restart
Stop:
ret
Keyboard endp
Xiaodou proc near;判断两次输入的seq是否相同,相同只当一次
push dx
push bx
mov bh,00h
mov bl,num;bl表示序号,al表示输入的键值
cmp al,07h;输入键的范围超过数字键的范围
ja function;输入的可能是功能键也可能是无效键
cmp bl,01h;至少当al为01的时候才有比较的意义
jae compare
jmp save;num为00h进入保存阶段
;----------------------------------------------
compare:;需要看这次输入的数据以前是否输入过
;dec bl;上一次的数据
;mov dl,seq[bx];上一次的数据存储在dl中,seq的末尾
;cmp dl,al;这一次的数据存储在al中
;je stop1;如果相等退出,不记录这一次的结果
;cmp bl,01h;如果bl大于等于02h说明超范围了
;ja lights_out
;inc bl
mov cl,al
mov ch,00h
mov ah,01h
cmp cx,00h
ja loop_com;如果是0的话不能进入左移
jmp end_com
Loop_com:
shl ah,01h
loop loop_com
End_com:
mov dl,current_led
test dl,ah
jnz stop1
cmp bl,02h
ja lights_out
;----------------------------------------------
save:
mov seq[bx],al;将数据记录到seq中去
inc num;num的数值自增1,当num的数值大于3时,自动清零
jmp stop1
lights_out:
mov num,00h
mov al,00h;这里不应该只对应显示功能在后面的停止电梯中页应该用到
mov dx,First_A
out dx,al
jmp stop1
Function:
cmp al,0bh;超出范围表示无效
ja stop1
cmp al,08h;启动键
je Run_ele
cmp al,09h;紧急停止键
je Stop_ele
cmp al,0ah;求助键
je Help_ele
cmp al,0bh;进入外部按键的选择
je Out_ele
Run_ele:;启动将数据从seq中装入aim_floor,显示close
;应该要分成三种情况
;第一种当前楼层在输入的楼层之间,默认先上行
;第二种情况是当前楼层比输入的楼层低
;第三种情况是当前楼层比输入的楼层高
;第四种情况无输入楼层
;输入完成之后要将已经到达的楼层从seq中清除出去
call process;ordered存储的是排好序的数据
cmp ordered_num,00h;首先要排除没有输入的情况
je stop1
;-------------------------------------------
;运行部分
mov cl,ordered_num;循环次数为元素的个数
mov ch,00h
lea bx,ordered
;-------------------------------------------
;测试处理的结果
;mov bx,01h
;mov al,ordered[bx]
;call show_number
;jmp $
;经过测试ordered中的数据正确
;-------------------------------------------
Loop_running:;意思是seq中的每一层都去
mov al,[bx];seq中的最后一个数据应该先去
inc al;真实层数应该加1
mov aim_floor,al
call Running;运行程序
;-------------------------------------------
mov row,01h
mov line,04h
lea di,buf4;显示'Close',在关门的时候显示
push cx
mov cl,length4
call show_string
pop cx
call Wait_5s
;-------------------------------------------
;清除部分,熄灭对应数码管,从seq中清除,num自减1
mov dh,00h
mov dl,[bx]
mov si,dx
;---------------------------------------------
;熄灭主程序部分程序
mov ah,current_led;将当前的led显示放入ah中
mov al,Out_led[si];将熄灭数据放入al中
and al,ah;熄灭后的新输出
mov dx,First_A
out dx,al
mov current_led,al;输入新的输出数据
;---------------------------------------------
;在程序里剥离了方向关系,可是这里其实是有方向关系的
;有方向和楼层
;---------------------------------------------
;mov al,current_dir
;cmp al,00h;00h为下行,01h为上行,还没有解决的问题是同时有上有下即重复的情况,转场的情况
;je Down_out
;jmp up_out
;-------------------------------------------------
cmp cx,01h;只剩下最后一个楼层的情况
je loop_end
mov dl,[bx]
mov dh,[bx+1]
cmp dl,dh
jbe up_pro;这一个时刻比下一个时刻小是上行
jmp down_pro
Up_pro:
mov al,01h;01h为上行
mov ah,current_dir
xor al,ah;如果异或的结果相同说明是上行
cmp al,00h
je up_out
jmp both_out
Down_pro:
mov al,00h;00h为下行
mov ah,current_dir
xor al,ah;如果异或的结果相同说明为下行
cmp al,00h
je down_out
jmp both_out
;-------------------------------------------------
Down_out:
mov ah,current_down_led
mov al,out_led[si]
and al,ah
mov dx,Fourth_B
out dx,al
mov current_down_led,al
jmp out_end
Up_out:
mov ah,current_up_led
mov al,out_led[si]
and al,ah
mov dx,Fourth_A
out dx,al
mov current_up_led,al
jmp out_end
;------------------------------------------
Both_out:
mov ah,current_down_led
mov al,out_led[si]
and al,ah
mov dx,Fourth_B
out dx,al
mov current_down_led,al
;--------------------------
mov ah,current_up_led
mov al,out_led[si]
and al,ah
mov dx,Fourth_A
out dx,al
mov current_up_led,al
;------------------------------------------
Out_end:
inc bx;bx自增1
;--------------------------------------
;模拟cx语句
dec cx
cmp cx,00h
jne loop_running
;--------------------------------------
;loop Loop_running
loop_end:
mov num,00h
mov ordered_num,00h
mov out_num,00h
;熄灭外部中的所有灯
mov al,00h
mov dx,Fourth_A
out dx,al
mov dx,Fourth_B
out dx,al
mov current_up_led,al
mov current_down_led,al
jmp stop1
Stop_ele:;停止中断running
call stop_running
jmp stop1
Help_ele:;求助,这个用在串口通信中
jmp stop1
Out_ele:
call keyboard2
stop1:
pop bx
pop dx
ret
Xiaodou endp
;-----------------------------------------
;键盘2的相关函数
Keyboard2 proc near
mov dx,Fourth_A
mov al,00h
out dx,al
mov dx,Fourth_B
mov al,00h
out dx,al
mov bx,00h;从第零行开始扫描
Restart:
Detect_row:
mov dx,Fourth_C
mov al,row_disp[bx]
out dx,al
in al,dx
and al,0f0h
cmp al,0f0h
jnc next_line;无输入直接转到下一行
mov cx,5000h
loop $
in al,dx
and al,0f0h
cmp al,0f0h
jnc next_line
mov dl,0;用于记录该行中列的数据
mov cx,4
Find_line:
shl al,1
jnc record_line;无进位说明是列
inc dl
loop Find_line
Record_line:
mov al,bl;行的数据保存在bl中,列的数据保存在dl中
shl al,1
shl al,1
mov dh,03h
sub dh,dl
add al,dh
cmp al,07h;如果按下了功能键返回主键盘
je return_key
call Xiaodou2;al中的值没有改变
call disp2;使用al中的值
;记录之后继续扫描下一行
Next_line:
call delay
add bl,01h
and bl,0fbh
jmp restart
ret
Return_key:;返回主键盘部分
ret
Keyboard2 endp
Xiaodou2 proc near;判断两次输入的seq是否相同,相同只当一次
push dx
push bx
mov bh,00h
mov bl,out_num
cmp bl,01h;至少当al为01的时候才有比较的意义
jae compare
cmp bl,0fh
ja lights_out
jmp save;num为00h进入保存阶段
;-------------------------------------------
compare:
;dec bl;上一次的数据
;mov dl,Outside[bx];上一次的数据存储在dl中,seq的末尾
;cmp dl,al;这一次的数据存储在al中
;je stop1;如果相等退出,不记录这一次的结果
;inc bl
cmp al,07h
ja big_com
Small_com:
mov cl,al
mov ch,00h
mov ah,01h
cmp cx,00h
ja loop_com1;如果是0的话不能进入左移
jmp end_com1
Loop_com1:
shl ah,01h
loop loop_com1
End_com1:
mov dl,current_up_led
test dl,ah
jnz stop1
jmp save
Big_com:
mov cl,al
sub cl,08h
mov ch,00h
mov ah,01h
cmp cx,00h
ja loop_com2;如果是0的话不能进入左移
jmp end_com2
Loop_com2:
shl ah,01h
loop loop_com2
End_com2:
mov dl,current_down_led
test dl,ah
jnz stop1
;-------------------------------------------
save:
mov Outside[bx],al;将数据记录到seq中去
inc out_num;out_num的数值自增1
jmp stop1
lights_out:
mov Out_num,00h
mov al,00h;这里不应该只对应显示功能在后面的停止电梯中页应该用到
mov dx,Fourth_A
out dx,al
mov dx,Fourth_B
out dx,al
jmp stop1
stop1:
pop bx
pop dx
ret
Xiaodou2 endp
Disp2 proc near;数码管显示部分
push bx
cmp al,08h;将al和08h进行比较
jb up;up范围为00-07
jmp down;down范围为08-0f
Up:
mov bl,al
mov bh,00h
mov al,LED[bx]
mov ah,current_up_led
or al,ah
mov current_up_led,al;更新上升数据
mov dx,Fourth_A
out dx,al
jmp stop1
Down:
sub al,08h
mov bl,al
mov bh,00h
mov al,LED[bx]
mov ah,current_down_led
or al,ah
mov current_down_led,al;更新上升数据
mov dx,Fourth_B
out dx,al
Stop1:
pop bx
ret
Disp2 endp
;--------------------------------------------------
Stop_running proc near;这里要使用中断不然不能不能使用
mov num,00h
mov out_num,00h
mov ordered_num,00h
mov al,00h;这里不应该只对应显示功能在后面的停止电梯中页应该用到
mov dx,First_A
out dx,al
mov dx,Fourth_A
out dx,al
mov dx,Fourth_B
out dx,al
mov current_led,al
mov current_up_led,al
mov current_down_led,al
ret
stop_running endp
Wait_5s proc near;软件延时程序
push cx
push ax
mov cx,0ffh
D1:
mov ax,0fffh
D2:
dec ax
jnz d2
loop d1
pop ax
pop cx
ret
Wait_5s endp
;-------------------------------------------------------
Process proc near;分四种情况,改变seq中数据存放的顺序
push ax
push bx
push cx
push dx
;-----------------------------------------------
Next_pro:;显示原始数据
;-----------------------------------------------
;先对其进行正序排序
;--------------------------------------
lea di,seq
mov cl,num;cx为比较轮数,大循环次数
mov ch,00h
mov sort_dir,00h;选择正向排序
call bubble
;--------------------------------------
lea di,outside
mov cl,out_num;cx为比较轮数,大循环次数
mov sort_dir,00h;选择正向排序
call Bubble
;-----------------------------------------------
;判断最大值部分
;还有一种情况内部没有按键的情况根据外面的按键确定也是上优先于下
mov bl,num
mov bh,00h
cmp bx,00h
je find_out_max
dec bx
mov al,seq[bx]
mov max,al
jmp max_dir
Find_out_max:
;分成两部分一部分是上行楼层的最大值,一部分是下行楼层的最大值
mov bl,out_num
mov bh,00h
cmp bx,00h;两个数组都为0,直接结束
je end_pro
dec bx
;---------------------------------------------
;ah中保存下行楼层的最大值
mov ah,outside[bx];最后一个元素不一定是下行的最大值,比如没有下行的情况就是上行的最大值
cmp ah,09h
jb down_max
sub ah,08h
;---------------------------------------------
;dl中保存下行楼层的最大值,还需要考虑没有下行的情况
Down_max:
inc bx
mov cx,bx
mov dl,00h;如果没有元素的话可以保存
lea di,outside
Loop_find:
mov al,[di]
cmp al,09h;如果没有下行的情况直接就退出了
jae compare_up_down;超出范围了
mov dl,[di]
inc di
loop loop_find
Compare_up_down:
cmp ah,dl
jb up_big
mov max,ah
jmp max_dir
Up_big:
mov max,dl
;-----------------------------------------------
;加入的重要的判断运行方向部分
;判断当前楼层是否大于最大值,下行
;判断当前楼层是否小于最小值,上行
;如果最大值等于当前楼层也是要下行的因为已经派出了只有一个目标楼层的情况
;其实只需要判断一种情况即下行的情况即可其余都为上行
Max_dir:
mov al,max
mov ah,current_floor
dec ah;current_floor要改为从0开始
cmp ah,al
jae down_running
jmp up_running
down_running:;确定运行方向上行
mov al,00h
mov dir,al;改变dir,00h表示下行
jmp Down_sorted
up_running:;确定运行方向下行
mov al,01h
mov dir,al;改变dir,01h表示上行
;-----------------------------------------------
;要先对其进行拍好顺序
Up_sorted:;正方向的排序
;a.内部按键大于当前楼层和外部按键高于当前楼层上行
;b.所有外部按键的下行和内部按键低于当前楼层
;c.外部按键低于当前楼层的上行
;-----------------------------------------------
;a.内部按键大于当前楼层和外部按键高于当前楼层上行
;排序Seq中的数据
lea di,seq;di表示内部按键
lea si,tmp;si表示临时存储空间
mov cl,num
mov ch,00h
cmp cx,00h
je up_out_a
mov al,current_floor
dec al
Loop_seq_up1:
cmp al,[di]
ja back_seq_up_loop1;大于的话不加入
mov ah,[di]
call add_to_tmp;小于等于皆可
Back_seq_up_loop1:
inc di
loop Loop_seq_up1
;排序Outside中的数据,并且必须是上行方向,自动满足了
Up_out_a:
lea di,Outside
mov cl,out_num
mov ch,00h
cmp cx,00h
je end_up_a
mov al,current_floor
dec al
Loop_out_up1:
cmp al,[di];al=04h
ja back_out_up_loop1
mov ah,09h
cmp ah,[di]
jbe back_out_up_loop1;09h小于等于[di]说明是下行0不加入
mov ah,[di]
call add_to_tmp;要小于09h且大于等于current_floor的值
Back_out_up_loop1:
inc di
loop Loop_out_up1
;--------------------------------------
;先对ordered中的数据进行排序
lea di,tmp
mov cl,tmp_num;cx为比较轮数,大循环次数
mov sort_dir,00h;选择正向排序
call bubble
;--------------------------------------
;再删除排好序之后重复的元素
lea di,tmp
mov cl,tmp_num;cx为比较轮数,大循环次数
call delete_repeat
mov tmp_num,dh
;--------------------------------------
End_up_a:
call move_tmp_order;需要进行排序排序以后去除重复的元素
call clear_tmp
;--------------------------------------------------
;b.所有外部按键的下行和内部按键低于当前楼层
lea di,seq
lea si,tmp
mov cl,num
mov ch,00h
cmp cx,00h
je up_out_b
mov al,current_floor
dec al
Loop_seq_up2:
cmp al,[di]
jbe back_seq_up_loop2;大于等于的话不加入
mov ah,[di]
call add_to_tmp;小于加入
Back_seq_up_loop2:
inc di
loop Loop_seq_up2
;排序Outside中的数据,加入所有方向向下的元素
Up_out_b:
lea di,Outside
mov cl,out_num
mov ch,00h
cmp cx,00h
je end_up_b
Loop_out_up2:
mov al,[di]
cmp al,09h
jb back_out_up_loop2;小于09h的都是上行,不加入
sub al,08h;上行因此要减去09h
mov ah,al
call add_to_tmp;加入所有下行元素
Back_out_up_loop2:
inc di
loop Loop_out_up2
;--------------------------------------
End_up_b:;如果只有一个元素有的话只需要倒序,其实不需要去除重复
lea di,tmp
mov cl,tmp_num;cx为比较轮数,大循环次数
mov sort_dir,01h;选择正向排序
call bubble
;;--------------------------------------
lea di,tmp
mov cl,tmp_num;cx为比较轮数,大循环次数
call delete_repeat
mov tmp_num,dh
;--------------------------------------
call move_tmp_order
call clear_tmp
;--------------------------------------------------
;c.外部按键低于当前楼层的上行
;外部按键低于当前楼层的上行
lea di,Outside
mov cl,out_num
mov ch,00h
cmp cx,00h
je end_up_c
mov al,current_floor
dec al
Loop_out_up3:
cmp [di],al
jae back_out_up_loop3
mov ah,[di]
call add_to_tmp;小于al且上行
Back_out_up_loop3:
inc di
loop Loop_out_up3
call move_tmp_order
call clear_tmp
;--------------------------------------
lea di,ordered
mov cl,ordered_num;cx为比较轮数,大循环次数
call delete_repeat
mov ordered_num,dh
End_up_c:
jmp end_pro
;--------------------------------------------------
Down_sorted:;先向下运行的结果
;a.内部按键小于当前楼层和外部按键低于当前楼层下行
;b.所有外部按键的上行
;c.外部按键高于当前楼层的下行
;--------------------------------------------------
;a步骤
;排序Seq中的数据
lea di,seq;di表示内部按键
lea si,tmp;si表示临时存储空间
mov cl,num
mov ch,00h
cmp cx,00h
je down_out_a
mov al,current_floor
dec al
Loop_seq_down1:;不需要比较全部加入
mov ah,[di]
call add_to_tmp
inc di
loop Loop_seq_down1
;排序Outside中的数据,并且必须是下行方向,且低于当前楼层
Down_out_a:
lea di,Outside
mov cl,out_num
mov ch,00h
cmp cx,00h
je end_down_a
mov al,current_floor
dec al
add al,08h;要加上08h才可以比较
Loop_out_down1:
mov dl,[di]
cmp dl,09h
jb back_out_down_loop1;小于09h表示上行
cmp al,[di];只加入小于等于当前楼层的楼层
jb back_out_down_loop1
mov ah,[di]
sub ah,08h
call add_to_tmp;要小于09h且大于等于current_floor的值
Back_out_down_loop1:
inc di
loop Loop_out_down1
End_down_a:
;--------------------------------------
;先对ordered中的数据进行排序
lea di,tmp
mov cl,tmp_num;cx为比较轮数,大循环次数
mov sort_dir,01h;选择反向排序
call bubble
;--------------------------------------
;再删除排好序之后重复的元素
lea di,tmp
mov cl,tmp_num;cx为比较轮数,大循环次数
call delete_repeat
mov tmp_num,dh
;--------------------------------------
call move_tmp_order;需要进行排序排序以后去除重复的元素
call clear_tmp
;--------------------------------------------------
;b步骤
;所有外部按键的上行
lea di,Outside
mov cl,out_num
mov ch,00h
cmp cx,00h
je end_down_b
Loop_out_down2:
mov al,[di]
cmp al,09h
jae back_out_down_loop2;小于09h的都是下行,不加入
mov ah,al
call add_to_tmp;加入所有下行元素
Back_out_down_loop2:
inc di
loop Loop_out_down2
;--------------------------------------
call move_tmp_order
call clear_tmp
End_down_b:
;--------------------------------------------------
;c步骤
;外部按键高于当前楼层的下行
lea di,Outside
mov cl,out_num
mov ch,00h
cmp cx,00h
je end_down_c
mov al,current_floor
dec al
add al,08h
Loop_out_down3:
cmp [di],al
jbe back_out_down_loop3;大于al且下行
mov ah,[di]
sub ah,08h
call add_to_tmp;小于al且上行
Back_out_down_loop3:
inc di
loop Loop_out_down3
;--------------------------------------
;先对tmp中的数据进行反序
lea di,tmp
mov cl,tmp_num;cx为比较轮数,大循环次数
mov sort_dir,01h;选择反向排序
call bubble
;--------------------------------------
call move_tmp_order;移动
call clear_tmp
;--------------------------------------
lea di,ordered;ordered整体去重
mov cl,ordered_num;cx为比较轮数,大循环次数
call delete_repeat
mov ordered_num,dh
;--------------------------------------
End_down_c:
jmp end_pro
end_pro:
;------------------------------------------
;测试显示部分
;mov row,01h;设置行
;mov line,00h;设置列
;mov bx,00h
;mov al,ordered[bx]
;call show_number
;mov cl,ordered_num
;mov ch,00h
;lea di,ordered
;Loop_ascii:
;mov al,[di]
;add al,'0'
;mov [di],al
;inc di
;loop loop_ascii
;
;lea di,ordered
;mov cl,ordered_num
;call show_string
;jmp $
;--------------------------------------------
pop dx
pop cx
pop bx
pop ax
ret
Process endp
Add_to_tmp proc near;加入tmp中
mov [si],ah
inc si
inc tmp_num
ret
Add_to_tmp endp
Clear_tmp proc near;清除
mov tmp_num,00h
lea si,tmp
ret
Clear_tmp endp
Move_tmp_order proc near;将tmp中的数据转移到ordered中保存
mov cl,tmp_num
mov ch,00h
cmp cx,00h;tmp中没有元素不需要转移
je exit
mov bl,ordered_num
mov bh,00h
lea si,tmp
Loop_move:
mov al,[si]
mov ordered[bx],al
inc bx
inc si
inc ordered_num
loop loop_move
exit:
ret
Move_tmp_order endp
;-----------------------------------------------
Bubble proc near;冒泡排序
cmp cx,01h;小于等于1说明不需要使用冒泡排序
jbe end_bubble
mov si,di;备份di中的数据
;冒泡排序部分
mov ch,00h
dec cx
Loop_sort1:
mov dx,cx;dx表示大循环次数
;mov bx,0;地址指针
;lea di,seq
mov di,si
Loop_sort2:
;mov al,seq[bx]
mov al,[di]
;cmp al,seq[bx+1]
cmp sort_dir,01h
je ir_dir
cmp al,[di+1]
jbe no_change
Loop_back:
;xchg al,seq[bx+1]
xchg al,[di+1]
;mov seq[bx],al;在这里相当于溢出多给num了值
mov [di],al
no_change:
;inc bx
inc di
loop loop_sort2
mov cx,dx;一轮比完之后,cx再次赋值比较轮数
loop loop_sort1
jmp end_bubble
Ir_dir:
cmp al,[di+1]
jae no_change
jmp Loop_back
End_bubble:
ret
Bubble endp
Delete_repeat proc near;数据放在di中,数据长度放在cl中
cmp cl,01h;排除只有无元素和一个元素的情况
jbe end_delete
mov dh,cl;备份一下数据,表示元素的个数
dec cl;真实比较的次数要比实际元素的个数少一个
Loop_delete:
mov al,[di]
cmp al,[di+1]
je delete
Back_loop:;将后面的元素都往前移动
inc di
loop loop_delete
jmp exit
Delete:;如果相等的是最后一个元素的情况
cmp cl,01h
je End_repeat;说明重复的是倒数两个元素
dec dh
push cx
push di
dec cx
;mov cx,01h
Loop_delete2:
mov dl,[di+2]
mov [di+1],dl
inc di
loop loop_delete2
pop di
pop cx
dec cx
jmp back_loop
End_repeat:
dec dh;不需要dec cx了因为已经不会再进行比较了
ret
End_delete:
mov dh,cl
Exit:
ret
Delete_repeat endp
;-------------------------------------------------------
Disp proc near;数码管显示部分
push cx
push bx
mov cl,num;元素的个数放入cl中
mov ch,00h;为后面的loop做准备
mov bh,00h;为后面的bx做序号做准备
lea di,seq;seq的取值为0到7
lea si,led;输出的数据应该是led中的数据
mov al,00h;为之后的与运算做好准备
cmp cl,00h
je stop2
cmp cl,03h
ja lights_out
Loop1:
mov bl,[di];求得当前的序号,下表
or al,led[bx];由下标值求得对应的元素值
inc di
loop loop1
mov dx,First_A
out dx,al
mov current_led,al;保存上一次输出的数据为熄灭做准备
jmp stop2
lights_out:
mov num,00h
mov al,00h;这里不应该只对应显示功能在后面的停止电梯中页应该用到
mov dx,First_A
out dx,al
stop2:
pop bx
pop cx
ret
Disp endp
delay proc near;软件延时程序
push cx
push ax
mov cx,011h
D1:
mov ax,00ffh
D2:
dec ax
jnz d2
loop d1
pop ax
pop cx
ret
delay endp
;-------------------------------------------------
Lcd_main proc near
call Lcd_init
restart:
mov row,00h;设置行
mov line,03h;设置列
lea di,buf1;显示'Welcome'
mov cl,length1
call show_string
ret
Lcd_main endp
Set_cursor proc near
push bx
mov bl,line
mov bh,row
cmp bh,00h
ja row_2;大于说明再第二行
Row_1:
add bl,00h
or bl,80h
mov al,bl
jmp stop
Row_2:
add bl,40h
or bl,80h
mov al,bl
Stop:
pop bx
ret
Set_cursor endp
Show_string_clear proc near;数据在di中,长度在cl中
push ax
push bx
push cx
mov ch,00h
mov cl,05h
call set_cursor;得到的al的结果即为要显示的数据的位置
call Lcd_wcmd
;------------------------------------
mov cl,05h
Loop_clear:
mov al,' '
call Lcd_wdata
loop Loop_clear
pop cx
pop bx
pop ax
ret
show_string_clear endp
Show_string proc near;数据在di中,长度在cl中
push ax
push bx
mov ch,00h
;push cx;将cl压栈
call set_cursor;得到的al的结果即为要显示的数据的位置
call Lcd_wcmd
;------------------------------------
;mov cl,05h
;Loop_clear:
;mov al,' '
;call Lcd_wdata
;loop Loop_clear
;pop cx;将cl出栈
;call set_cursor;重新定位
;call Lcd_wcmd
;------------------------------------
Loop1:
mov al,[di]
call Lcd_wdata
inc di
loop Loop1
pop bx
pop ax
ret
show_string endp
Show_number proc near;根据当前al中的数据判断显示什么数据
push ax
mov ah,'0'
add al,ah
;mov row,00h;设置行
;mov line,02h;设置列
mov [di],al
mov cl,01h
call show_string
pop ax
ret
show_number endp
Lcd_init proc near;初始化函数
mov dx,Second_MODE
mov al,88h;全为输出,C的高位设置成输入模式
out dx,al
mov al,38h;16*2显示,5*7点阵,8位数据接口
call Lcd_wcmd
mov al,0ch;显示器开,光标关闭
call Lcd_wcmd
mov al,06h;文字不动,地址自动+1
call Lcd_wcmd
mov al,01h;清屏
call Lcd_wcmd
ret
Lcd_init endp
Lcd_wcmd proc near;写命令函数,把命令存储在al中
call waitready
mov bl,00h;RS和RW都为低电平表示命令模式,输出
call RW_RS_set
mov bl,01h;先需要设置E为低电平
call E_set
mov dx,Second_A
out dx,al
mov bl,00h;再设E为高电平
call E_set
ret
Lcd_wcmd endp
Lcd_wdata proc near;写数据函数,把数据存储在al中
call waitready
mov bl,01h;RS=1,RW=0表示数据模式,输出
call RW_RS_set
mov bl,01h;先需要设置E为低电平
call E_set
mov dx,Second_A
out dx,al
mov bl,00h;再设E为高电平
call E_set
ret
Lcd_wdata endp
Waitready proc near
push ax
mov dx,Second_A;先输出A口为0ffh
mov al,0ffh
out dx,al
mov bl,02h;RS=0,RW=1表示命令模式,输入
call RW_RS_set
Loop1:
mov bl,01h
call E_set
mov dx,Second_C;从C口读入命令字
in al,dx
test al,80h;与运算判断输入的第八位是否为1
mov bl,00h
call E_set
jnz loop1;高位为1表示还没有处理完
pop ax
ret
Waitready endp
RW_RS_set proc near;对应PB0,PB1,先把数据存在bl中
;00表示RW=RS=0,01表示RW=0,RS=1,02表示RW=1,RS=0
push ax
mov dx,Second_B
mov al,bl
out dx,al
pop ax
ret
RW_RS_set endp
E_set proc near;对应PC4,先把数据存在bl中
push ax
mov dx,Second_C
mov al,bl
out dx,al
pop ax
ret
E_set endp
;-------------------------------------------------------
Timer proc near;产生2ms脉冲信号
push ax
mov dx,MY8253_MODE
mov al,076h;01通道1,11先读写低字节后读写高字节,011方式3,0二进制计数
out dx,al
mov dx,MY8253_COUNT1
mov ah,0f4h;频率为1kHz,计数值为500,高位为01,低位为f4
mov al,ah
out dx,al
mov al,01h
out dx,al
pop ax
ret
Timer endp
Play_music proc near;停止计数器的计数
FREQ:
mov di,[si]
cmp di,0
je stop
call sound
add si,2
add bx,2
jmp freq
Stop:
mov dx,Third_c
mov al,00h;停止播放音乐
out dx,al
ret
Play_music endp
Sound proc near
mov dx,MY8253_MODE
mov al,0b6h;选择通道2,11先读写低字节后读写高字节,011方式3,0二进制计数
out dx,al
mov dx,2
mov ax,307
div di
mov dx,MY8253_COUNT2
out dx,al
mov al,ah
out dx,al
mov ax,[bx]
sloop:
mov cx,0018h
loop $
dec ax
jnz sloop
ret
Sound endp
;-------------------------------------------------------
Running proc near
push bx
push cx
mov row,01h
mov line,04h
lea di,buf6;显示'Run'
mov cl,length6
call show_string_clear
call show_string
mov dx,Third_mode
mov al,10000010B;A口输出,B口输入,C口第四位输出
out dx,al;设置当前8255的模式
mov al,current_floor;al中存储当前楼层
mov ah,aim_floor;ah中存储目标楼层
cmp al,ah
;-----------------------------------------
;mov al,ah
;call show_number
;jmp $
;-----------------------------------------
ja down;当前楼层大于目标楼层下行
jb up;当前楼层小于目标楼层上行
je equal
Down:
mov dl,00h
mov current_dir,dl
mov row,00h
mov line,0bh
lea di,buf3;显示'Down'
mov cl,length3
;call show_string_clear
call show_string
mov dx,Third_A;输出初始值即楼层到计数器
out dx,al
mov dx,Third_C
mov al,03h;PC0=1因为要做减法计数器
out dx,al
call Timer;开始运行
Down_loop:
mov dx,Third_B
in al,dx
;---------------------------------------------
;mov ah,03h
;mov stop_mode,ah
;call stop_running
;---------------------------------------------
cmp al,ah;仍然大于目标楼层
ja down_loop
jmp stop
Up:
mov dl,01h
mov current_dir,dl
mov row,00h
mov line,0bh
lea di,buf2;显示'Up'
mov cl,length2
call show_string
mov dx,Third_A;输出初始值即楼层到计数器
out dx,al
mov dx,Third_C
mov al,02h;PC0=0因为要做加法计数器
out dx,al
call Timer
Up_loop:
mov dx,Third_B
in al,dx
;---------------------------------------------
;mov ah,02h
;mov stop_mode,ah
;call stop_running
;---------------------------------------------
cmp al,ah;仍然小于目标楼层
jb up_loop
jmp stop
Equal:
mov dx,Third_A
out dx,al
Stop:
mov dx,Third_C
mov al,04h;开始播放音乐的同时停止0.5s脉冲的输出
out dx,al
mov Current_floor,ah;更新当前楼层
mov al,ah
;显示部分
mov row,01h
mov line,04h
lea di,buf5;显示'Open'
mov cl,length5
call show_string
;------------------------------------
;播放乐曲部分
mov si,offset tfreq
mov bx,offset tdly
call Play_Music
mov row,00h
mov line,0bh
call show_string_clear;清空up和down
;-------------------------------------
pop cx
pop bx
ret
Running endp
;-------------------------------------------------------
MOV AH,4CH
INT 21H
CODES ENDS
END START