硬件课程设计【微波炉】

需求:

用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

 

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值