基于51单片机交通灯程序设计与仿真
摘要

交通信号灯是城市交通安全、有序、快速运行的重要保障。本文提出一种基于单片机的交通信号灯控制系统的设计方案。该系统模拟现实中十字路口的通行指示,倒计时、紧急车辆通行、强制东西/南北通行、夜间模式灯、转向等功能。并结合交通灯,设计了人行道灯。采用STC89C51芯片作为中心期间来设计交通灯来控制电路,结合七段共阴极数码管显示时间的模块、交通灯显示模块、按键电路、IO口扩展电路等组成,通过程序设计和软件仿真来实现红、黄、绿、蓝燃亮时间以及双位数码管显示倒计时。

关键字:交通信号灯、人行道灯、STC89C51单片机、紧急通行、转向功能

51单片机交通灯Proteus仿真

一、工程介绍

1.1、实现要求

  1. 控制交通灯实现车辆东西通行后,南北通行功能
  2. 控制转向灯实现交通灯东西通行后左转,南北通行后左转功能
  3. 控制人行道灯实现交通灯东西通行的同时,同时南北人行道开启,同理南北通行亦如此
  4. 可以控制按钮实现东西时间的调整、夜间模式、紧急模式、强制东西/南北模式、查看时间

二、仿真电路设计

2.1环境介绍

  • 仿真设计使用Proteus 8.0;Proteus安装参考链接

2.2、电路设计

2.2.1、最小系统的实现

关于51单片机最小系统可以查看我以前博客,2.2.1、最小系统实现参考链接

从Proteus中选取元件有:74HC595芯片、74HC245芯片、AT89C51单片机、BUTTON开关、BUZZER蜂鸣器、CAP电容、CAP-ELEC电解电容、CRYSTAL晶振、LED-BLUE蓝色LED、LED-GREEN绿色LED、LED-RED红色LED、LED-YELLOW黄色LED、PNP三极管、RES电阻、RESPACK-8排阻、TRAFFICLIGHTS交通灯、7SEG-MPX2-CC两位八段共阴极数码管

最小系统如下:

2.2.2、数码管的使用

数码管按段数可分为七段数码管和八段数码管,八段数码管比七段数码管多一个发光二极管单元(多一个小数点显示);按能显示多少个“8”可分为1位、2位、3位、4位、5位、6位、7位等数码管。按发光二极管单元连接方式可分为共阳极数码管和共阴极数码管。共阳数码管是指将所有发光二极管的阳极接到一起形成公共阳极(COM)的数码管,共阳数码管在应用时应将公共极COM接到+5V,当某一字段发光二极管的阴极为低电平时,相应字段就点亮,当某一字段的阴极为高电平时,相应字段就不亮。共阴数码管是指将所有发光二极管的阴极接到一起形成公共阴极(COM)的数码管,共阴数码管在应用时应将公共极COM接到地线GND上,当某一字段发光二极管的阳极为高电平时,相应字段就点亮,当某一字段的阳极为低电平时,相应字段就不亮。

一位数码管内部原图如图所示:

在实际电路中数码管是要加驱动芯片的,因为单靠51单片机管脚输出电流是不够的,这里通过添加74HC245驱动芯片驱动各个数码管,用51单片机P0口传送数据给数码管,一定要加上拉电阻,并通过八同相三态总线收发器74HC245直接连接数码管的八个LED。

74HC245芯片内部结构如下:




由于单片机或CPU的数据地址控制总线端口都有一定的负载能力,如果负载超过其负载能力,一般应加驱动器。主要应用于大屏显示,以及其它的消费类电子产品中增加驱动。

仿真电路图如下:


2.2.3、交通灯、人行灯及转向灯

通过Proteus绘制路线以及人行道,可以画出如下电路图:

2.2.4、74HC595芯片的使用

74HC595是串口转并口芯片,可输出三种状态:高电平、低电平和高组态。一片74HC595芯片可实现3根口线扩展为8根口线.也可采用多片74HC595进行级联的方式扩展输出口线。控制可以采取如下控制:

仿真电路图如下:

2.2.6、蜂鸣器电路的设计

当IO输出低电平时,三极管导通,蜂鸣器发出声音。

2.2.7、按键电路的设计

2.3、总体仿真电路图

三、程序设计

3.1、环境介绍

  • 程序设计采用Keil 5.22;MDK5安装以及C51支持包

3.2、定时器的使用

89C51单片机内部有两个16位的定时/计数器,即定时器T0和定时器T1,这次仿真是要控制数码管每隔1S变化一次,所以应把两个定时器配置50MS的中断,响应10次即完成0.5S,响应20次完成1S。由于51单片机1个机器周期=12个时钟周期,系统时钟频率为12MHZ,则一个机器周期为1US,$ Sysclk = \frac{12MHZ}{12}=1MHZ$。下面是涉及定时器的相关寄存器:

工作模式寄存器TMOD是用于控制定时器0/1的工作模式,通过对TMOD进行赋值,则可以改变定时器的工作模式具体各位的定义如下:

定时器T0/T1有四种工作模式:模式0(13位定时器/计数器),模式1(16位定时器/计数器模式),模式2(8位自动重重装载模式),模式3(两个8位定时器/计数器)。T1除模式3外,其他工作模式与定时器/计数器0相同,T1载模式3无效,停止计数。

定时器的控制寄存器TCON为定时器/计数器T0、T1的控制寄存器,同时也锁存T0、T1溢出中断源和外部请求中断源等,格式如下:

配置T0和T1定时器程序如下:

void TIMER_init(void)     // 定时器初始化配置
{TMOD=0X11;            // 设置T0和T1为模式1(16位定时器)TH1=0X3C;             // 定时器1置初值 0.05STL1=0XB0;TH0=0X3C;          // 定时器0置初值 0.05STL0=0XB0;EA=1;              // 开总中断ET0=1;               // 定时器0中断开启ET1=1;               // 定时器1中断开启TR0=1;               // 启动定时0TR1=0;              // 关闭定时1
}

定时器T0实现交通灯和转向灯程序流程:


















































T0开始计时









当东西/南北倒计时到0重置5秒









开启黄灯闪烁和蜂鸣器









黄灯闪烁完开启转向灯10秒









当东西/南北转向灯倒计时为5S开启闪烁







黄灯和转向灯闪烁程序如下:

void Yellow_Flicker(void)
{if (countt0 == 10)                                           // 加到10也就是半秒{if ((sec_nb <= 5) && (dx_nb == 0) && (shanruo == 1))     // 东西黄灯闪{Green_dx = 0;Yellow_dx = 0;if (DX_LL == 1)SendTo595(0XF7);Buzz = 0;                                             // 蜂鸣器关}if ((sec_dx <= 5) && (dx_nb == 1) && (shanruo == 1)) // 南北黄灯闪{Green_nb = 0;Yellow_nb = 0;if (NB_LL == 1)SendTo595(0XFB);Buzz = 0;                                           // 蜂鸣器关}}if (countt0 == 20)         // 定时器中断次数=20时(即1秒时){if ((sec_nb <= 5) && (dx_nb == 0) && (shanruo == 1))     // 打开交通灯{Green_dx = 0;Buzz = 1;                                             // 蜂鸣器关if (DX_LL == 1)SendTo595(DX_L);elseYellow_dx = 1;}if ((sec_dx <= 5) && (dx_nb == 1) && (shanruo == 1))  // 南北黄灯闪{Green_nb = 0;Buzz = 1;                                            // 蜂鸣器关if (NB_LL == 1)SendTo595(NB_L);elseYellow_nb = 1;}}
}

定时器0中断程序如下:

void time0(void) interrupt 1 using 1     // 定时中断子程序
{TH0=0X3C;                                           // 重赋初值TL0=0XB0;                                            // 12m晶振50ms//重赋初值TR0=1;                                                // 重新启动定时器countt0++;                                        // 软件计数加1Yellow_Flicker();if(countt0==20)       // 定时器中断次数=20时(即1秒时){ countt0=0;                 // 清零计数器sec_dx--;                     // 东西时间减1sec_nb--;                        // 南北时间减1if(sec_dx==0&&sec_nb==5)       //当东西倒计时到0时,重置5秒,用于黄灯闪烁时间{sec_dx=5;shanruo=1;}if(sec_nb==0&&sec_dx==5)     //当南北倒计时到0时,重置5秒,用于黄灯闪烁时间{sec_nb=5;shanruo=1;}if(dx_nb==0&&sec_nb==0&&DX_LL==0)          //当东西通行时间完毕,开始东西左转{sec_nb = 10;sec_dx = 10;SendTo595(DX_L);     DX_LL=1;Yellow_dx = 0;}if(dx_nb==0&&sec_nb==0&&DX_LL==1)            //当黄灯闪烁时间倒计时到0时,{Buzz=1;                      //蜂鸣器开P2 &=0x81;                    //重置东西南背方向的红绿灯Green_nb=1;Red_dx=1;dx_nb=!dx_nb;shanruo=0;if(num_che_nb>set_timenb/2)//如果此时南北通行的车辆数大于预设通行量set_timenb=set_timenb+5;    if(num_che_nb==0)//如果南北方向无车辆通行,每次递减5秒set_timenb=set_timenb-5;if(set_timenb<=15)set_timenb=15;sec_nb=set_timenb;            //重赋南北方向的起始值sec_dx=set_timenb+5;        //重赋东西方向的起始值num_che_nb=0;//清零SendTo595(NB_R);   DX_LL=0;   }    if(dx_nb==1&&sec_dx==0&&NB_LL==0)            //当南北通行时间完毕,开始南北左转{sec_nb = 10;sec_dx = 10;SendTo595(NB_L);     NB_LL=1;Yellow_nb = 0;    }if(dx_nb==1&&sec_dx==0&&NB_LL==1)            //当黄灯闪烁时间到{P2&=0X81;                     //重置东西南北的红绿灯状态Green_dx=1;                    //东西绿灯亮Red_nb=1;                    //南北红灯亮dx_nb=!dx_nb;              //取反shanruo=0;                 //闪烁if(num_che_dx>set_timedx/2)//如果此时南北通行的车辆数大于预设通行量set_timedx=set_timedx+5;   if(num_che_dx==0)//如果东西方向无车辆通行,每次递减5秒set_timedx=set_timedx-5;if(set_timedx<=15)set_timedx=15;sec_dx=set_timedx;            //重赋东西方向的起始值sec_nb=set_timedx+5;        //重赋南北方向的起始值num_che_dx=0;//清零SendTo595(DX_R);       NB_LL=0;}}
}

3.3、外部中断的使用

程序使用两个外部中断实现东西/南北强制转换,分别使用了外部中断0和外部中断1,且中断结构如下。

通过结构图可以看出使用外部中断步骤如下:

  1. 设置电平触发方式
  2. 开启EX0/1
  3. 开启总中断

初始化外部中断程序如下:

    IT0 = 1;//设置为下降沿触发EX0 = 1;//使能外部中断IT1 = 1;EX1 = 1;

两个外部中断具体使用的功能:

//外部中断0
void int0(void) interrupt 0 using 1    //只允许东西通行
{TR0=0;                             //关定时器0TR1=0;                               //关定时器1P2=0x00;                         //灭显示Green_dx=1;                            //东西方向置绿灯Red_nb=1;                          //南北方向为红灯sec_dx=00;                         //四个方向的时间都为00sec_nb=00; SendTo595(null);
}
//外部中断1
void int1(void) interrupt 2 using 1      //只允许南北通行
{TR0=0;                             //关定时器0TR1=0;                              //关定时器1P2=0x00;                          //灭显示Green_nb=1;                            //置南北方向为绿灯Red_dx=1;                         //东西方向为红灯sec_nb=00;                         //四个方向的时间都为00sec_dx=00;SendTo595(null);
}

3.4、控制595芯片

我们都知道通信从大的方面有两种:串行和并行。串行的最大优点是占用总线少,但是传输速率低;并行恰恰相反,占用总线多,传输速率高。市面上有很多这样的芯片,有串入并出的(通俗讲就是 一个一个进,最后一块出来),有并入串出的(相对前者而言)。具体用哪种类型要根据我们得实际情况。比如利用单片机显示数码管单纯的显示一个数码管如果仅仅是为了显示 那么动用单片机一个端口(如P0或P1/P2/P3)那没有什么,当然这里我说的数码管是8段的(如果利用BCD类型 16进制数码管那么只需四个即可)就拿51类型的单片机来说,总共32个I/O口,一般如果不是做太大的工程是完全够用的,但有些时候你会恨单片机怎么不多长几条“腿”,怎么省还是不够用。这个时候就需要用到并转串或者串转并芯片来进行IO口的扩展,74HC595就是一种串行转并行的芯片。参考链接

程序如下:

#define NB_L 0XFE
#define DX_L 0XFD
#define NB_G 0XF7
#define NB_R 0XF7
#define DX_G 5
#define DX_R 0XFB
#define null 0XF3
sbit DS = P2^0;
sbit SH_CP = P2^7;
sbit ST_CP = P1^4;
void SendTo595(uchar Data)//发送一个字节数据给595再并行输出
{char i=0;ST_CP = 0;for(i;i<8;i++){SH_CP = 0;  DS=0x80&Data;//&为按位运算符,即全1为1,有0为0,上式也就是 (1000 0000)&(1111 1111)=1000 0000,若高位为1则是1高位为0则这个式子为0Data=_crol_(Data,1); //左移一位 将高位补给低位,如果二进制数为01010101 那么_crol_(1) 为10101010SH_CP = 1;           //上升沿让串行输入时钟变成高电平 并延时一个时钟周期_nop_(); }    /*位移寄存器完毕,转移到存储寄存器*/ST_CP = 1;               //上升沿,存储寄存器变为高电平 延迟两个时钟周期_nop_();_nop_();}

3.5、数码管程序设计

uchar code table[11]={  //共阴极字型码0x3f,  //--00x06,  //--10x5b,  //--20x4f,  //--30x66,  //--40x6d,  //--50x7d,  //--60x07,  //--70x7f,  //--80x6f,  //--90x00   //--NULL
};
void display(void) //显示子程序
{   if(xianshi_fx==0)//正常显示{buf[1]=sec_nb/10;       //第1位 东西显示秒十位buf[2]=sec_nb%10;      //第2位 东西显示秒个位buf[3]=sec_dx/10;      //第3位 南北显示秒十位buf[0]=sec_dx%10;      //第4位 南北显示秒个位   }if(xianshi_fx==1)//查看通行时间{buf[1]=set_timenb/10;        //第1位 东西通行秒十位buf[2]=set_timenb%10;      //第2位 东西通行秒个位buf[3]=set_timedx/10;      //第3位 南北通行秒十位buf[0]=set_timedx%10;      //第4位 南北通行秒个位   }if(xianshi_fx==2)//查看红外计数值{buf[1]=num_che_nb/10;       //第1位 东西红外计数值十位buf[2]=num_che_nb%10;        //第2位 东西红外计数值个位buf[3]=num_che_dx/10;        //第3位 南北红外计数值十位buf[0]=num_che_dx%10;        //第4位 南北红外计数值个位 }s1 = 1;s2 = 1;s3 = 1;s4 = 1;P0=0x00;                灭显示s1 = 0;s2 = 1;s3 = 1;s4 = 1;P0=table[buf[1]];       //送东西时间十位的数码管编码         delay(1);               //延时s1 = 1;s2 = 1;s3 = 1;s4 = 1;P0=0x00;                //灭显示                          s1 = 1;s2 = 0;s3 = 1;s4 = 1;P0=table[buf[2]];         //送东西时间个位的数码管编码delay(1);                //延时s1 = 1;s2 = 1;s3 = 1;s4 = 1;P0=0x00;               //关显示s1 = 1;s2 = 1;s3 = 0;s4 = 1;P0=table[buf[3]];      //送南北时间十位的数码管编码delay(1);                //延时s1 = 1;s2 = 1;s3 = 1;s4 = 1;    P0=0x00;                 //关显示s1 = 1;s2 = 1;s3 = 1;s4 = 0;  P0=table[buf[0]];       //送南北时间个位的数码管编码delay(1);                //延时
}

五、结果分析与改进

  1. 问题:仿真结果表明,当增加时间或者减小时间那么东西和南北的倒计时会同时增加
  2. 解决:通过设置独立按键把东西/南北倒计时时间分开即可解决

参考资料:

  1. 51单片机 74hc595使用用法(利用proteus仿真)
  2. 74HC245 内部结构及作用

基于51单片机交通灯程序设计与仿真相关推荐

  1. 【Proteus】51单片机交通灯信号模拟仿真示例二

    [Proteus]51单片机交通灯信号模拟仿真示例二 Proteus仿真效果 相关篇<[Proteus]51单片机交通灯信号模拟仿真示例一> 程序代码 /*---------------- ...

  2. 基于51单片机交通灯控制系统

    51单片机交通灯控制系统 可调时间+紧急+行人+黄灯5s 仿真:proteus 7.8 程序编译器:keil 4/keil 5 编程语言:C语言 设计编号:J008 目录标题 51单片机交通灯控制系统 ...

  3. 基于51单片机交通灯设计时间可设置仿真红绿灯十字路口

    演示视频:https://www.bilibili.com/video/BV1Tt4y1y7s8/ 将链接复制至IE浏览器打开!!! 功能操作说明: 从上到下,设置键,加键,减键,特殊键.单独一个按键 ...

  4. 30、基于51单片机交通灯车流量管控数码管显示系统设计

    摘要 随着社会主义的建设,城市的规模在不断扩大,城市的交通也在不断的提高和改进,交通的顺畅已经成为制约社会主义建设的一个重要因素.目前,伴随着机动车辆的不断增加,尤其是十字路口的交通建设 颇为关键,严 ...

  5. 基于单片机超声波视力保护系统设计-基于51单片机8音键电子琴仿真设计-基于8086八路模拟信号采集均值显示系统设计-基于8086八路数据电压温度采集系统-基于8086波形发生器仿真设计【毕设课设分享】

    539基于单片机超声波视力保护系统设计-设计资料 硬件构成:单片机+最小系统+LCD1602液晶显示模块+超声波模块+DS18B20温度采集模块+光线检测模块+ADC0832模块+蜂鸣器模块+LED指 ...

  6. 基于51单片机的烟雾火灾报警器proteus仿真设计

    基于51单片机的烟雾火灾报警器proteus仿真设计 1 开发环境 仿真图:proteus8.9以上 程序代码:KEIL4/KEIL5 原理图:AD 设计编号:A0004 代码讲解+仿真讲解+仿真演示 ...

  7. 基于51单片机的噪声测量仪仿真

    具体实现功能 具体实现功能: ①LCD1602实时显示噪声分贝值,精度为0.1db: ②可以按键设置报警值,实现声光报警:三个按键:设置键.加键.减键: ③当噪声分贝值未超过阀值时,绿灯闪烁:当超过阈 ...

  8. 51单片机交通灯(定时器+38译码器+中断)

    51单片机交通灯这个实例主要用到的知识点有: >如何点亮LED >38译码器位选与段选 >定时器控制 >中断控制 #include <reg52.h>/****** ...

  9. 基于51单片机的废气检测I2Cproteus仿真

    目录 文章目录 前言 二.设计步骤 1.proteus设计 2.keil5代码编程设计 总结 前言 前段时间高中同学让我帮忙给她做一个数电课设,反正也没事做就随便做了做,现在总结一下,话不多说直接上效 ...

  10. 【034】基于51单片机的HX711电子秤Proteus仿真设计

    一.压缩包资料内容 (1).基于51单片机的HX711电子秤proteus仿真设计一份: (2).基于51单片机的HX711电子秤proteus仿真设计keli源代码一份: (3).基于51单片机的H ...

最新文章

  1. FinFET与2nm晶圆工艺壁垒
  2. .NET程序员的C\C++情结(3)
  3. idea 中 git 修改了文件却无法提交(No Changes detected)
  4. OpenCV在图像上添加边框borders
  5. 新一代Hologres实时数仓大揭秘
  6. nginx开发简单的http模块
  7. php下载文件与服务器有关吗,php 下载文件功能中下载后文件大小与服务器源文件大小不一致...
  8. 网络虚拟化基础协议之Geneve
  9. 数控系统市场下行压力逐渐增大
  10. DDWRT几种无线工作模式简介
  11. linux 下ssd训练自己的数据
  12. 击破“坪效”天花板,从“3050法则”看餐饮数字化迁徙
  13. 天翼阅读倾情回馈——《海盗鬼皮书》限时免费畅读
  14. Mysql 中的各种“删除”。删除数据库、删除表、删除字段
  15. CPU个数、CPU物理核数、CPU逻辑核数、vCPU数之间的区别
  16. 教你用认知和人性来做最棒的程序员
  17. JavaScript特效源码(8、其他特效)
  18. Node+express+mongoose前端实现简单crud接口
  19. Zookeeper原理详解
  20. java applet 淘汰_java – 替代applet的替代技术?

热门文章

  1. matlab arccos uint8,《高等应用数学问题的MATLAB求解》——第3章习题代码
  2. windows下3389端口开启和连接
  3. linux cam软件,基于Linux图形交互式线切割CAM软件实现技术研究
  4. 佳能g2800清废墨_佳能G2800打印机清零
  5. C++STL源码剖析之vector
  6. 用c语言编程图书管理系统,C语言图书管理系统简洁版
  7. 直播系统源码,直播平台系统源码
  8. 编译原理——Lex与Yacc及应用
  9. 人人商城小程序服务器根目录,人人商城小程序前端怎么安装?人人商城小程序如何配置实用...
  10. 带你了解网络的魅力——tcping和ping区别