仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
摘 要... I 一、设计要求以及总体方案介绍... 1 1.2交通灯总体方案介绍... 1 1.3元件清单... 2 二、交通灯各模块及程序设计... 2 2.1数码管显示模块... 3 2.2红绿灯模块... 6 2.3按键模块... 6 三、仿真与部分实物演示... 8 3.1南北通行... 8 3.2东西通行... 8 3.3夜间模式... 8 设计心得... 9 附 录... 10
为了节省按键占用的I/O口,也为了去除查询按键的时间占用,减轻CPU的负担,所以按键使用外部中断的方式,通过74HC573扩展中断。此时只需要使用三个I/O口,使用中断的好处是只有触发中断时程序才回去执行按键功能,增加了程序运行的效率。
具体内容见交通灯压缩包,附有源代码,仿真文件,仿真实物视频
1、东西方向、南北方向均有红、黄、绿三种信号灯,初始红灯 30秒,黄灯闪烁3秒,绿灯30秒,东西方向红灯时刻,南北方向绿灯,南北方向绿灯,东西方向红灯;
2、按键调节与控制功能,通过按键,可以控制某一个方向长时间绿灯,另一个方向长时间红灯;通过按键可以调整某一个方向的红灯时长,比如调整东西方向红灯40秒,绿灯20秒,于此同时,南北方向红灯20秒,绿灯40秒。 3、夜间模式按钮按下,所有方向显示黄灯闪烁 4、实时提醒灯亮的剩余时间 1.2 交通灯总体方案介绍
初始状态:东西方向绿灯,南北红灯,南北时间为13秒,东西方向为10秒。 while循环:有按键检测函数,有按键执行程序;数码管显示函数。 定时器T0中断函数:计时时间为50ms,当计时20次计时变量加到20后清零,时间为1s,此时让数码管显示的数自减,判断红绿灯的状态是否需要改变。 外部中断0中断函数:将标志变量flag置1,并读取P2口的值,用以判断按键按下。
1.3 原件清单
名称
| 型号
| 数量
| 单片机
| STC89C52RC
| 1
| 排阻
| 10k/4.7K
| 1
| 发光二极管
| 红黄绿
| 4/4/4
| 晶振
| 12MHZ
| 1
| 电容
| 10uf 30pf
| 1/2
| 电阻
| 10K/1K/0.33K
| 4/7/14
| 按键
| 4脚
| 7
| 数码管
| 两位八段
| 4
| 74HC573/74LS148
|
| 2/1
| 导线
| 15cm
| 若干
| 杜邦线
| 15cm/10cm
| 若干
| 焊锡
|
| 若干
| 单排插针
| SIP20
| 若干
| DIP40芯片座子
|
| 1
| DC插座
|
| 1
| US转DC002电源线
|
| 1
| 三极管
| S9012
| 4
| 万用板
| 7*9cm/9*15cm
| 1/1
| 二、交通灯各模块
2.1 数码管显示模块 对于共阴极数码管来说,当某个发光二极管的阳极为高电平时,发光二极管点亮,相应的段被显示。同样,共阳极数码管的阳极连接在一起,公共阳极接+5V,当某个发光二极管的阴极接低电平时,该发光二极管被点亮,相应的段被显示。共阴极数码 管是把所有led的阴极连接到共同接点COM,而每个led的阳极分别为A、B、C、D、E、F、G及DP(小数点),如下图所示。图中的8个led分别与A~DP各段相对应,通过控制各个led的亮灭来显示数字。
由于对面的数码管的显示是相同的,所以将相对的数码管的位选端接在一起,当需要显示数字时同时选中个位或十位,实现同时显示。 其中数码管的显示用到了74HC573锁存器,数码管的段选端连在锁存器的输出端,东西南北的数码管一共用了四个位选(因为相对的位选连在了一起,所以共四个)并连接在第二个锁存器的输出端。如图所示:
U2为段选锁存器,U3为位选锁存器。由于是共阴极数码管,当数码管亮起时位选端的电流为几个LED的电流之和,设每个数码管段的驱动电流为10ma—15ma,则位选端的电流会很大,如果直接导入锁存器的引脚可能会损坏引脚或减小锁存器的寿命。为了减小导入锁存器引脚的电流,采用三极管将位选端的大部分电流导入GND,极小的电流会导入锁存器的引脚,从而解决了该问题。以下是三极管电路: 还有就是U2的输入端和U3的输入端都是接P0口,在显示数码管时需要切换使能两个锁存器。其中U2的输出端直接接在数码管上时可能会产生较大的电流,使数码管段烧毁,所以需要串联一个限流电阻。 设置数码管段的驱动电流为ID=15ma,这个电流点亮度好,并且有一定的裕度,即使电源输出电压偏高也不会烧毁LED,限流电阻值 R = (VCC-VCE– VOL– VLED) / ID VCC为5v供电,VCE为三极管C、E间饱和电压,估为0.2v,VOL为74hc573输出低电平时电压,不同灌电流,此值不一样,估为0.2v,具体查看规格书,VLED为红光驱动电压,估为1.7v,根据上式可算出限流电阻为R= 200R。为保险起见选用330欧姆的电阻,电流大概在10ma—15ma。 为了数码管的倒计时为准确倒计时,所以不能采用平时的delay方法,而是要用更精确的定时器来实现倒计时。在定时器T0中断中的主要工作是将数码管要显示的数字变量每隔一秒自减,然后根据情况使显示数字变量做相应的变化。 2.2 红绿灯模块 首先要了解红绿灯的亮灭规则:假设南北红灯,东西绿灯,南北的时间为13秒,东西时间为10秒。然后开始倒计时,当东西倒计时为1秒时,此时南北为4秒,下一秒东西变为3秒(和此时的南北一样),然后东西黄灯每隔一秒闪烁一次,两个方向同时倒计时,当时间减为0时南北变为绿灯,东西变为红灯。南北的时间为开始设置的通行时间(假设南北的通行时间为15秒),则东西从18秒(15+3)开始倒计时(因为黄灯的闪烁时间为3秒,所以红灯时间=绿灯时间+黄灯时间)。然后后面和前面的过程一样。 为了让红绿灯能准确的按照准确的“秒”去亮灭,所以此处也要采用定时器来实现。通过代码实现以上功能,代码见附录。 2.3 按键模块 为了让交通灯实现所要求的功能,则需要加独立按键实现。该项目一共使用了七个按键,每一个按键都对应一个特定的功能。如第一个按键(南北通行):此时需要将定时器关闭,定时器不再计数,通过P1口控制南北绿灯亮,东西红灯亮,并改变显示标志位,关闭数码管;第二个按键(东西通行):如第一个按键的功能做细微改变;第三个按键(夜间模式):此按键按下时,关闭定时器,改变显示标志位,关闭数码管,并在while循环中判断此按键,实现黄灯闪烁。第四位和第五位(加减时间):第四位减时间,第五位加时间,负责加减南北通行时间(最低减到00,最高加到99),按下时定时器停止计数,交通灯熄灭,计数变量加或减;第六个按键和第七个按键:第七个按键为切换按键,按下时南北方向切换为东西方向,此时加减时间为东西方向,一次类推:第六个按键为确认键,调整完时间后按下此键交通灯开始运行。(具体程序见附录)
单片机源程序如下:
- #include<reg52.h>
- #define uchar unsigned char
- #define uint unsigned int
- sbit dula=P3^6; //段选锁存器锁存端
- sbit wela=P3^7; //位选锁存器锁存端
- uchar time1=13; //初值南北13秒
- uchar time2=10; //初值东西10秒
- uchar t1=13,t2=10,chose=0;
- uchar time1_2,temp=0,p=0,tab;
- uchar shi1,ge1,shi2,ge2,q;
- uchar status,key,flag;
- //共阴极数字显示编码
- 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()
- {
- //第一个按键(南北通行)
- if(key==1)
- {
- TR0=0; //定时器0停止计时
- P1=0x0c; //南北通行
- p=1; //数码管显示99
- }
- //第二个按键(东西通行)
- if(key==2)
- {
- TR0=0; //定时器0停止计时
- P1=0x21; //东西通行
- p=1;
- }
- //第三个按键(夜间模式)
- if(key==3)
- {
- TR0=0; //关闭定时器
- p=1;
- }
- //第四个按键(减时间)
- if(key==4)
- {
- p=0;
- TR0=0; //定时器0停止计时
- P1=0; //灯灭
- if(chose==0) //减南北方向
- {
- if(time1>0) //最低减到0
- {
- time1--;
- t1=time1;
- }
- }
- if(chose==1) //减东西方向
- {
- if(time2>0)
- {
- time2--;
- t2=time2;
- }
- }
- }
- //第五个按键(加时间)
- if(key==5)
- {
- p=0;
- TR0=0; //定时器0停止计时
- P1=0; //灯灭
- if(chose==0) //加南北方向
- {
- if(time1<99) //最多加到99
- {
- time1++;
- t1=time1;
- }
- }
- if(chose==1) //加东西方向
- {
- if(time2<99)
- {
- time2++;
- t2=time2;
- }
- }
- }
- //第六个按键(加减后确定工作)
- if(key==6)
- {
- if(time1>time2)
- time1=time2+3;
- else
- time2=time1+3;
- temp=0; //计数值清零
- p=0;
- P1=0x21; //南北红灯,东西绿灯
- TR0=1; //定时器0开始计时
- }
- //第七个按键(切换)
- if(key==7)
- {
- p=0;
- chose=!chose;
- }
- }
- void dis()
- {
- wela=1;
- P0=0xff;
- wela=0;
- }
- void main()
- {
- P1=0x21; //刚开始南北的红灯亮,东西的绿灯亮
- TMOD=0x01;
- TH0=(65535-50000)/256;
- TL0=(65535-50000)%256; //初值
- EA=1; //打开总中断
- ET0=1; //定时器0允许中断
- TR0=1; //定时器0开始计时
- EX0=1; //外部中断0允许位
- IT0=1; //外部中断0触发方式(下降沿)
- while(1)
- {
- if(flag)
- {
- switch(status) //判断按键
- {
- case 0xfe:key=1;break;
- case 0xfd:key=2;break;
- case 0xfc:key=3;break;
- case 0xfb:key=4;break;
- case 0xfa:key=5;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); //显示函数
- }
- if(p)
- dis(); //不显示函数
- if(key==3) //夜间模式
- {
- P0=0xff;
- q=!q;
- if(q!=0)
- P1=0x12;
- else
- P1=0;
- delay(200);
- }
- }
- }
- void ext0() interrupt 0
- {
- flag=1;
- status=P2;
- }
- void timer() interrupt 1 //定时中断程序
- {
- TH0=(65535-50000)/256;
- TL0=(65535-50000)%256; //重新赋初值
- temp++;
- if(temp==20) //说明过去了1秒
- {
- temp=0; //清零,重新加到20
- //东西方向南北方向时间自减
- time1--;
- time2--;
- if(time1>time2) //南北大于东西
- {
- time1=time2+3;
- P1=0x21; //南北红灯亮起,东西绿灯亮起
- if(time2==0&&time1==3)
- {
- time2=3; //重新赋南北和东西的差值,与南北方向一起倒计时
- P1=0x11; //东西黄灯亮起,东西绿灯关闭
- tab=0; //标志位
- }
- }
- if(time1<time2) //南北小于东西
- {
- time2=time1+3;
- P1=0x0c; //南北绿灯亮起,东西红灯亮起
- if(time1==0&&time2==3)
- {
- time1=3; //重新赋南北和东西的差值,与东西方向一起倒计时
- P1=0x0a; //南北黄灯亮起,南北绿灯关闭
- tab=1; //标志位
- }
- }
- if(!tab) //黄灯闪烁三秒
- {
- if(time1==2&&time2==2)
- P1=0x01;
- if(time1==1&&time2==1)
- P1=0x11;
- }
- if(tab)
- {
- if(time1==2&&time2==2)
- P1=0x08;
- if(time1==1&&time2==1)
- P1=0x0a;
- }
- if(time1==0&&time2==0&&tab==0) //东西倒计时结束
- {
- time1=t1;
- time2=t1+3;
- P1=0x0c; //东西红灯,南北绿灯
- }
- if(time1==0&&time2==0&&tab==1) //南北倒计时结束
- {
- time1=t2+3;
- time2=t2;
- P1=0x21; //南北红灯,东西绿灯
- }
- }
- }
复制代码
所有资料51hei提供下载:
交通灯.zip
(4.65 MB, 下载次数: 545)
|