一、实验名称:十字路口交通灯实验
二、实验目的:
利用51单片机完成模拟正常路口交通灯的运行过程,过程中配备紧急调控按键(路口均为红灯,模拟突发情况禁止路口通行),南北调度按键(紧急调度南北或者东西方向的通行),每个事件结束后,均可以恢复原来的通行秩序,也就是涉及了保护现场和恢复现场。
三、实验平台:
Keil4编写代码,Proteus仿真程序
四、Proteus仿真搭建:
显示路口时间器件我们选择了两位数码管动态显示,动态显示的特点是将所有数码管的段选线并联在一起,通过控制位选信号来控制数码管的点亮。这样一来,就没有必要给每一位数码管配一个锁存器,从而大大简化了硬件电路。数码管采用动态扫描显示,即轮流向各位数码管送出字形码和相应的位选,利用发光管的余辉和人眼的视觉暂留作用,使人感觉好像各位数码管在同时显示,因此亮度比静态显示要差一些,所以在选择限流电阻时应略小于静态显示电路中的限流电阻。
五、程序分析
1、对于需要用到的单片机外设的初始化设置,外设的意义我在初始化函数里写的很清楚了,下面上代码:
void init()
{
second=25; //当前数码管显示南北方向红绿灯初始时间
second1=30; //当前数码管显示东西方向红绿灯时间
TMOD=0x01; // M0=1,M1=0 定时器0设置工作方式为方式1,即16位定时器/计数器
TH0=(65536-50000)/256;//晶振默认为12MHz,所以执行一条指令的时间为1us
TL0=(65536-50000)%256;//这里表示进入一次定时器中断,耗时为50ms
EA=1; //系统允许中断,即开启总中断
ET0=1;//定时0(TR0)定时中断开启位
EX0=1;//外部中断0使能
IT0=1;//外部中断0触发方式为:下降沿触发,即引脚P30接受到一次下降信号,触发外部中断0
EX1=1;//外部中断1使能
IT1=1;//外部中断1触发方式为:下降沿触发,即引脚P31接受到一次下降信号,触发外部中断0
IP=0x02;//定时器0中断优先,这个比较重要,不然默认外部中断0优先级是先于定时器0中断的
TR0=1;//开启定时器0
a=0;
b=0;
c=10;
d=10;
e=10;
f=10;
}
我们在初始化函数里面开启了定时器,开启了定时器中断,开启了外部中断,并且设置了中断的优先级,防止紧急情况定时器中断由于优先级被挡死在外面,导致定时器不进行。其实给abcdef这几个变量的赋值本质上就是一个bool值得关系,是非0即1的关系,所以给这些变量赋值10,或者赋值100,1,18…都是没有影响的。
2、定时器中断:
在定时器中断我们其实只是完成一个定时1s后对设定值second自减(比如南北方向我们设定初始绿灯30s,那么定时器就会在每秒对30这个设定值second自减),在主程序中我们把这个动态的设定值显示在数码管上即可。代码太长我们这里就不全列出来了。
有一点我们讲一下,就是这个程序中标志量c d 为一组,e f 为一组,用来完成紧急事件的定时工作和恢复现场(即按下按键之前各个交通灯是什么值,恢复回来,系统又可以稳定的运行了。)这里以e f(禁止通行标志量)列一下代码吧:
if(e==0)
{
timer3++;
if(timer3==15)
{
timer3=0;
second--;
}
if(second==0)//保护现场
{
a=m;b=n;
e=10;f=10;
second=v;second1=x;
}
if(f==0)
{
timer3++;
if(timer3==15)
{
timer3=0;
second1--;
}
}
3、外部中断:
在仿真图中我们可以很容易的看到我们单片机上的外部中断引脚连接了两个按键,根据初始化函数,按下按键就会触发中断进入外部中断0/1中。
这里我们以外部中断0为例,这个中断是紧急禁行(全是红灯)事件,我们按下按键,进入该中断里:
void waibu0(void) interrupt 0
{
TR0=0;
m=a;n=b;v=second;x=second1;//保存进入外部中断0后,程序的变量大小
second=20; //设定禁止通行时间,并通过数码管显示出来
second1=20;
a=10;b=10; //改变这6个标志位,控制进入定时器中断执行哪些语句
c=10;d=10;
e=0;f=0;
EX0=0; //关闭外部中断,即在此按下不会打断现有状况
EX1=0;
TR0=1;
g=1;r=0;y=1; //改变交通灯,使其均变为红灯
G1=1;R1=0;Y1=1;
}
在这个中断里面有一行指令m=a;n=b;v=second;x=second1;这个指令其实就是我们平时说的保护现场,把进入中断时当前场景的有关变量保存起来,执行完相关命令后,再恢复现场。
再说一下外部中断1函数吧:
void waibu1(void) interrupt 2
{
if(key1==0)
{
TR0=0;
j=second;h=second1;
second=20;
second1=20;
a=10;b=10;
c=0;d=0;
e=10;f=10;
TR0=1;
g=1;r=0;y=1;
G1=0;R1=1;Y1=1;
}
if(key2==0)
{
TR0=0;
j=second;h=second1;
second=20;
second1=20;
a=10;b=10;
c=0;d=0;
e=10;f=10;
TR0=1;
g=0;r=1;y=1;
G1=1;R1=0;Y1=1;
}
}
其实思路和外部中断0里的一样,但是我们这里设计的是在按下这个按键之前就要先选择是哪一路通行,即按下key1或者key2并自锁以后,再按下这个外部中断1按键,才能正常的进行调控,这里是程序不太合理的地方,有时间改改!
4、主程序:
主程序就很简单了,就是数码管的扫描和显示,根据标志位判断路口交通灯的变化。我们这里把程序列一下:
void main()
{
init();
while(1)
{
// P1=0x02;
YOU1=1;ZUO1=0;ZUO2=0;YOU2=0;
P2=~table[second/10];
delay(10);
// P1=0x01;
YOU1=0;ZUO1=1;ZUO2=0;YOU2=0;
P2=~table[second%10];
delay(10);
// P1=0x04;
ZUO1=0;YOU1=0;ZUO2=1;YOU2=0;
P0=~table[second1/10];
delay(10);
// P1=0x08;
ZUO1=0;YOU1=0;ZUO2=0;YOU2=1;
P0=~table[second1%10];
delay(10);
if(a==0)
{g=0;r=1;}
if(a==1)
{y=0;g=1;}
if(a==2)
{r=0;y=1;}
if(b==0)
{R1=0;Y1=1;}
if(b==1)
{G1=0;R1=1;}
if(b==2)
{Y1=0;G1=1;}
}
}
六、实验现象:
其中按键功能我们通过图片不好表示,我又懒得上视频,有时间把程序和仿真图都放出来大家可以自己下载测试一下!
代码及仿真图