需求:
用3个七段教码管分别模拟微波炉的火力以及时间,两个数码管模拟时间(分),一个数码管模拟档位。在输入模式下,用户自定义要工作的时间以及档位,设置好之后拨动启动开关,开始工作,此时时间开始计时(时间递减),当时间减到00后,系统完成工作。
原理:
用8255的A和B口作为输出分别控制七段数码管显示的时间和档位,用Co低4位作 为输出控制数码管的位码,然后用仅剩的c口高四位作为时间及档位的输入还有整个程序的启动。具体连线图如下:
分工:
我们组一共四个人,我主要负责软件,也就是写代码的,下面是软件的流程图:
代码:
经过这一次课设,我对汇编语言的编写和调试有了很大程度的提高(微机原理期末感觉不用愁0.0),下面我就给我的代码做个介绍,以防后面翻出来啥都看不懂......
变量介绍:
didas:中间抄了一段延迟子程序中的一个变量;
num:存储0~9的段码(不知道的百度下,就是给数码管传相应的段码,才能显示相应的数字);
tens:存储时间的十位数(存储的其实是段码);
single:存储时间的个位数(存储的其实是段码);
fire:存储档位(存储的其实是段码);
number:存储的是当前的剩余工作时间(十进制);
firelevel:存储的是档位(但是这个是十进制的数字)。
子程序介绍:
divide proc near
;保存信息
push di
push ax
push bx
push cx
push si
;将数字初除以10 商保存在al中,余数保存在ah中
xor ax,ax
xor bx,bx
xor cx,cx
mov al,number[0]
mov bl,0ah
div bl ;商在al,余数在ah
mov cx,ax
lea bx,num
xor ax,ax
mov al,ch
;获得实际待显示的数码管的地址
add bx,ax ;加al
lea si,tens
mov al,[bx]
;将该地址中的值赋值给tens,即十位
mov [si],al
lea bx,num
xor ax,ax
mov al,cl
;获得实际待显示的数码管的地址
add bx,ax
lea si,single
mov al,[bx]
;将该地址中的值赋值给single,即个位
mov [si],al
lea bx,num
xor ax,ax
mov al,firelevel[0]
add bx,ax
lea si,fire
mov al,[bx]
mov [si],al
pop si
pop cx
pop bx
pop ax
pop di
ret
divide endp
功能:
(1):将number变量分割成十位和个位,再将它们的段码分别存储到tens和single中;
(2):将firelevel里的十进制数对应的段码存到fire里面;
这样做了之后,show函数就可以直接从tens、single和fire里面取段码来显示到数码管里,并且你在修改时间和档位的值时可以直接修改number和firelevel的值,只要在调用show显示之前调用一下divide就可以了。
具体分割两位数的方法是number除10,用sub指令,商和余数都存在了AX里面,也比较方便。
show proc near
;显示时间和档位子程序
;让三个灯先熄灭
mov dx,0604h
mov al,11111111b
out dx,al
;显示十位数
mov dx,0602h
lea si,tens
mov al,[si]
out dx,al
mov dx,0604h
mov al,11111101b
out dx,al
;调用延迟子程序
call showdelay
;熄灭数码管
mov dx,0604h
mov al,11111111b
out dx,al
;再点亮个位数码管
mov dx,0602h
lea si,single
mov al,[si]
out dx,al
mov dx,0604h
mov al,11111110b
out dx,al
;调用延迟子程序
call showdelay
;熄灭数码管
mov dx,0604h
mov al,11111111b
out dx,al
;再点亮档位数码管
lea si,fire
mov al,[si]
mov dx,0600h
out dx,al
mov dx,0604h
mov al,11111011b
out dx,al
ret
show endp
功能:显示两位时间和一位档位,所读取的存储数据是tens(十位数)、single(个位数)和fire(档位),它们里面经过divide的调整都变成段码了。
坑:
(1)多数码管显示的时候不要一次全显示,这样它每个位只会显示同一个数,我做这个之前想了好久最后不知道在哪看到的:多位数码管显示时是动态显示的,拿两位数码管来说,先熄灭所有数码管,再显示一位数码管,再熄灭它,然后显示另一个数码管,然后循环执行,这样会给人造成一种显示多位数码管的错觉,但实际上同一时刻只显示一位数码管;
(2)注意你的芯片的端口地址对不对,我们学校实验室的8255端口地址是0600~0606h,不对的话没反应的。
;输入时间和档位的信息
inputWait proc near
;判断是否有按键按下
mov dx,0604h
in al,dx
and al,01110000b
cmp al,00000000b
call showdelay
mov dx,0604h ;再判断一次有没有按下键
in al,dx
and al,01110000b
cmp al,00000000b
jz next1 ;相等表示无按键按下
;判断是不是档位加按键
mov dx,0604h
in al,dx
and al,01000000b
cmp al,01000000b
jz firelevelAdd
jz next1
;判断是不是时间减按键
mov dx,0604h
in al,dx
and al,00010000b
cmp al,00010000b
jz numberSub
jz next1
;判断是不是时间加按键
mov dx,0604h
in al,dx
and al,00100000b
cmp al,00100000b
jz numberAdd
next1:
ret
inputWait endp
功能:判断用户按下的是哪个键。
只说一个问题:第一次判断时为啥要判断两次?原因是按键和开关不一样,他只有一瞬间的高电平,但这一瞬间很可能是碰撞或者其他原因引起的,判断两次就可以确定是按键了,而不是其他原因。
其余的子程序就没啥好说的了,主程序有兴趣的可以看看跳转关系,写的也不是很好,总的代码在下面(可以跑的,前提是端口地址可硬件连线得正确)
didas equ 18
DATAS SEGMENT
num db 3fh,06h,5bh,4fh,66h,6dh,7dh,07h,7fh,6fh;数码显示管对应的0~9
tens db 0 ;十位数
single db 0 ;个位数
fire db 1 ;火力等级
number db 25
firelevel db 1
Times dw 0,0
DATAS ENDS
STACKS SEGMENT
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
;======================
main proc near
MOV AX,DATAS
MOV DS,AX
call init
next3:
call divide
call show
;判断PC7是0还是1
mov dx,0604h
in al,dx
and al,10000000b
cmp al,00000000b ;0为输入
jz input
jnz next
jmp next3
input: ;输入
call divide
call show
call inputWait
call delay1s
;判断PC7是0还是1
mov dx,0604h
in al,dx
and al,10000000b
cmp al,00000000b ;0为输入
jz input
next:
call divide
call show
call delay1s
call numberSub
;判断是否是输入
mov dx,0604h
in al,dx
and al,10000000b
cmp al,00000000b ;0为输入
jz input
jmp next
ret
main endp
;======================
;;;;;;;;;;;;;;;;;;;;;;;
numberAdd proc near
;时间加1
push si
mov al,number[0]
lea si,number
add al,1
mov [si],al
pop si
ret
numberAdd endp
;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;
;输入时间和档位的信息
inputWait proc near
;判断是否有按键按下
mov dx,0604h
in al,dx
and al,01110000b
cmp al,00000000b
call showdelay
mov dx,0604h ;再判断一次有没有按下键
in al,dx
and al,01110000b
cmp al,00000000b
jz next1 ;相等表示无按键按下
;判断是不是档位加按键
mov dx,0604h
in al,dx
and al,01000000b
cmp al,01000000b
jz firelevelAdd
jz next1
;判断是不是时间减按键
mov dx,0604h
in al,dx
and al,00010000b
cmp al,00010000b
jz numberSub
jz next1
;判断是不是时间加按键
mov dx,0604h
in al,dx
and al,00100000b
cmp al,00100000b
jz numberAdd
next1:
ret
inputWait endp
;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;
;火力等级加1
firelevelAdd proc near
push si
mov al,firelevel[0]
lea si,firelevel
add al,1
mov [si],al
cmp al,10
jnz firelevelnext
mov al,1
mov [si],al
firelevelnext:
pop si
ret
firelevelAdd endp
;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;
;初始化8255及数据段
init proc near
mov dx,0606h
mov al,10001000b
out dx,al
ret
init endp
;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;
;number减1
numberSub proc near
push si
mov al,number[0]
lea si,number
cmp al,0
jz next2
sub al,1
mov [si],al
pop si
next2:
ret
numberSub endp
;;;;;;;;;;;;;;;;;;;;;;;
;*****************************************
;利用偏移量取出数码管对应的要显示的编码
divide proc near
;保存信息
push di
push ax
push bx
push cx
push si
;将数字初除以10 商保存在al中,余数保存在ah中
xor ax,ax
xor bx,bx
xor cx,cx
mov al,number[0]
mov bl,0ah
div bl ;商在al,余数在ah
mov cx,ax
lea bx,num
xor ax,ax
mov al,ch
;获得实际待显示的数码管的地址
add bx,ax ;加al
lea si,tens
mov al,[bx]
;将该地址中的值赋值给tens,即十位
mov [si],al
lea bx,num
xor ax,ax
mov al,cl
;获得实际待显示的数码管的地址
add bx,ax
lea si,single
mov al,[bx]
;将该地址中的值赋值给single,即个位
mov [si],al
lea bx,num
xor ax,ax
mov al,firelevel[0]
add bx,ax
lea si,fire
mov al,[bx]
mov [si],al
pop si
pop cx
pop bx
pop ax
pop di
ret
divide endp
;***************************************
;;;;;;;;;;;;;;;;;;;;;;;
show proc near
;显示时间和档位子程序
;让四个灯先熄灭
mov dx,0604h
mov al,11111111b
out dx,al
;显示十位数
mov dx,0602h
lea si,tens
mov al,[si]
out dx,al
mov dx,0604h
mov al,11111101b
out dx,al
;调用延迟子程序
call showdelay
;熄灭数码管
mov dx,0604h
mov al,11111111b
out dx,al
;再点亮个位数码管
mov dx,0602h
lea si,single
mov al,[si]
out dx,al
mov dx,0604h
mov al,11111110b
out dx,al
;调用延迟子程序
call showdelay
;熄灭数码管
mov dx,0604h
mov al,11111111b
out dx,al
;再点亮档位数码管
lea si,fire
mov al,[si]
mov dx,0600h
out dx,al
mov dx,0604h
mov al,11111011b
out dx,al
ret
show endp
;;;;;;;;;;;;;;;;;;;;;;;
showdelay proc near
;显示时间延迟子程序
push cx
mov cx,10
mylelay:
loop mylelay
pop cx
ret
showdelay endp
;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;
delay1s proc near
push cx
push ax
mov cx,0606h
t1:
call divide
call show
mov ax,019fh
t2:
dec ax
jnz t2
loop t1
pop ax
pop cx
ret
delay1s endp
;;;;;;;;;;;;;;;;;;;;;;;
CODES ends
end START