十字路口交通信号灯控制系统电信
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
一、实验目的:
利用8086、8253、8255及8279实现交通信号灯控制,它能实现:
(1)模拟有南北与东西两个方向,每个方向有红黄绿三个灯;
(2)南北向:红(20秒),黄(5秒),绿(20秒);
东西向:红(20秒),黄(5秒),绿(20秒);
灯的变化规律与实际路口规律相同,绿灯在最后5秒钟时,黄灯亮,然后红
灯亮,两个方向不会亮绿灯;
(3)灯的时间显示在数码管上进行显示,显示规律是先显示红绿灯的剩余时间,黄灯亮时显示黄灯剩余时间;
(4)可以通过一个开关控制,当开关信号为1时,整个交通灯全灭,并且数码管显示为0,开关撤销后,按照开关按下之前的状态继续运行;
(5)有一个紧急控制开关信号,当紧急开关信号为1时,两个方向的灯全为红灯。
紧急开关撤消后,按照开关按下之前的状态继续运行;
二、实验内容:
首先要实现对6个灯进行控制就要用到intel8255A并行通信接口,可设置在工作
方式0(基本的输入/输出方式)下,用B端口进行输入C端口进行输出。
要使红绿灯持续亮20s黄灯亮5s,就必须用到延时程序,这就要用到intel8253了,
可以使8253的计数器工作在方式3(方波发生器)提供周期为2秒的时钟信号,在B端
口选择一口如PB3口进行2秒时钟信号的输入。
延时程序方面可利用这2s时钟信号,可
以实现1s的延迟,具体方法是先初始化8253立即检测PB3口的输入信号是否为高电平,
如果是则说明还没有通过8253的第一个方波的半个周期即还没到1s,继续检测直到到1s,
这样就实现了1s的延迟。
要实现延迟N秒如20s,只要延迟20个1s即可,在每次延迟
1s前初始化一下8253即可,这样的延迟程序可以延迟任意的时间。
接下来要解决的是交通灯全灭和紧急情况控制两种情况,只要用8255的B端口的
两个口即可,当检测到这两个端口为高电平时,用C端口输出相应的电平来实现红绿灯
全灭和只有红灯亮。
接下来要在数码管上显示剩余时间,要编一个显示子程序,这里要用到Intel8279
芯片了,在EL-MUT-III 型单片机上8279芯片和数码管内部是连好的,给它一个数它会
通过用给定的数码管显示码表进行译码从而在数码管上显示这个数,但是只是一片数码管
显示即只能显示一位。
这次实验要求显示两位数,我用了个div指令,具体为mov cl,10 div cl,这样就把数除以10,十位放到al中,个位加十位放到ah中,这样就把两位数
变成两个一位数可以在两片数码管上显示,达到目的。
至于紧急开关撤消后,按照开关按下之前的状态继续运行,只要在调用紧急控制程
序前把这时灯的状态存起来,到用完后再恢复即可。
以上是对如何完成这次实验的基本考虑,实际编程过程中还遇到很多问题,不过已
解决。
实验程序:
io8255a equ 04a0h
io8255b equ 04a2h
io8255c equ 04a4h
io8255ctrl equ 04a6h
io8253a equ 04b0h
io8253b equ 04b2h
io8253ctrl equ 04b6h
con8279 equ 0492h
dat8279 equ 0490h
assume cs:code
code segment public
org 100h
start:
led db 3fh,06h,5bh,4fh,66h,6dh,7dh,07h,7fh,6fh ;显示段码表
call init8253 ;初始化8253 mov dx,io8255ctrl ;8255控制口
mov al,82h ;工作方式0 A,C口输出,B口输入
out dx,al
;---------------------------------------------------------- repeat: ;以下为主程序
mov al,11000011b ;南北路口绿灯亮,东西路口红灯亮
mov dx,io8255c ;C端口地址
out dx,al
mov bh,al ;保存这时灯的状态
mov cl,20 ;设置延迟时间为20s
call delay ;调用延迟程序
mov al,10100011b ;南北路口黄灯亮,东西路口红灯亮
out dx,al
mov bh,al ;保存这时灯的状态
mov cl,5 ;设置延迟时间为5秒
call delay ;调用延迟程序
mov al,01100110b ;南北路口红灯亮,东西路口绿灯亮
out dx,al
mov bh,al ;保存这时灯的状态
mov cl,20 ;设置延迟时间为20s call delay ;调用延时程序 mov al,01100101b ;南北路口红灯亮,东西路口黄灯亮 out dx,al
mov bh,al ;保存这时灯的状态 mov cl,5 ;设置延迟时间为5s call delay ;调用延迟程序 jmp repeat ;跳转到主程序;-------------------------------------------------------------
delay: ;延迟程序 push ax ;将用到的寄存器放入堆栈 push dx
mov ch,cl ;读延迟时间lop: cmp ch,0 ;看延迟时间是否为0 jz exit ;是,则跳转到exit call init8253 ;初始化8253 wait1s:
mov dx,io8255b ;读PB口 in al,dx
and al,00000001b ;判断PB0是否为1 cmp al,0
jz next ;是则跳到下一步 call emergency ;不是则调用emergency next:
in al,dx
and al,00000010b ;判断PB1是否为1 cmp al,0
jz next1 ;是则跳到下一步 call turnoff ;不是则调用turnoff next1:
call display ;调用display mov dx,io8255b ;读B口 in al,dx
and al,00001000b ;判断PB3是否为0 cmp al,0
jnz wait1s ;不是则则表示还没到一秒,等待 dec ch ;延时长度减一 jmp lop
exit: ;把寄存器推出堆栈 pop dx
pop ax
ret
;---------------------------------------------------------- display: ; 显示子程序
push ax ;将用到的寄存器放入堆栈
push bx
push cx
push dx
mov di,offset led ;载入段码表
mov ax,08h ;工作方式,16位,左入 mov dx,con8279
out dx,ax
mov ax,90h
mov dx,con8279
out dx,ax ;写显示RAM命令,地址自增
mov dx,dat8279
mov cl,10 ;设置除数
mov al, ch ;;要显示的数为ch的值
mov ah,0
div cl ;除10,求出十位及个位,商(即十位)在AL,
;余数(即个位)与个位的加和在AH
sub ah,al ;减命令,使ah保存要显示的数的个位
mov bl,ah ;把ah的值付给bl,原因在下面
mov cl,al ;把al的值付给cl
mov bh,0 ; bx高8位至零
mov ch,0 ; cx高8位至零
add di,cx ;因为di为16位的实现加命令也必须是16位
;这就是为什么把十位赋给cx,并且di对应
;码表初值0,要想对应cx的值必须加上cx mov al,cs:[di] ;进行译码,把值付给al
mov ah,0
out dx,ax ;显示出要显示数的十位
mov dx,dat8279 ;以下为显示个位命令
add di,bx
mov al,cs:[di]
mov ah,0
out dx,ax
pop dx ;把寄存器推出堆栈 pop cx
pop bx
pop ax
ret ;返回
;---------------------------------------------------------
init8253: ;初始化8253 push dx
push ax
mov dx, io8253ctrl
mov al, 36h ;计数器0方式3 out dx, al
mov ax, 1000 ;初值为1000 mov dx, io8253a
out dx, al
xchg ah, al ;将高8位与低八位对换
out dx, al
mov dx, io8253ctrl
mov al, 76h ;计数器一方式3
out dx, al
mov ax,1500 ;初值1500
mov dx, io8253b
out dx, al
xchg ah, al
out dx, al
pop ax
pop dx
ret
;------------------------------------------------------------- turnoff: ;控制交通灯全灭子程序push ax
push bx
push cx
push dx
mov dx,io8255c ;C端口地址
mov al,0ffh ;交通灯全灭
out dx,al
mov bl,ch ;保存显示数
mov ch,0 ;显示数置0 again:
call display ;调用display显示程序
mov dx,io8255b ;读B口
in al,dx
and al,00000001b ;判断PB0是否为1
cmp al,0
jz noemergency ;是则跳到下一步
call emergency ;不是则调用emergency noemergency:
mov dx,io8255b ;读B口
in al,dx
and al,00000010b ;判断PB1是否为1 cmp al,0
jnz again ;是则跳到again,继续
mov al,bh ;恢复显示灯状态mov dx,io8255c
out dx,al
call init8253 ;初始化8253
mov ch,bl ;恢复显示数
pop dx
pop cx
pop bx
pop ax
ret
;------------------------------------------------------------------- emergency: ;紧急情况控制程序push ax
push bx
push cx
push dx
mov al,ch ;保存显示数
push ax
mov ch,00 ;设置显示数为0
mov dx,io8255c ;C端口地址
mov al,01100011b ;设置两方向红灯亮
out dx,al
mov dx,io8255b ;读B口lop3:
call display ;调用显示子程序
in al,dx
and al,00000001b ;判断PB0是否为1
cmp al,0
jnz lop3 ;是则跳到lop3,继续
mov al,bh ;恢复显示灯状态
mov dx,io8255c
out dx,al
call init8253 ;初始化8253
pop ax
mov ch,al
pop dx
pop cx
pop bx
pop ax
ret
code ends
end start
三、实验连线:
CS0——CS8255、CS1——CS8253、CLK3——8253CLK0、OUT0——8253CLK1
OUT1——PB3、PB0——K1、PB1——K2、PC7——LED1 、PC6——LED2
PC5——LED3 、PC2——LED6、 PC1——LED7、 PC0——LED8
四、实验总结:
一般同学做的交通灯实验只是有红黄绿三个灯在运作,我们做的增加了显示剩余时间功能,还有多了一般现实生活中交通灯都有的功能即:交通灯全灭功能和紧急情况控制功能。
这次实验在程序编写方面遇到了一些问题,调试了很长时间才达到目的。
比如说显示子程序的编写,以前没学过8279芯片,对其功能全然不知,只好上网查询了解了8279的显示原理和显示程序的编写,不过因为要显示的是两位数,这又增加了难度,后来查到div指令可以通过除10把两位变成个位和十位来显示,不过又发现di为16位,如果把ax赋给它,这样又将个位和十位组合起来,还是两位数无法显示,后来想到用其他没用的寄存器代替AX,终于解决了这个问题。
而这只是很多问题中的一个。
通过这次自己设计做实验,感受很深,明白了理论和实际差别很大,你理论上通过了,可真正做实验时却会遇到很多麻烦,当然当你自己把实验做成功后或某一环节搞通后,那种喜悦别人也无法体会。