如何用单片机设计一个路口通过有交通信号灯的路口?

学习目标:1、了解交通灯的基本工作原理;2、用multisim模拟实现交通灯控制;3、用Keil C51编程实现上述功能;4、用Keil与multisim联调学习内容:通过AT89C51实现对交通灯(十字路口)的管理。除了日常的计时与三色灯交换外还能够通过按键对相应道路进行控制(可控制东北通信、东南通信、全部禁行、南北时间的加减、东西时间的加减与时间的恢复)。大幅度地提高了产品可靠性并降低了制造成本。学习产出:项目工程及仿真资料链接:https://pan.baidu.com/s/1bwVjGAM5-JaNJOPo1lsOJQ 提取码:bhug原理图设计:本实验主要有单片机、8个按键、4组三色灯及电阻、4组二位数码管组成,实现电路如下:项目代码:主函数代码:#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
sbit P1_0 =P1^0;
sbit P1_1 =P1^1;
sbit P1_2 =P1^2;
sbit P1_3 =P1^3;
sbit sn_red=P0^0;
sbit sn__yellow=P0^1;
sbit sn__green=P0^2;
sbit ew_red=P0^3;
sbit ew__yellow=P0^4;
sbit ew_green=P0^5;
sbit key_sourth_north=P3^2;
sbit key_earth_west=P3^3;
sbit all_not=P3^4;
sbit key_sn_add=P3^0;
sbit key_sn_sub=P3^1;
sbit key_ew_add=P3^5;
sbit key_ew_sub=P3^6;
sbit key_reset=P3^7;
uchar code s7_table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
uchar time=30;
uchar timex=33;
uchar time_flag;
uchar timex_flag;
uchar led_change;
uchar led_change1;
uchar yellow_led_flag;
void delay_ms(uchar z)
{
uchar i,j;
for(i=z;i>0;i--)
for(j=110;j>0;j--);
}
void display_time()
{
P1_0=0;P1_1=1;P1_2=1;P1_3=1;
P2=s7_table[timex/10];
delay_ms(2);
P2=0;
P1_0=1;
P1_1=0;
P2=s7_table[timex%10];
delay_ms(2);
P2=0;
P1_1=1;
P1_2=0;
P2=s7_table[time/10];
delay_ms(2);
P2=0;
P1_2=1;
P1_3=0;
P2=s7_table[time%10];
delay_ms(2);
P2=0;
P1_3=1;
}
/*
void display_time1()
{
if(key_sn_add==0
key_sn_sub==1
key_ew_add==1
key_ew_sub==1)
{
P1_0=0;P1_1=1;P1_2=1;P1_3=1;
P2=s7_table[time/10];
delay_ms(2);
P2=0;
P1_0=1;
P1_1=0;
P2=s7_table[time%10];
delay_ms(2);
P2=0;
P1_1=1;
P1_2=0;
P2=s7_table[timex/10];
delay_ms(2);
P2=0;
P1_2=1;
P1_3=0;
P2=s7_table[timex%10];
delay_ms(2);
P2=0;
P1_3=1;
}
}
*/
void init0_timer()
{
TMOD=0X01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
ET0=1;
EA=1;
TR0=1;
}
void south_north_allow()
{
ew_red=0;
ew_green=1;
ew__yellow=1;
sn_red=1;
sn__green=0;
sn__yellow=1;
}
void earth_west_allow()
{
ew_red=1;
ew_green=0;
ew__yellow=1;
sn_red=0;
sn__green=1;
sn__yellow=1;
}
void key_scan()
{
if(key_sourth_north==0)
{
delay_ms(2);
if(key_sourth_north==0)
{
south_north_allow();
while(!key_sourth_north)display_time();
TR0=0;
}
}
if(key_earth_west==0)
{
delay_ms(2);
if(key_earth_west==0)
{
earth_west_allow();
while(!key_earth_west)display_time();
TR0=0;
}
}
if(all_not==0)
{
delay_ms(2);
if(all_not==0)
{
TR0=0;
ew_red=0;
ew_green=1;
ew__yellow=1;
sn_red=0;
sn__green=1;
sn__yellow=1;
}
}
if(key_sn_add==0)
{
delay_ms(2);
if(key_sn_add==0)
{
time=time+2;
while(!key_sn_add)display_time();
}
}
if(key_sn_sub==0)
{
delay_ms(2);
if(key_sn_sub==0)
{
time=time-2;
while(!key_sn_sub)display_time();
}
}
if(key_ew_add==0)
{
delay_ms(2);
if(key_ew_add==0)
{
timex=timex+2;
while(!key_ew_add)display_time();
}
}
if(key_ew_sub==0)
{
delay_ms(2);
if(key_ew_sub==0)
{
timex=timex-2;
while(!key_ew_sub)display_time();
}
}
if(key_reset==0)
{
delay_ms(2);
TR0=1;
}
}
void main()
{
init0_timer();
ew_red=1;
ew_green=0;
ew__yellow=1;
sn_red=0;
sn__green=1;
sn__yellow=1;
yellow_led_flag=2;
while(1)
{
display_time();
key_scan();
}
}
void_int0_isr() interrupt 1
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
time_flag++;
timex_flag++;
if(time_flag==20
timex_flag==20)
{
time_flag=0;
timex_flag=0;
if(time==0)
{
time=30;
if(key_sn_add==0)
{
time++;
}
if(key_sn_sub==0)
{
time--;
}
led_change++;
if(led_change==1)
{
sn_red=0;
sn__green=1;
ew_red=0;
ew_green=1;
ew__yellow=1;
sn__yellow=1;
yellow_led_flag=1;
}
if(led_change==2)
{
led_change=0;
ew_red=1;
ew_green=0;
sn_red=1;
sn__green=1;
ew__yellow=1;
sn__yellow=0;
yellow_led_flag=2;
}
}
else
{
time--;
}
if(time==8)
{
if(yellow_led_flag==2)
{
ew_red=1;
ew_green=1;
sn_red=0;
sn__green=1;
ew__yellow=0;
sn__yellow=1;
}
}
if(timex==0)
{
timex=30;
if(key_ew_add==0)
{
timex++;
}
if(key_ew_sub==0)
{
timex--;
}
led_change1++;
if(led_change1==1)
{
sn_red=1;
sn__green=0;
ew_red=0;
ew_green=1;
ew__yellow=1;
sn__yellow=1;
yellow_led_flag=1;
}
if(led_change1==2)
{
led_change1=0;
ew_red=1;
ew_green=0;
ew__yellow=1;
sn_red=0;
sn__green=1;
sn__yellow=1;
yellow_led_flag=2;
}
}
else
{
timex--;
}
if(timex==8)
{
if(yellow_led_flag==1)
{
ew_red=0;
ew_green=1;
sn_red=1;
sn__green=1;
ew__yellow=1;
sn__yellow=0;
}
}
}
}
实验总结本实验通过51单片机实现了交通灯的显示与时间调节系统。设置南北初始时间为30秒绿灯,东西初始时间为33秒红灯。当绿灯时间剩下8秒时转为红灯。当红灯时间结束时才变绿(注意:红灯转绿灯时不需要先转黄灯)。若烧录时路径有问题,需双击AT89C51单片机重新选择.OBJ文件的路径进行重新模拟烧录代码。当时写这个实验的时候还是个新手,对于交通灯的变化是强制将所有灯按指定的颜色进行转化的。可能多了很多不必需要的代码。最后:希望本博客能在51单片机上给读者一定的帮助,省下找各种解决方案的时间成本。感谢各位观看,如有不足,欢迎在评论内留言与讨论。如果觉得写得好的,可以给我点赞+收藏+关注哦,再次感谢各位!
资源文件夹包含:proteus仿真+原理图;keil编写的C语言程序。资源链接:加我QQ:1271370903一、设计要求及内容该控制系统中,主要由AT89C51单片机芯片、时钟电路、复位电路、数码管显示电路、按键电路、发光二极管LED组成,在正常的情况下东西直行时间为52s运行,黄灯5秒闪烁,东西左转绿灯61秒,最后黄灯5秒闪烁;接着南北直行时间为70s运行,黄灯5秒闪烁,南北左转绿灯64秒,最后黄灯5秒闪烁,依次循环。在遇到特殊交通情况时,需要交通控制人员人工控制系统的运行,通过按键的方式,对系统的指示作出调整。这时复位电路和按键电路都会通过AT89C51单片机的作用,把信号传递给驱动电路,驱动电路控制把信号显示在LED电路中,LED电路又会把信号传递给复位电路,进而实现循环形式的系统控制过程。二、仿真器件清单单片机,排阻,发光二极管 ,晶振 ,电容 ,电阻 ,按键 ,数码管,等,网络标号导线三、组成1、最小应用系统单片机最小系统,或者称为最小应用系统,是指用最少的元件组成的单片机可以工作的系统。2.晶振电路即时钟电路,是AT89C51单片不可或缺的电路,在其工作运行时它起到控制信号的作用。时钟信号对单机片内部电路的影响极大,在它的作用下,单片机会遵循基本的设计原则通过时序指令完成工作。本设计通过数据的分析采用频率为12MHz的晶振,22pF的电容。3.单片机小系统采用上电自动复位和手动按键复位两种方式实现系统的复位操作。所谓复位电路,就是在AT89C51的引脚RET端接入的一个能产生复位信号的电路。单片机在进行工作的同时,把关于内部的数据恢复到原来的参数。数码管时间显示电路4、数码管共阴极数码管是把所有LED的阴极连接到共同接点COM,而每个led的阳极分别为A、B、C、D、E、F、G及DP(小数点),如下图所示。图3-8中的8个led分别与A~DP各段相对应,通过控制各个led的亮灭来显示数字。5、驱动电路数码管显示模块采用2位8段LED共阴数码管。数码管的段码线与单片机P0口相连。为了让数码管的显示更加明显,采用一个驱动模块来驱动数码管,驱动模块由4个NPN管和4个10K的电阻组成。由于对面的数码管的显示是相同的,所以将相对的数码管的位选端接在一起,当需要显示数字时同时选中个位或十位,实现同时显示。其中数码管的显示用到了74HC573锁存器,数码管的段选端连在锁存器的输出端,东西南北的数码管一共用了四个,并连接在第二个锁存器的输出端。锁存器作用是可以把数据输入端与输出端进行隔离或连接。U2为段选锁存器,U3为位选锁存器。由于是共阴极数码管,当数码管亮起时位选端的电流为几个LED的电流之和,设每个数码管段的驱动电流为10ma—15ma,则位选端的电流会很大,如果直接导入锁存器的引脚可能会损坏引脚或减小锁存器的寿命。为了减小导入锁存器引脚的电流,采用三极管将位选端的大部分电流导入GND,极小的电流会导入锁存器的引脚,从而解决了该问题。本文采用PNP三极管作为驱动器驱动数码管的显示,由于每个发光二极管额定电流3-10UA,故在电路中加限流电阻,经计算取该电阻为 330欧姆。其中U2的输出端直接接在数码管上时可能会产生较大的电流,使数码管段烧毁,所以需要串联一个限流电阻。6.根据数码管的驱动方式不同,可以分为静态显示和动态显示两类。本次设计采用的是动态显示驱动,数码管动态显示接口是单片机中应用最为广泛的一种显示方式之一,动态驱动是将所有数码管的8个显示笔段同名端连在一起,另外为每个数码管的公共极 COM增加位选通控制电路,位选通有各自独立的I/O线控制,当单片机输出字型码时,所有数码管都接收到相同的字型码,但究竟是哪个数码管会显示出字形,取决于单片机对位选通COM端电路的控制,所以我们只要将需要显示的数码管的选通控制打开,改为就显示出字形,没有选通的数码管就不会亮。通过分时轮流控制各个数码管的点亮时间为1~2毫秒,由于人的视觉暂留现象及发光二极管的余辉效应,尽管实际上个位数码管并非同时点亮,但只要扫描的速度足够快,给人的印象就是一组稳定的显示数据,不会有闪烁感,动态显示的效果和静态是一样的,能够节省大量的T门端口.而日功耗更低。7、倒计时模块由4个8位数码管来显示等待或者通行时间。为了数码管的倒计时为准确倒计时,所以不能采用平时的delay方法,而是要用更精确的定时器来实现倒计时。在定时器T0中断中的主要工作是将数码管要显示的数字变量每隔一秒自减,然后根据情况使显示数字变量做相应的变化。8.信号灯电路我们在设计初时已给出红绿灯变化的规则:东西直行时间为52s运行,黄灯5秒闪烁,东西左转绿灯61秒,最后黄灯5秒闪烁;接着南北直行时间为70s运行,黄灯5秒闪烁,南北左转绿灯64秒,最后黄灯5秒闪烁,依次循环。交通灯信号显示模块,采用红黄绿三种LED灯模拟十字路口的交通灯。信号灯电路的设计通过AT89C51单片机P1端口的指示,芯片会控制16个发光二极管的信号模式。东西方向的红、黄、绿、左转绿灯分别接到单片机的P1.3、P1.4、P1.5、P1.8,南北方向的红、黄、绿、左转绿灯分别接到单片机的P1.0、P1.1、P1.2、P1.6。9.功能按键电路在实际道路交通中,一定会出现紧急的交通情况,这时系统很难对现场的交通情况进行指挥,这时就需要根据实时交通堵塞情况,进行人为系统控制模式。交通人员可以一边观察一边控制,使系统的控制开关可以起到作用,并能使交通恢复当时适应的状态。为了让交通灯实现基础的功能之外还增加了其他控制功能,而这些其他功能按键组在一起新的电路。该项目一共使用了二个按键,每一个按键都对应一个特定的功能。如第一个按键(夜间模式):此按键按下时,关闭定时器,改变显示标志位,关闭数码管,并在while循环中判断此按键,实现黄灯闪烁。第二个按键(紧急模式):此时四个方向的红灯都亮起。为了节省按键占用的I/O口,也为了去除查询按键的时间占用,减轻CPU的负担,所以按键使用外部中断的方式,通过74LS148扩展中断。此时只需要使用三个I/O口,使用中断的好处是只有触发中断时程序才回去执行按键功能,增加了程序运行的效率。四、整体仿真图1.2、程序流程3.黄灯模式4.紧急模式5.正常模式五、部分代码sbit dula=P3^6;
//段选锁存器锁存端
sbit wela=P3^7;
//位选锁存器锁存端
sbit EW=P1^4;
//东西黄灯
sbit SN=P1^1; //南北黄灯
char time1=52;
//初值东西
char time2=52;
//初值55秒
char huang=5;
//黄灯时间
char time11=70,time22=70; //南北时间70s
char zzz=61,aaa=64;
//东西,南北左转时间
char t1=60,t2=60,chose=0;
uchar time1_2,temp=0,p=0,tab;
uchar shi1,ge1,shi2,ge2,q;
uchar status,key,flag;
uchar zhuangtai_flag=0;
//共阴极数字显示编码
uchar code table[]={0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f};
uchar code wei[]={0xfd,0xfe,0xf7,0xfb,
0xdf,0xef,0x7f,0xbf}; //位选
void delay(uint x)
{
uint i,j;
for(i=x;i>0;i--)
//定时x毫秒
for(j=110;j>0;j--);
}
void display(uint ge1,uint shi1,uint ge2,uint shi2) //数码管显示
{
//显示北
wela=1; //打开位选锁存器
P0=wei[0]; //送入位选码(北个位)
wela=0; //关闭位选锁存器
P0=0;
//消影
dula=1; //打开段选锁存器
P0=table[ge1]; //送入段选
dula=0; //关闭段选锁存器
delay(1);
wela=1; //打开位选锁存器
P0=wei[1]; //送入位选码(北十位)
wela=0; //关闭位选锁存器
P0=0;
dula=1; //打开段选锁存器
P0=table[shi1]; //送入段选
dula=0; //关闭段选锁存器
delay(1);
//显示东西
wela=1; //打开位选锁存器
P0=wei[2]; //送入位选码(东个位)
wela=0; //关闭位选锁存器
P0=0;
dula=1; //打开段选锁存器
P0=table[ge2];
dula=0; //关闭段选锁存器
delay(1);
wela=1; //打开位选锁存器
P0=wei[3]; //送入位选码(东十位)
wela=0; //关闭位选锁存器
P0=0;
dula=1; //打开段选锁存器
P0=table[shi2];
dula=0; //关闭段选锁存器
delay(1);
}
void key1_6()
{ void dis();
//第一个按键(夜间模式)
if(key==3)
{
p=1;
TR0=0;
if(p)
dis();
//不显示函数
P1=0x12 ;
while(1)
{
P1=0x00;
delay(800);
P1=0x12 ;
delay(800);
}
}
if(key==6)
{
temp=0;
//计数值清零
p=0;
TR0=1;
//定时器0开始计时
}
//第二个按键
if(key==7)
//红灯全亮
{
time1=0;
time2=0;
temp=0;
//计数值清零
p=0;
TR0=0;
P1=0x09;
}
}
void dis()
{
wela=1;
P0=0xff;
wela=0;
}
void zhuangtai1()
{
P1=0x21;
//刚开始东西通,南北禁行
if(time1<0)
{
time1=huang;
//东西黄灯时间准备
time2=huang;
zhuangtai_flag=1;
//转状态
}
}
void main()
{
P1=0x21;
//刚开始东西通,南北禁行
TMOD=0x01;
TH0=(65535-10000)/256;
TL0=(65535-10000)%256;
//初值
EA=1;
//打开总中断
ET0=1;
//定时器0允许中断
TR0=1;
//定时器0开始计时
EX0=1;
//外部中断0允许位
IT0=1;
//外部中断0触发方式(下降沿)
while(1)
{
if(flag)
{
switch(status)
//判断按键
{
case 0xfc:key=3;break;
case 0xf9:key=6;break;
case 0xf8:key=7;break;
}
key1_6();
//按键程序
flag=0;
}
if(!p)
{
shi1=time1/10; //南北十位
ge1=time1%10; //南北个位
shi2=time2/10; //东西十位
ge2=time2%10; //东西个位
display(ge1,shi1,ge2,shi2); //显示函数
}

我要回帖

更多关于 通过有交通信号灯的路口 的文章

 

随机推荐