单片机应用综合实验报告
题目:平面交叉口多时段多相位交通信号灯控制器设计
学院: 电子与控制工程学院
专业: 自动化(交通信息与控制)
班级:
姓名:
指导教师:
实验题目:平面交叉口多时段多相位交通信号灯控制器设计
实验功能要求:
1、交通信号灯控制器为两相位(基本部分),可设置为三相位或四相位,设 有平峰时段、早高峰时段、午间高峰时段和夜间时段四个时段,时段的起止时间可以根据交通工程相关课程的知识确定;
2、通过键盘进行相位、时段设定,设置相应的信号周期、绿灯时间等,黄闪设定为三秒,闪三次;时间单位:秒;
3、具有红绿灯倒计时功能;
4、具有紧急车辆优先功能,设紧急车辆通过十字路口需要5秒,若此时为红灯,则转为绿灯,倒计时5秒,让紧急车辆通过;若此时为绿灯,则判断剩余的时间是否够紧急车辆通过,若不足,则延长够5秒让紧急车辆通过;遥控或按键输入紧急车辆到达信息。
5、具有公交优先通行功能(选做);
6、具有绿冲突检测功能(选作)。
实验方案设计:
1、时段设计
早高峰时段:8:00--9:00
午间高峰时段:11:00--13:00
夜间时段:22:00--4:00
正常时段:9:00--11:00、13:00--22:00、4:00--8:00
2、设计方案功能:
(1)交通灯四相位多时段控制,交通灯控制分别为东西直行绿灯、南北红灯,东西左转绿灯、南北红灯,东西黄闪、南北红灯,东西红灯、南北直行绿灯,东西红灯、南北左转绿灯,东西红灯、南北黄闪共六中状态。
(2)可以对灯的时间进行倒计时显示。倒计时显示可以提醒驾驶员在信号灯灯色发生改变的时间、在“通过”和 “停止”两者间作出合适的选择。驾驶员和行人普遍都愿意选择有倒计时显示的信号控制方式,并且认为有倒计时显示的路口更安全。倒计时显示是用来减少驾驶员在信号灯色改变的关键时刻做出复杂判断的1种方法,它可以提醒驾驶员灯色发生改变的时间,帮助驾驶员在“停止”和“通过”两者间作出合适的选择 。
(3)可以进行实时时间与交通灯显示时间的转换,到达早高峰或午间高峰等特定时期进行自动转换。
(4)可以根据实际情况对周期或绿灯时间进行更改,方便灵活。
(5)在紧急事件发生时,可以对紧急事件进行妥善处理。例如东西方向绿灯,有紧急车辆要通过时,判断绿灯时间是否够5秒,够5秒不做操作;不够5秒时,延长到5秒,让紧急车辆通过。如果东西方向是红灯,有紧急车辆通过时,让东西、南北方向都变成红灯,让紧急车辆通过。
(6)夜间模式所有数码管显示0黄灯亮0.6s熄灭0.4s(周期为1s)以此循环不停闪烁以提醒司机朋友注意安全。
理论知识积累
1、中断原理
本系统主要使用了外部中断,中断信号有引脚INT0和INT1输入,低电平有效,CPU每个时钟周期都会检测INT0和INT1上的信号,8051允许外部中断以电平方式或负边沿方式两种中断方式输入中断请求信号,可由用户通过设置TCON中IT0和IT1位的状态来实现。以IT0为例,IT0=0,为电平触发方式,IT0=1,为负边沿触发方式,本设计采用电平方式,IE0为其中断标志位,有中断信号则置位,中断服务子程序响应后,IE0自动清零。IE中的EA为允许中断的总控制位,为1开启,EX0为外部中断允许控制位,为1开启。
在优先级的允许下,一旦有外部中断信号产生,单片机CPU首先保护断点,PC值进栈,然后执行相应的中断服务子程序,执行完后,用RETI指令返回,此时CPU会从堆栈中取保存的断点地址,送回PC,程序再正常执行。
2、根据《交通工程原理》计算配时参数
根据TRRL配时方法的基本原理,信号配时参数可按如下公式计算。
1)最佳周期时长
Co=1.5L+5/1-Y
式中:L——信号总损失时间;
Y——流量比总和。
2)信号总损失时间
L=
式中:L——启动损失时间,应实测,当无实测时间时可取3s;
A——黄灯时长,可定为3s;
I——绿灯间隔时间(s);
k——一个周期内的绿灯间隔数。
3)绿灯间隔时间
I=z/u+t
式中:z——停止线到冲突点距离(m);
u——车辆在进口道上的行驶车速(m/s);
t——车辆制动时间(s)。
当计算绿灯时间间隔时间I<3s时,配以黄灯时间3s;当I>3s时,其中3s配以黄灯时间,其余时间配以红灯。
4)流量比总和
流量比总和,按下式计算。
Y= (Y<=0.9)
式中:Y——组成周期的全部信号相位的各个最大流量比y值之和;
j——一个周期内的相位数;
y——第j相的流量比;
q——设计交通量(pcu/h);
S——计算饱和流量(pcu/h)。
当计算的Y值大于0.9时,需改进进口道设计或/和信号相位方案,并进行重新设计。
5)总有效绿灯时间
每周期的总有效绿灯时间按下式计算。
Ge=Co-L
6)每相位有效绿灯时间
gej=Ge 7)各相位的绿信比
λ=g/Co
8)各相位显示绿灯时间
gj=gej-Aj+Lj
式中:l——第j相位起动损失时间;
其余符号意义同上。
9)最短绿灯时间
g(min)=7-I+Lp/Vp
式中:g(min)——最短绿灯时间(s);
L——行人过街道长度(m);
I——绿灯间隔时间(s)。
计算的显示绿灯时间小于相应的最短绿灯时间时,应延长计算时间周期时长,重新计算。
3、软件延时的实现
51的工作频率为12MHZ,机器周期与主频有关,机器周期是主频的12倍,所以一个机器周期的时间为12*(1/12MHZ)=1us。可知具体每条指令的周期数,则就可以通过指令的执行条数来确定1秒的时间,但同时由于单片机的运行速度很快其他的指令执行时间可以忽略不计。
4、定时器原理
定时器工作的基本原理即给定初值,让它不断加1直至减完为止,这个初值是送到TH和TL中的。它是以加法记数的,并能从全1到全0时自动产生溢出中断请求。因此,我们可以把计数器记满为零所需的计数值,即所要求的计数值设定为C,把计数初值设定为TC 计算公式如下:
TC=M-C
式中,M为计数器模值。计数值并不是目的,目的是时间值,设计1次的时间,即定时器计数脉冲的周期为T0,它是单片机系统主频周期的12倍,设要求的时间值为T,则有C=T/T0。计算通式变为:
T=(M-TC)T0
模值和计数器工作方式有关。在方式1时M的值为65536。就此可以算出各种方式的最大延时。如单片机的主脉冲频率为12MHZ,经过12分频后,采用方式1最大延时也只有65.536毫秒。所以扫描周期为50ms的方法是令TH=(65536-50000)/256;;;;TL=(65536-50000)%256;,
若使用软件则会耽搁程序流程,显然不可行。相反,时间计时方面却不可能只用计数器,因为显然1秒钟已经超过了计数器的最大定时间,所以我们还必须采用定时器和软件相结合的办法才能解决这个问题。
集成开发环境KEIL
KEIL IDE Vision2集成开发环境主要由以下部分组成:
1、u Vision2 IDE。ision2 IDE包括:一个工程管理器,一个功能丰富并有交互式错误提示的编辑器选项设置生成工具,以及在线帮助。使用vision2创建源文件并组成应用工程加以管理。vision2可以自动完成编译汇编链接程序的操作;
2、C51编译器和A51汇编器。Vision2 IDE创建的源文件可以被C51编译器或A51汇编器处理生成可重定位的object文件。KEIL C51编译器遵照ANSI C语言标准支持C语言的所有标准特性,另外还增加了几个可以直接支持80C51结构的特性。KEIL A51宏汇编器支持80C51及其派生系列的所有指令集;
3、LIB51库管理器。B51库管理器可以从由汇编器和编译器创建的目标文件建立目标库,这些库是按规定格式排列的目标模块,可在以后被链接器所使用当链接器处理一个库时仅仅使用了库中程序使用了的目标模块而不是全部加以引用;
4、BL51链接器定位器。L51链接器使用从库中提取出来的目标模块和由编译器汇编器生成的目标模块创建一个绝对地址目标模块,绝对地址目标文件或模块包括不可重定位的代码和数据所有的代码和数据都被固定在具体的存储器单元中。
利用KEIL开发和调试系统软件流程大致如下:
5、启动Vision2,进入KEIL软件的集成开发环境;
6、利用KEIL内置的文本编辑器进行程序源文件的编辑,因为KEIL集成的文本编辑器对中文支持不是很好,可以选择其他的编辑器(本文使用的文本编辑器是Ultraedit—32),Vision2能够自动识别外部改变了的源文件;
7、建立工程,指定针对哪种单片机进行开发,指定对源程序的编译、链接参数,指定调试方式(本文采用外部硬件仿真器仿真调试的方式,即使TKS仿真器仿真),然后对工程进行相关设置;
8、设置好工程后即可进行编译、链接。连接仿真器对软件进行调试。也可以生成下载到单片机存储器上的HEX文件。
单片机交通灯控制系统硬件设计
1、AT89C51单片机简介
AT89C51是一种带4K字节闪烁可编程可擦除只读存储器(FPEROM—Falsh Programmable and Erasable Read Only Memory)的低电压,高性能CMOS8位微处理器,俗称单片机。AT89C2051是一种带2K字节闪烁可编程可擦除只读存储器的单片机。单片机的可擦除只读存储器可以反复擦除100次。该器件采用ATMEL高密度非易失存储器制造技术制造,与工业标准的MCS-51指令集和输出管脚相兼容。由于将多功能8位CPU和闪烁存储器组合在单个芯片中,ATMEL的AT89C51是一种高效微控制器,AT89C2051是它的一种精简版本。AT89C单片机为很多嵌入式控制系统提供了一种灵活性高且价廉的方案。
2、AT89C51单片机的主要特性
与MCS-51 兼容 ,4K字节可编程闪烁存储器 ,寿命:1000写/擦循环,数据保留时间:10年,全静态工作:0Hz-24Hz,三级程序存储器锁定,128*8位内部RAM,32可编程I/O线,两个16位定时器/计数器,5个中断源(两个外部中断源和3个内部中断源) ,可编程串行通道,低功耗的闲置和掉电模式,片内振荡器和时钟电路。
时钟电路:时钟电路的作用是产生单片机工作所需要的时钟脉冲序列。
中断系统:中断系统的作用主要是对外部或内部的终端请求进行管理与处理。AT89S51共有5个中断源,其中又2个外部中断源和3个内部中断源。
AT89C51系列单片机的内部结构示意图
3 、主要引脚功能
·VCC:电源电压
·GND:接地
·P0口:P0口是一组8位双向I/0口。P0口即可作地址/数据总线使用,又可以作为通用的I/O口使用。当CPU访问片外存储器时,P0口分时先作低8位地址总线,后作双向数据总线,此时,P0口就不能再作I/O口使用了。在访问期间激活要使用上拉电阻。
·P1口:Pl 是一个带内部上拉电阻的8准位双向I/O口,P1作为通用的I/O口使用。
·P2 口:P2 是一个带有内部上拉电阻的8 位准双向I/O 口,P2即可作为通用的I/O口使用,也可以作为片外存储器的高8位地址总线,与P0口配合,组成16位片外存储器单元地址。
·P3 口:P3 口是一组带有内部上拉电阻的8 位准双向I/0 口。P3 口除了作为通用的I/O口使用之外,每个引脚还具有第二功能,具体分配如表2
4 、具有第二功能的P3口引脚
·RST:复位输入。当振荡器工作时,RST引脚出现两个机器周期以上高电平将使单片机复位。WDT 溢出将使该引脚输出高电平,设置SFR AUXR的DISRT0 位(地址8EH)可打开或关闭该功能。DISRT0位缺省为RESET输出高电平打开状态。
·ALE/PROG(————):当访问外部程序存储器或数据存储器时,ALE(地址锁存允许)输出脉冲用于锁存地址的低8位字节。即使不访问外部存储器,ALE 仍以时钟振荡频率的1/6 输出固定的正脉冲信号,因此它可对外输出时钟或用于定时目的。要注意的是:每当访问外部数据存储器时将跳过一个ALE脉冲。对F1ash存储器编程期间,该引脚还用于输入编程脉冲(PROG)。如有必要,可通过对特殊功能寄存器(SFR)区中的8EH 单元的D0 位置位,可禁止ALE 操作。该位置位后,只有一条M0VX和M0VC指令ALE才会被激活。此外,该引脚会被微弱拉高,单片机执行外部程序时,应设置ALE无效。
·PSEN(————)程序储存允许(PSEN(————))输出是外部程序存储器的读选通信号,当AT89S51 由外部程序存储器取指令(或数据)时,每个机器周期两次PSEN(————)有效,即输出两个脉冲。当访问外部数据存储器,没有两次有效的PSEN(————)信号。
·EA(——)/VPP:外部访问允许。欲使CPU仅访问外部程序存储器(地址为0000H-FFFFH),EA端必须保持低电平(接地)。需注意的是:如果加密位LB1被编程,复位时内部会锁存EA端状态。如EA端为高电平(接VCC端),CPU则执行内部程序存储器中的指令。F1ash存储器编程时,该引脚加上+12V的编程电压Vcc。
·XTAL1:振荡器反相放大器及内部时钟发生器的输入端。
5、MCS—51的中断源
8051有5个中断源,它们是两个外中断INT0(P3.2)和INT1(P3.3)、两个片内定时/计数器溢出中断TF0和TF1,一个是片内串行口中断TI或RI,这几个中断源由TCON和SCON两个特殊功能寄存器进行控制,其中5个中断源的程序入口地址如表4所示:
中断源程序入口:
6、八段LED数码管
LED显示屏作为大型显示设备的一种,具有亮度高、价格低、寿命长、维护简便等优点。LED数码管的结构简单,分为七段和八段两种形式,也有共阳和共阴之分。本实验采用八段共阴极数码管,每个发光二极管的阴极连在一起,如图所示。这样,一个数码管就有I根位选线和8根段选线,要想显示一个数值,就要分别对它们的高低电平来加以控制。
图LED数码管
LED 灯的显示原理:通过同名管脚上所加电平的高低来控制发光二极管是否点亮而显示不同的字形,如 dp,g,f,e,d,c,b,a全亮显示为8,采用共阴极连接驱动代码,代码表如下表5所示。
表 驱动代码表
相应在程序软件上,可以通过调用程序给定的秒值经过特定计算算出需要显示的个位和十位,然后有DPTR调取LEDMAP的代码。
LED8段数码管的设置为每个方位上的一对2为显示器。四个方位上总共用8个LED接在单片机的IO口上。虽然路口不一样,但是显示的时间在数字上是一样的,所以两边连接的IO口是对称的。
7、按键控制
该实验设置了有8个键:
K1键=P3.0
K2键=P3.1
K3键=P3.2
K4键=P3.3
K5键=P3.4
K6键=P3.5
K7键=P3.6
K8键=P3.7
每个按键一端接地,另一端接对应的P3端口。低电平有效,当按键按下端口接地,相应键控制的程序起作用。
8、发光二极管
交通灯控制系统软件设计
1、实验程序流程图
实验主程序流程图:
运行过程流程图:
2、各时段配时参数
单片机课程设计总结与体会
刚刚拿到《单片机应用综合实验题目及要求》时,我们仔细阅读了一下各个实验题目及要求。经过初步分析发现四个题目中第一个:《平面交叉路口多时段多相位交通信号灯控制器设计》虽然要求较多、相对难度较大,但我们对这个选题比较感兴趣,又比较接近我们所学专业的知识。所以在四个题目中选择了第一个。
由于我们的单片机开发仪上的交通信号灯模块是两相位控制,但是我们打算用人行横道的两个绿灯分别代替东西左转绿灯和南北左转绿灯。这样便可在我们的单片机开发仪上
为了明细日后的设计,我们先绘制出了一个单片机的系统框图。
由该框图可知,我们所需的工作即为:确定LED数码管显示程序编程、数码管灯信号配时方案确定、按键控制程序编程。
由于题目中要求对交通信号灯的多时段配时,即一天中有平峰时段、早高峰时段、午间高峰时段、夜间时段,所以不同时间信号周期不同。我们原来的想法是,先在程序中确定四种时段的不同方案,实际控制时,用按键的选择来切换方案。但与老师沟通后,老师指出了我们的缺点。如果这样做交通灯控制不够灵活,应该用键盘设置加一按键和减一按键,并结合多种方案会使总体运行更加完善。
刚开始时,我们找的资料里大部分程序是用汇编语言编写的,看了几个后,我们对汇编语言用了一定的掌握后开始自己编写。参照教科书等资料编出了几个小程序,可以基本实现灯的点亮和数码管显示。但在编写紧急车辆通行功能时,总是无法实现,里面的许多参数都统一不了。经过慎重考虑我们又选择了C语言编写。由于先前在汇编上浪费了太多时间,我们组的进程变慢了。
选择C语言编写后,我们又重新在图书馆和网上找了一些资料,开始编写。一开始编写时,对数码管和交通灯模块不太熟悉,所以我们又对开发仪例程里的两个小实验仔细地看了一遍,清楚了里面各个管脚的顺序与接法。所以基础工作必须的做充分,否则后续工作无法完成。在编写的过程中遇到了许多麻烦和意想不到的困难,我们特地向老师和同学请教,我们的最终成功与老师的悉心指导和同学的帮助息息相关、密不可分,在此要特别感谢苏诗琳老师、李曙光老师!!!
在编写与调试程序过程中,我和队友遇到了许多难题,程序没有错误但就是得不到正确结果时,感到很绝望。但一次又一次的咬牙坚持下来,我和队友相互加油、打气,相互鼓励,最终看到交通灯按照预期的目标正常运转时,我们十分激动。这些天的努力终究的到的结果。
在这次试验中,我们也充分的认识到了只是学会单片机这本书不是本事,能成功的编出程序才是硬道理!在今后的学习过程中,不仅要把知识学懂,更重要的是学会应用。我和队友都觉得这次课程设计收获良多.理论知识只有应用到实践中才能发挥价值!
参考文献
[1].边海龙、孙永奎.《单片机开发与典型工程项目》.电子工业出版社
[2].任福田、刘小明、荣建.《交通工程学》.人民交通出版社
[3].汪贵平、李登峰、龚贤武.《单片机原理及应用》.机械工业出版社
[4].袁振洲、谷远利 .《人民交通出版社》.人民交通出版社
[5].赵建领、薛园园.《零基础学单片机C语言程序设计》.机械工业出版社
附:平面交叉口多时段多相位控制系统源程序
/************************************************************/
//##########################################################//
//####### 平面交叉口多时段四相位交通信号灯控制器设计 #######//
//############## P1口接交通信号控制灯 ##################//
//############## P2口接数码管位选 ##################//
//############## P0口接数码管段选 ##################//
//##########################################################//
/************************************************************/
#include
#define uchar unsigned char
#define uint unsigned int
uint m,hour2,hour1,minute2,minute1,second2,second1,aa,bb,round3,round2,round1,direct2,direct1,left2,left1;
uchar ewg,snr,ewr,sng,ewg1,snr1,hour,minute,second,round,direct,left;
uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,};//LED的字模,共阴极数码管0—9
sbit D2=P1^0; // P1.0口接交通控制灯D2
sbit D3=P1^1; // P1.1口接交通控制灯D3
sbit D4=P1^2; // P1.2口接交通控制灯D4
sbit D5=P1^3; // P1.3口接交通控制灯D5
sbit D6=P1^4; // P1.4口接交通控制灯D6
sbit D7=P1^5; // P1.5口接交通控制灯D7
sbit D8=P1^6; // P1.6口接交通控制灯D8
sbit D10=P1^7; // P1.7口接交通控制灯D10
sbit key1=P3^0; // P3.0口接独立键盘K1
sbit key2=P3^1; // P3.1口接独立键盘K2
sbit key3=P3^2; // P3.2口接独立键盘K3
sbit key4=P3^3; // P3.3口接独立键盘K4
sbit key5=P3^4; // P3.4口接独立键盘K5
sbit key6=P3^5; // P3.5口接独立键盘K6
sbit key7=P3^6; // P3.6口接独立键盘K7
sbit key8=P3^7; // P3.7口接独立键盘K8
void rgset( ); //周期和绿灯时间设置函数
void initial (); //函数的初始化
void timeset(); //时间设置函数
void common(); //平峰阶段函数
void ampeak(); //早高峰阶段函数
void pmpeak(); //午高峰阶段函数
void night( ); //夜间阶段函数
void delay(uint); //延时子函数
void display(); //倒计时显示
void display2(); //周期、绿灯时间显示
void display3(); //实际时间显示
void urgent(); //东西、南北方向紧急车辆处理函数
/************************/
//###### 主函数 ######//
/************************/
void main()
{
initial( );
second=30;minute=59;hour=9;
while(1)
{
if(hour>=4&&hour<8) //4:00—8:00为平峰阶段
common();
if(hour==8) //8:00—9:00为早高峰阶段
ampeak();
if(hour>=9&&hour<11) //9:00—11:00为平峰阶段
common();
if(hour>=11&&hour<13) //11:00—13:00为午高峰阶段
pmpeak();
if(hour>=13&&hour<22) //13:00—22:00为平峰阶段
common();
if(hour<4||hour>=22) //22:00—次日4:00为夜间阶段
night();
}
}
/******************************/
//###### 平峰阶段函数 ######//
/******************************/
void common()
{
round=90;direct=32;left=10; //设置平峰阶段周期为90s,东西方向直行绿灯时间为32s,东西左转方向绿灯时间为10s
while((hour>=4&&hour<8)||(hour>=9&&hour<11)||(hour>=13&&hour<22))
{ewg=direct;snr=(direct+left+3);D6=1;D4=1;D8=0;D3=0;D2=1;D5=1;D7=1;D10=1; //东西方向直行绿灯亮,南北方向红灯亮
do
{rgset();
timeset();
display();
urgent() ;
if(aa==20)
aa=0;
ewg--;
snr--;
}
}while(ewg!=0);
ewg=left;snr=(left+3);D10=0;D8=1;D3=0;//东西方向左转绿灯亮,南北方向红灯亮
do
{
rgset();
timeset();
display();
urgent() ;
if(aa==20)
{
aa=0;
ewg--;
snr--;
}
}while(ewg!=0);
ewg=3; snr=3;D7=0;D3=0;D10=1; //东西方向黄灯亮,南北方向红灯亮
do
{
rgset();
timeset();
display();
urgent();
if(aa==20)
{ D7=0;delay(500);D7=1;
aa=0;
ewg--;
snr--;
}
}while(ewg!=0);
ewg=(round-direct-left-3);snr=(round-2*left-direct-6); D6=0;D7=1;D3=1;D5=0;//东西方向红灯亮,南北方向直行绿灯亮
do
{
rgset();
timeset();
display();
urgent();
if(aa==20)
{
aa=0;
ewg--;
snr--;
}
}while(snr!=0);
ewg=(3+left);snr=(left);D6=0;D2=0;D5=1;//东西方向红灯亮,南北方向左转绿灯亮
do
{
rgset();
timeset();
display();
urgent();
if(aa==20)
{
aa=0;
ewg--;
snr--;
}
}while(snr!=0);
ewg=3;snr=3;D6=0;D4=0;D2=1; //东西方向红灯亮,南北方向黄灯亮
do
{
rgset();
timeset();
display();
urgent();
if(aa==20)
{
aa=0;
ewg--;
snr--;
D4=0;delay(500);D4=1;
}
}while(snr!=0);
}
}
/*********************************/
//###### 早高峰阶段函数 #######//
/********************************/
void ampeak()
{ round=84;direct=28;left=10;//设置早高峰阶段周期时间为84s,东西直行方向绿灯时间为28s,东西左转方向绿灯时间为10s
while(hour==8)
{
ewg=direct;snr=(direct+left+3);D6=1;D4=1;D8=0;D3=0;D2=1;D5=1;D7=1;D10=1; //东西方向直行绿灯亮,南北方向红灯亮
do
{
rgset();
timeset();
display();
urgent() ;
if(aa==20)
{
aa=0;
ewg--;
snr--;
}
}while(ewg!=0);
ewg=left;snr=(left+3);D10=0;D8=1;D3=0;//东西方向左转绿灯亮,南北方向红灯亮
do
{
rgset();
timeset();
display();
urgent() ;
if(aa==20)
{
aa=0;
ewg--;
snr--;
}
}while(ewg!=0);
ewg=3; snr=3;D7=0;D3=0;D10=1; //东西方向黄灯亮,南北方向红灯亮
do
{
rgset();
timeset();
display();
urgent();
if(aa==20)
{ D7=0;delay(500);D7=1;
aa=0;
ewg--;
snr--;
}
}while(ewg!=0); ewg=(round-direct-left-3);snr=(round-2*left-direct-6); D6=0;D7=1;D3=1;D5=0;//东西方向红灯亮,南北方向直行绿灯亮
do {
rgset();
timeset();
display();
urgent();
if(aa==20)
{
aa=0;
ewg--;
snr--;
}
}while(snr!=0);
ewg=(3+left);snr=(left);D6=0;D2=0;D5=1;//D4=0;D10=0;D7=0;D5=0;D2=1; //东西方向红灯亮,南北方向左转绿灯亮
do {
rgset();
timeset();
display();
urgent();
if(aa==20)
{
aa=0;
ewg--;
snr--;
}
}while(snr!=0);
ewg=3;snr=3;D6=0;D4=0;D2=1;//东西方向红灯亮,南北方向黄灯亮
do {
rgset();
timeset();
display();
urgent();
if(aa==20)
{
aa=0;
ewg--;
snr--;
D4=0;delay(500);D4=1;
}
}while(snr!=0);
}
}
/********************************/
//###### 午高峰时段函数 ######//
/********************************/
void pmpeak()
{
round=120;direct=47;left=10; //设置午高峰阶段周期时间为120s,东西直行方向绿灯时间为47s,东西左转方向绿灯时间为10s
while((hour>=11)||(hour<13))
{
ewg=direct;snr=(direct+left+3);D6=1;D4=1;D8=0;D3=0;D2=1;D5=1;D7=1;D10=1; //东西方向直行绿灯亮,南北方向红灯亮
do {
rgset();
timeset();
display();
urgent() ;
if(aa==20)
{
aa=0;
ewg--;
snr--;
}
}while(ewg!=0);
ewg=left;snr=(left+3);D10=0;D8=1;D3=0;//东西方向左转绿灯亮,南北方向红灯亮
do {
rgset();
timeset();
display();
urgent() ;
if(aa==20)
{
aa=0;
ewg--;
snr--;
}
}while(ewg!=0);
ewg=3; snr=3;D7=0;D3=0;D10=1; //东西方向黄灯亮,南北方向红灯亮
do {
rgset();
timeset();
display();
urgent();
if(aa==20)
{ D7=0;delay(500);D7=1;
aa=0;
ewg--;
snr--;
}
}while(ewg!=0);
ewg=(round-direct-left-3);snr=(round-2*left-direct-6); D6=0;D7=1;D3=1;D5=0;//东西方向红灯亮,南北方向直行绿灯亮
do {
rgset();
timeset();
display();
urgent();
if(aa==20)
{
aa=0;
sng--;
snr--;
}
}while(snr!=0);
ewg=(3+left);snr=(left);D6=0;D2=0;D5=1;//D4=0;D10=0;D7=0;D5=0;D2=1; //东西方向红灯亮,南北方向左转绿灯亮
do {
rgset();
timeset();
display();
urgent();
if(aa==20)
{
aa=0;
ewg--;
snr--;
}
}while(snr!=0);
ewg=3;snr=3;D6=0;D4=0;D2=1; //东西方向红灯亮,南北方向黄灯亮
do {
rgset();
timeset();
display();
urgent();
if(aa==20)
{
aa=0;
ewg--;
snr--;
D4=0;delay(500);D4=1;
}
}while(snr!=0);
}
}
/*******************************/
//###### 夜间阶段函数 #######//
/*******************************/
void night( )
{
D6=1;
display();
timeset();
if(aa==12)
D7=D4=0;
if(aa==20)
{
aa=0;
D7=D4=1;
}
}
/****************************************/
//###### 周期和绿灯时间设置函数 ######//
/****************************************/
void rgset( )
{
P3=0xff;
while(key1==0) //按下K1键进入周期和绿灯时间设置
{
delay(10);
if(key1==0)
TR1=0;
display2();
if(key2==0) //再按下K2键周期时间加1
{
delay(10);
if(key2==0)
round++;
while(!key2)
display2();}
if(key3==0) //按下K3直行绿灯时间加1
{
delay(10);
if(key3==0)
direct++;
while(!key3)
display2();}
if(key4==0) //按下K4键左转绿灯时间加1
{
delay(10);
if(key4==0)
left++;
while(!key4)
display2();}
if(key6==0) //按下K6键周期时间减1
{
delay(10);
if(key6==0)
round--;
while(!key6)
display2();}
if(key7==0) //按下K7键直行绿灯时间减1
{
delay(10);
if(key7==0)
direct--;
while(!key7)
display2();}
if(key8==0) //按下K8键左转绿灯时间减1
{
delay(10);
if(key8==0)
left--;
while(!key8)
display2();}
}
TR1=1;
}
/*******************************************/
//###### LED灯倒计时数码管显示函数 ######//
/*******************************************/
void display()
{
minute2=snr/10;
minute1=snr%10;
second2=(ewg)/10;
second1=(ewg)%10;
P0=table[second1]; //数码管从右向左后第一、二两位控制东西方向绿灯倒计时显示
P2=0xfe;
delay(2);
P0=table[second2];
P2=0xfd;
delay(2);
P0=table[minute1];//数码管从右向左第三、四两位控制南北方向红灯倒计时显示
P2=0xfb;
delay(2);
P0=table[minute2];
P2=0xf7;
delay(2);
P2=0xff;
}
/**************************************************/
//###### 周期和绿灯时间设置数码管显示函数 ######//
/**************************************************/
void display2()
{ round3=round/100;
round2=(round%100)/10;
round1=(round%100)%10;
direct2=direct/10;
direct1=direct%10;
left2=left/10;
left1=left%10;
P0=table[direct1];//数码管从右向左第一、二两位控制直行绿灯时间显示
P2=0xfe;
delay(2);
P0=table[direct2];
P2=0xfd;
delay(2);
P0=table[round1]; //数码管从右向左第三、四、五两位控制周期时间显示
P2=0xfb;
delay(2);
P0=table[round2];
P2=0xf7;
delay(2);
P0=table[round3];
P2=0xef;
delay(2);
P0=table[left1]; //数码管从右向左第六、七位控制左转绿灯时间显示
P2=0xdf;
delay(2);
P0=table[left2];
P2=0xbf;
delay(2);
}
/************************************/
//###### 时间数码管显示函数 ######//
/************************************/
void display3()
{ hour2=hour/10;
hour1=hour%10;
minute2=minute/10;
minute1=minute%10;
second2=second/10;
second1=second%10;
P0=table[second1]; //数码管从右向左第一、二两位控制时间秒的显示
P2=0xfe;
delay(2);
P0=table[second2];
P2=0xfd;
delay(2);
P0=table[minute1]; //数码管从右向左第三、四两位控制时间分的显示
P2=0xfb;
delay(2);
P0=table[minute2];
P2=0xf7;
delay(2);
P0=table[hour1]; //数码管从右向左第五六两位控制时间小时的显示
P2=0xef;
delay(2);
P0=table[hour2];
P2=0xdf;
delay(2);
P2=0xff;
}
/****************************/
//###### 延时子函数 ######//
/****************************/
void delay(uint m)
{
int x,y;
for(x=m;x>0;x--)
for(y=100;y>0;y--);
}
/****************************/
//###### 函数初始化 ######//
/****************************/
void initial ( )
{
ewg=0;P1=0x00;
TMOD=0x11;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
TH1=(65536-50000)/256;
TL1=(65536-50000)%256;
EA=1;
ET0=1;
TR0=1;
ET1=1;
TR1=1;
}
/*********************************/
//###### 中断倒计时函数 #######//
/*********************************/
void time1( ) interrupt 3
{
TH1=(65536-50000)/256;
TL1=(65536-50000)%256;
aa++;
}
/**************************/
//###### 时间函数 ######//
/**************************/
void time0( ) interrupt 1
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
bb++;
if(bb==20)
{
bb=0;
second++;
if(second==60)
{second=0;minute++; }
if(minute==60)
{minute=0;hour++; }
if(hour==24)
hour=0 ;
}
}
/******************************/
//###### 时间设置函数 ######//
/******************************/
void timeset()
{
P3=0xff;
while(key5==0) //按下K5键进入时间设置
{
delay(10);
if(key5==0)
display3();
TR1=0;
if(key2==0) //再按下K2键时间小时加1
{
delay(10);
if(key2==0)
hour++;
while(!key2)
display3();}
if(key3==0) //按下K3键时间分钟加1
{
delay(10);
if(key3==0)
minute++;
while(!key3)
display3();}
if(key6==0) //按下K6键时间小时减1
{
delay(10);
if(key6==0)
hour--;
while(!key6)
display3();}
if(key7==0) //按下K7键时间分钟减1
{
delay(10);
if(key7==0)
minute--;
while(!key7)
display3();}
P3=0xff;
}
TR1=1;
}
/************************************************/
//###### 东西、南北方向紧急车辆处理函数 ######//
/************************************************/
void urgent()
{
TR1=0;
while(key4==0) //东西方向有紧急车
{
if(ewg
{
if(ewg<5)
{ewg=5;snr=8;}
}
else //此时东西方向是红灯
{
ewr=ewg;sng=snr; //保护倒计时初值
ewg=5;snr=5;D3=1;D5=0; //全红
TR1=1;
do
{
display();
if(aa==20)
{
aa=0;
ewg--;
snr--;
}
}
while(snr!=0);
ewg=ewr;snr=sng;
display();D3=0;D5=1;} //恢复刚才状态
}
while(key8==0) //南北有紧急车
{
if(ewg>snr) //东西项时间大于南北项时间(此时南北是绿灯)
{
if(snr<5)
{snr=5;ewg=8;}
}
else //此时南北为红灯
{
ewg1=ewg;snr1=snr; //保护倒计时初值
ewg=5;snr=5;D6=1;D8=0; //全红
TR1=1;
do
{
display();
if(aa==20)
{
aa=0;
ewg--;
snr--;
}
}
while(snr!=0);
ewg=ewg1;snr=snr1; //恢复刚才状态
display();
D6=0;D8=1;}
}
TR1=1;
}