找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 14088|回复: 11
收起左侧

51单片机交通灯项目(Proteus仿真及源码)

  [复制链接]
ID:612139 发表于 2019-10-20 09:31 | 显示全部楼层 |阅读模式
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
0.png 0.png

摘 要... 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

  排阻
  
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),按下时定时器停止计数,交通灯熄灭,计数变量加或减;第六个按键和第七个按键:第七个按键为切换按键,按下时南北方向切换为东西方向,此时加减时间为东西方向,一次类推:第六个按键为确认键,调整完时间后按下此键交通灯开始运行。(具体程序见附录)

单片机源程序如下:
  1. #include<reg52.h>
  2. #define uchar unsigned char
  3. #define uint unsigned int
  4. sbit dula=P3^6;          //段选锁存器锁存端
  5. sbit wela=P3^7;          //位选锁存器锁存端

  6. uchar time1=13;  //初值南北13秒
  7. uchar time2=10;  //初值东西10秒
  8. uchar t1=13,t2=10,chose=0;
  9. uchar time1_2,temp=0,p=0,tab;
  10. uchar shi1,ge1,shi2,ge2,q;
  11. uchar status,key,flag;

  12. //共阴极数字显示编码
  13. uchar code table[]={0x3f,0x06,0x5b,0x4f,
  14.                        0x66,0x6d,0x7d,0x07,
  15.                        0x7f,0x6f};
  16. uchar code wei[]={0xfd,0xfe,0xf7,0xfb,
  17.                                   0xdf,0xef,0x7f,0xbf}; //位选

  18. void delay(uint x)
  19. {
  20.                 uint i,j;
  21.                 for(i=x;i>0;i--)                        //定时x毫秒
  22.                         for(j=110;j>0;j--);
  23. }
  24. void display(uint ge1,uint shi1,uint ge2,uint shi2)        //数码管显示
  25. {
  26.         //显示北
  27.         wela=1; //打开位选锁存器
  28.         P0=wei[0];        //送入位选码(北个位)
  29.         wela=0; //关闭位选锁存器
  30.         P0=0;  //消影
  31.         dula=1; //打开段选锁存器
  32.         P0=table[ge1]; //送入段选
  33.         dula=0;        //关闭段选锁存器
  34.         delay(1);

  35.         wela=1; //打开位选锁存器
  36.         P0=wei[1];        //送入位选码(北十位)
  37.         wela=0; //关闭位选锁存器
  38.         P0=0;
  39.         dula=1; //打开段选锁存器
  40.         P0=table[shi1]; //送入段选
  41.         dula=0;        //关闭段选锁存器
  42.         delay(1);

  43.         //显示东西
  44.         wela=1; //打开位选锁存器
  45.         P0=wei[2];        //送入位选码(东个位)
  46.         wela=0; //关闭位选锁存器
  47.         P0=0;
  48.         dula=1; //打开段选锁存器
  49.         P0=table[ge2];
  50.         dula=0;        //关闭段选锁存器
  51.         delay(1);

  52.         wela=1; //打开位选锁存器
  53.         P0=wei[3];        //送入位选码(东十位)
  54.         wela=0; //关闭位选锁存器
  55.         P0=0;        
  56.         dula=1; //打开段选锁存器
  57.         P0=table[shi2];
  58.         dula=0;        //关闭段选锁存器
  59.         delay(1);
  60. }
  61. void key1_6()
  62. {
  63.         //第一个按键(南北通行)
  64.         if(key==1)
  65.         {
  66.                 TR0=0;  //定时器0停止计时
  67.                 P1=0x0c; //南北通行
  68.                 p=1;        //数码管显示99
  69.         }
  70.         //第二个按键(东西通行)
  71.         if(key==2)
  72.         {
  73.                 TR0=0;  //定时器0停止计时
  74.                 P1=0x21; //东西通行
  75.                 p=1;
  76.         }
  77.         //第三个按键(夜间模式)
  78.         if(key==3)
  79.         {
  80.                 TR0=0;  //关闭定时器
  81.                 p=1;
  82.         }
  83.         //第四个按键(减时间)
  84.         if(key==4)
  85.         {
  86.                 p=0;                        
  87.                 TR0=0;  //定时器0停止计时
  88.                 P1=0;        //灯灭
  89.                 if(chose==0)  //减南北方向
  90.                 {
  91.                         if(time1>0)          //最低减到0
  92.                         {
  93.                                 time1--;
  94.                                 t1=time1;
  95.                         }
  96.                 }
  97.                 if(chose==1)  //减东西方向
  98.                 {
  99.                         if(time2>0)
  100.                         {
  101.                                 time2--;
  102.                                 t2=time2;
  103.                         }
  104.                 }
  105.         }
  106.         //第五个按键(加时间)
  107.         if(key==5)
  108.         {
  109.                 p=0;
  110.                 TR0=0;  //定时器0停止计时
  111.                 P1=0;        //灯灭
  112.                 if(chose==0)  //加南北方向
  113.                 {
  114.                         if(time1<99)   //最多加到99
  115.                         {
  116.                                 time1++;
  117.                                 t1=time1;
  118.                         }
  119.                 }
  120.                 if(chose==1)  //加东西方向
  121.                 {
  122.                         if(time2<99)
  123.                         {
  124.                                 time2++;
  125.                                 t2=time2;
  126.                         }
  127.                 }
  128.         }
  129.         //第六个按键(加减后确定工作)
  130.         if(key==6)
  131.         {
  132.                 if(time1>time2)
  133.                         time1=time2+3;
  134.                 else
  135.                         time2=time1+3;
  136.                 temp=0;         //计数值清零
  137.                 p=0;
  138.                 P1=0x21;  //南北红灯,东西绿灯        
  139.                 TR0=1;  //定时器0开始计时
  140.         }
  141.         //第七个按键(切换)
  142.         if(key==7)
  143.         {
  144.                 p=0;
  145.                 chose=!chose;  
  146.         }
  147. }
  148. void dis()
  149. {
  150.         wela=1;
  151.         P0=0xff;
  152.         wela=0;
  153. }         
  154. void main()
  155. {
  156.         P1=0x21;  //刚开始南北的红灯亮,东西的绿灯亮
  157.         TMOD=0x01;
  158.         TH0=(65535-50000)/256;
  159.         TL0=(65535-50000)%256;   //初值
  160.         EA=1;           //打开总中断
  161.         ET0=1;           //定时器0允许中断
  162.         TR0=1;           //定时器0开始计时
  163.         EX0=1;           //外部中断0允许位
  164.         IT0=1;           //外部中断0触发方式(下降沿)
  165.         while(1)
  166.         {
  167.                 if(flag)
  168.                 {
  169.                         switch(status)                   //判断按键
  170.                         {
  171.                                 case 0xfe:key=1;break;
  172.                                 case 0xfd:key=2;break;
  173.                                 case 0xfc:key=3;break;
  174.                                 case 0xfb:key=4;break;
  175.                                 case 0xfa:key=5;break;
  176.                                 case 0xf9:key=6;break;
  177.                                 case 0xf8:key=7;break;
  178.                         }
  179.                         key1_6();   //按键程序
  180.                         flag=0;
  181.                 }        
  182.                 if(!p)
  183.                 {
  184.                         shi1=time1/10;        //南北十位
  185.                         ge1=time1%10;        //南北个位
  186.                         shi2=time2/10;        //东西十位
  187.                         ge2=time2%10;        //东西个位        
  188.                         display(ge1,shi1,ge2,shi2); //显示函数
  189.                 }
  190.             if(p)
  191.                         dis();         //不显示函数
  192.                 if(key==3)          //夜间模式
  193.                 {
  194.                         P0=0xff;
  195.                         q=!q;
  196.                         if(q!=0)
  197.                                 P1=0x12;
  198.                         else
  199.                                 P1=0;
  200.                         delay(200);
  201.                 }
  202.         }  
  203. }         
  204. void ext0() interrupt 0
  205. {
  206.         flag=1;
  207.         status=P2;        
  208. }
  209. void timer() interrupt 1   //定时中断程序
  210. {
  211.         TH0=(65535-50000)/256;
  212.         TL0=(65535-50000)%256;                //重新赋初值
  213.         temp++;
  214.         if(temp==20)   //说明过去了1秒
  215.         {
  216.                 temp=0;   //清零,重新加到20
  217.                 //东西方向南北方向时间自减
  218.                 time1--;
  219.                 time2--;
  220.                 if(time1>time2)        //南北大于东西
  221.                 {
  222.                         time1=time2+3;
  223.                         P1=0x21;        //南北红灯亮起,东西绿灯亮起
  224.                         if(time2==0&&time1==3)  
  225.                         {
  226.                                 time2=3;  //重新赋南北和东西的差值,与南北方向一起倒计时
  227.                                 P1=0x11;  //东西黄灯亮起,东西绿灯关闭
  228.                                 tab=0;         //标志位
  229.                         }        
  230.                 }
  231.                 if(time1<time2)        //南北小于东西
  232.                 {        
  233.                         time2=time1+3;               
  234.                         P1=0x0c;        //南北绿灯亮起,东西红灯亮起
  235.                         if(time1==0&&time2==3)  
  236.                         {
  237.                                 time1=3;  //重新赋南北和东西的差值,与东西方向一起倒计时
  238.                                 P1=0x0a;  //南北黄灯亮起,南北绿灯关闭
  239.                                 tab=1;        //标志位
  240.                         }        
  241.                 }
  242.                 if(!tab)                   //黄灯闪烁三秒
  243.                 {
  244.                         if(time1==2&&time2==2)
  245.                                 P1=0x01;
  246.                         if(time1==1&&time2==1)
  247.                                 P1=0x11;
  248.                 }
  249.                 if(tab)
  250.                 {
  251.                         if(time1==2&&time2==2)
  252.                                 P1=0x08;
  253.                         if(time1==1&&time2==1)
  254.                                 P1=0x0a;
  255.                 }        
  256.                 if(time1==0&&time2==0&&tab==0)  //东西倒计时结束
  257.                 {
  258.                         time1=t1;
  259.                         time2=t1+3;
  260.                         P1=0x0c;   //东西红灯,南北绿灯
  261.                 }
  262.                 if(time1==0&&time2==0&&tab==1)  //南北倒计时结束
  263.                 {
  264.                         time1=t2+3;
  265.                         time2=t2;
  266.                         P1=0x21;   //南北红灯,东西绿灯
  267.                 }        
  268.         }        
  269. }
复制代码

所有资料51hei提供下载:
交通灯.zip (4.65 MB, 下载次数: 545)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:630068 发表于 2019-11-15 21:20 | 显示全部楼层
很好,很强大,模式多样。
回复

使用道具 举报

ID:639511 发表于 2019-11-19 08:54 | 显示全部楼层
附件里面有仿真图文件吗
回复

使用道具 举报

ID:648621 发表于 2019-12-4 20:50 | 显示全部楼层
不行啊,数码管数字一直在闪动,倒计时都不减少的
回复

使用道具 举报

ID:765859 发表于 2020-5-31 16:53 | 显示全部楼层
里面的仿真文件没有错误吧
回复

使用道具 举报

ID:766439 发表于 2020-6-1 12:54 | 显示全部楼层
楼主,贴里面有protues原理图仿真文件吗
回复

使用道具 举报

ID:706694 发表于 2020-6-5 11:39 | 显示全部楼层
有用吗??????
回复

使用道具 举报

ID:699150 发表于 2020-10-15 16:26 | 显示全部楼层
谢谢楼主,不过仿真有问题
回复

使用道具 举报

ID:836280 发表于 2020-10-29 17:45 | 显示全部楼层
有仿真吗
回复

使用道具 举报

ID:812051 发表于 2020-12-12 21:15 | 显示全部楼层
学习了,比我考虑的周全
回复

使用道具 举报

ID:479945 发表于 2020-12-17 16:19 | 显示全部楼层
模式多样。
回复

使用道具 举报

ID:872775 发表于 2021-1-3 20:42 | 显示全部楼层
模式真多
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表