目录
--------------------------------------本实验案例包含所有源程序以及原理图--------------------------------------
博主大概用五天时间完成硬件设计与软件设计
原理图pdsprj和源程序c在本文末(完整)
---------------------------------------------全文26图含流程图共11657字-------------------------------------------
设计基于单片机控制的城市道路十字路口交通灯控制系统。要求具有下述功能:
1、系统有两个状态,设置状态和显示状态,利用键盘进行两个状态间的切换。上电默认为设置状态;
2、系统为显示状态时,四个路口数码管从设置的时间(或默认的)倒计时时间开始倒计时;
3、设置状态时,利用KEY1~KEY3键盘设置各路口直行通行倒计时时间,设置的路口数码管闪烁显示,各路口的通行时间可以不相等,其中KEY2为加1键,KEY3为减1键,KEY1为特殊情况按键;
4、显示状态时,交通灯模组的四个LED板的数码管进行倒计时;LED板各组的红绿灯进行交通指示;如果一个LED板上有三个绿灯亮(左转、直行、右转),这时候数码管显示的是通行时间,否则,数码管显示的是等待时间;显示过程中按状态建键可以重新进入设置状态。
5、注意考虑有些不可预知情况和紧急情况(例如,晚上状态,人比较多的时候需要按键过人行道,出现事故情况等)
1号路口直行时间:10秒;
2号路口直行时间:10秒;
3号路口直行时间:10秒;
4号路口直行时间:10秒;
黄灯控制时间:5秒
基于单片机控制的城市道路十字路口交通灯控制系统,该系统需要基于现实十字路口的交通灯进行模拟设计。
需要具备的整体功能为:
车辆行驶保障与调度:交通灯控制系统需要明确的信号指示(红绿灯与倒计时显示),提供明确的交通规则和行车顺序,为行车者提供明确的指引。
行人过街保障与调度:交通灯控制系统需要考虑车辆的通行,也需要充分考虑行人的安全和调度,设立行人信号灯和过街时间。
交通车辆行人安全:交通灯控制系统需要降低交通事故的风险,保障道路交通车辆和行人的安全,避免出现由于系统出错而造成的交通事故。
需要具备的具体功能为:
显示状态功能、设置状态功能、紧急状态功能,接下来会对具体功能进行分析说明。
需求:交通灯模组的四个LED板的数码管进行倒计时,LED板各组的红绿灯进行交通指示;如果一个LED板上有绿灯亮(左转、直行、右转),这时候数码管显示的是通行时间,否则,数码管显示的是等待时间;显示过程中按状态键可以重新进入设置状态。
并且还需要结合每个路口的绿灯通行时间,进行显示系统控制,达到车辆、行人、交通安全的功能要求。
每个路口车辆直行时间TG(绿灯时间)10秒,警示时间TY(黄灯时间)5秒,红灯时间TR为等待其他三个路口通行的排队时间,具体公式:
根据上述公式得出红灯时间TR=45秒,由此我们得出每个路口车辆显示信号灯红黄绿时间。
对于人行道红绿灯,由分析可知,一个路口的车辆通行(直行和左转)时,随之其右侧的人行道通行,行人的绿灯通行时间为车辆绿灯通行时间+黄灯警示时间=15秒,红灯也随车辆的排队时间一致为45秒。
然后我们以四个路口车辆全通行为一个轮回,对每个路口的信号灯显示状态功能进行分析:
表一 路口信号灯显示状态示意表
注意:由于在实际生活中,车辆是停在路口信号灯的对面路口,司机平视对向路口的信号灯和倒计时,故此路口亮绿灯是对向路口的车辆通行,此路口亮红灯是对向车辆等待。
需求:设置状态时,利用KEY1~KEY5键盘设置各路口直行通行倒计时时间,设置的路口数码管显示,各路口的通行时间可以不相等,其中KEY1为开始键,KEY2为暂停/设置键,KEY3为加1键,KEY4为减1键,KEY5为紧急情况按键。
需求:紧急状态时,考虑有些不可预知情况和紧急情况,比如出现了交通事故或者救护车需要通行,这时候需要交管所对此十字路口交通信号灯系统进行控制,于是需要一个紧急按钮对全部路口信号灯进行控制。
设置和紧急状态具体功能如下表所示:
表二 按键功能表
根据1.1节的功能需求分析,明确了各个板块的功能以及需求:车辆LED数码管倒计时显示板块、车辆信号灯显示板块、行人信号灯显示板块、键盘输入板块,接下来对每个板块进行分析,对比几种可能的设计方案,分析其优缺点、开发可行性、经济可行性、总体可行性。
需求:能够控制四个路口的LED数码管8位段码以及2位位码,显示1、2、3、4、5、6、7、8、9数字,配合信号灯实现倒计时。
表三 车辆LED数码管显示板块方案对比表
说明:开发可行性、经济可行性、总体可行性的打分为“?”表示,“?”个数越多越好,在参考若干文献与查阅资料后,其判断具有一定的主观性。
需求:能够控制四个路口的交通红绿灯显示,实现亮红灯、黄灯、绿灯功能,配合LED数码管实现交通管制。
表四 车辆信号灯显示板块方案对比表
说明:开发可行性、经济可行性、总体可行性的打分为“?”表示,“?”个数越多越好,在参考若干文献与查阅资料后,其判断具有一定的主观性。
需求:能够控制四个路口的行人红绿灯显示,实现亮红灯、绿灯功能,配合车辆的信号灯显示实现行人的通行控制。
表五 行人信号灯显示板块方案对比表
说明:开发可行性、经济可行性、总体可行性的打分为“?”表示,“?”个数越多越好,在参考若干文献与查阅资料后,其判断具有一定的主观性。
需求:能够利用KEY1~KEY5键盘设置各路口直行通行倒计时时间,设置的路口数码管显示,各路口的通行时间可以不相等,其中KEY1为开始键,KEY2为暂停/设置键,KEY3为加1键,KEY4为减1键,KEY5为紧急情况按键。
表五 键盘板块方案对比表
说明:开发可行性、经济可行性、总体可行性的打分为“?”表示,“?”个数越多越好,在参考若干文献与查阅资料后,其判断具有一定的主观性。
综上,基于单片机控制的城市道路十字路口交通灯控制系统,采用以下设计方案:
表六 整体系统板块设计
根据上一节的方案选择,对整体系统的各个板块进行设计,同时基于单片机控制的城市道路十字路口交通灯控制系统,需要具备的功能也在1.1节有详细的说明,如上一节的表六所示,接下来对具体的方案原理进行分析。
在硬件方面,说明四大核心板块车辆LED数码管倒计时显示板块、车辆信号灯显示板块、行人信号灯显示板块、键盘输入板块的硬件设计。
表七 核心硬件设计说明表
在基于单片机控制的城市道路十字路口交通灯控制系统中,采用C语言程序对系统进行编程,对于软件来说,具体就涉及整体逻辑控制、寄存器配置、锁存器配置、I/O口配置。
同时,若整个系统工作,涉及各个板块之间的协调工作,故在软件程序方面也需要分板块进行设计。
这里在主程序中初始化了定时器/计数器的寄存器,设置了初始化按键状态,在一个主循环中,不断检测有无按键状态改变,然后进入城市道路十字路口交通灯控制系统,这个系统包含更详细的计时逻辑、车行道红绿灯显示人行道红绿灯显示,最后进行LED数码管显示程序。
这里的城市道路十字路口交通灯控制程序,是在主程序中被调用的模块程序,用来对十字路口的整体计时逻辑以及判断各个路口的状态,用一个名为miao的计时器表示现在系统的时间,不断判断路口状态,如果进入对应路口状态,即刻配置LED四个路口的数码管显示时间,控制车辆的红绿灯状态,控制人行道红绿灯控制。
注:这里是以北路口的绿灯状态+黄灯状态+结束状态为例子,其余三个路口的程序与北路口配置基本一致,在此不做赘述。
车行道的红绿灯控制程序受到上层【城市道路十字路口交通灯控制程序】控制,用一个light_status车辆红绿灯状态标志表示各个路口的信号灯状态,用switch判断状态,并进入对应的配置程序。
注意这里的车行道红绿灯配置,对应各个路口的信号灯引脚配置:
注:这里是以KEY1开启定时器、KEY3加1秒、KEY5紧急情况为例,暂停/设置、减1秒程序与上述程序基本一致,在此不做赘述。
表八 实验设备表
单片机加载编译后的hex程序,加载点击运行,默认为设置状态,并且默认四个路口倒计时和车行道、行人红绿灯显示,10秒、15秒、30秒、45秒,默认为北路口绿灯通行。
点击KEY1键开始运行系统,可以看到十字路口的各个路口红绿灯、LED倒计时显示屏、行人路口红绿灯,均正常按照设计运行。这里测试时间为四个路口全部通行时间(根据表一路口信号灯显示状态示意表)为60秒一个周期,每个路口15秒,10秒绿灯,5秒黄灯。
经过四轮不重复测试,系统均能准确按顺序运行,且符合功能设计需求,车辆行驶保障与调度、行人过街保障与调度、交通车辆行人安全。
点击KEY2键暂停运行系统,可以看到十字路口的各个路口红绿灯暂停、LED显示屏暂停倒计时、行人路口红绿灯暂停。
经过四轮各个路口的暂停测试,系统均能准确暂停。
点击KEY2暂停/设置按键后,再点击KEY3时间加1按键,可以对相应的LED显示屏暂停倒计时时间进行加一秒操作,此时各个路口倒计时也会相应的增加一秒,再次点击开始按键,系统按照加一秒后的状态进行继续运行。
经过对四个路口的时间加一测试,系统均能准确按照需求时间加一,这里由于篇幅限制只对北路口加1进行展示,其他路口均能准确加1,在此不做赘述。
同理,对于KEY4时间减1按键,也进行测试,对于四个路口的测试均按照功能需求正常运行。
经过测试,时间加1/时间减1功能均能正常运行,符合前期的功能设计与分析。
按下KEY5紧急情况按键,十字路口进入紧急情况,所有路口的显示与信号灯熄灭,人行道亮红灯,由交警进行管制,这个按键只有在非常紧急的情况才能正常使用。
经过测试,通过在系统运行状态,随机截图,可以看到LED数码管倒计时均能够正常显示,没有出现因为扫描时间延迟造成的时间未显示,说明设计的数码管扫描时延误差小于人肉眼能够捕捉到的最小延迟,对于系统的整体功能几乎没有影响,故数码管扫描时延误差可以忽略不计。
按照功能设计,四个路口均通行一轮的时间是15s+15s+15s+15s=60秒,按照理论设计,每次十字路口状态结束后,都会回到最初的状态,即:北路口10秒绿灯、东路口15秒红灯、南路口30秒红灯、西路口45秒红灯倒计时。
故进行4小时系统测试,利用秒表进行计时,结果显示4小时后,十字路口处于东路口8秒红灯倒计时状态。
故计时误差为:10s+5s+(15s-8s)=22s
由于误差落在3%之内,故可以接收十字路口状态轮回刷新的计时误差。
交通灯控制系统设计具有一定的复杂性,需要考虑到多个状态的切换、倒计时功能、键盘输入和LED数码管显示等方面。在实现过程中,我遇到了一些挑战,学习到了一些经验。学会了如何使用单片机来控制硬件设备,通过学习和理解各种芯片比如74HC573锁存器的功能和各种接口,我能够正确地连接和控制LED数码管、车辆信号灯和行人信号灯等设备。这让我对单片机控制技术有了更深入的了解。通过编写代码,能够根据系统状态和键盘输入来控制LED数码管的显示和倒计时功能。我还学到了一些软硬件协作的技巧。在设计过程中,需要考虑到单片机的I/O资源限制,合理分配和利用有限的资源,以实现各个功能模块的控制。同时,还学会了如何进行硬件与软件的调试和测试,以确保系统的稳定性和可靠性。不仅加深了我对单片机控制理解,还提高了解决问题的能力和动手实践的能力,这段时间完成大作业为今后在单片机开发领域的学习和工作打下了坚实的基础。
在单片机基础实验中,我学习了多个实验项目,包括红绿灯、流水灯、单数码管、八位数码管显示、独立按键、矩阵键盘、外部中断、10秒秒表、时分秒和串口通信等。这些实验不仅让我掌握了单片机的基本知识和应用技巧,还提高了我的动手实践能力和解决问题的能力。
通过这些实验的学习,我深入了解了单片机的内部结构和工作原理,掌握了常见芯片和模块的使用方法,提高了我的编程能力和硬件设计能力。同时,这些实验也让我更加懂得了实践是检验理论的唯一标准的道理。
硬件设计、软件设计、功能分析、模块设计、程序编写与调试等等,感谢张老师的教诲,在单片机课程的学习上给予了我很大的启迪与帮助。
[1]武玉升.基于单片机的智能交通灯控制系统仿真设计[J].电子世界,2018(21):118-119+122.DOI:10.19353/j.cnki.dzsj.2018.21.068.
[2]郭玉秀.基于单片机的十字路口交通灯的设计及仿真[J].现代制造技术与装备,2018(08):66-68.DOI:10.16107/j.cnki.mmte.2018.0724.
[3]于希辰.基于AT89C51单片机的数显交通灯设计[J].科技资讯,2017,15(27):39-40.DOI:10.16661/j.cnki.1672-3791.2017.27.039.
[4]淡海英,杨聪.基于单片机控制的十字路口交通灯设计与分析[J].电子测试,2017(13):9+8.DOI:10.16520/j.cnki.1000-8519.2017.13.003.
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
uchar code table[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x00}; //显示的段码
// 北1 北2 南1 南2 西1 西2 东1 东2
uchar code wei[] = {0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; // 两个并排的显示 十位 | 个位
// 车行道红绿灯 北绿 北黄 东绿 东黄 南绿 南黄 西绿 西黄
uchar code light_H[] = {0x21,0x22,0x0C,0x14,0x64,0xA4,0x24,0x24};
uchar code light_L[] = {0x09,0x09,0x09,0x09,0x08,0x08,0x03,0x05};
sbit J_duan=P3^0;
sbit J_wei=P3^1;
sbit N_ren=P2^4;
sbit E_ren=P2^5;
sbit S_ren=P2^6;
sbit W_ren=P2^7;
bit key_state;
sbit K1=P3^2; // 3.2引脚--按键 赋值为K1
sbit K2=P3^3; // 3.3引脚--按键 赋值为K2
sbit K3=P3^5; // 3.5引脚--按键 赋值为K3
sbit K4=P3^6; // 3.6引脚--按键 赋值为K4
sbit K5=P3^7; // 3.7引脚--按键 赋值为K5
uint Timer_count=0;
uint green_time = 10, yellow_time = 5; // 我设置的每个路口10秒绿灯,5秒黄灯
uint miao = 0, N_miao = 0, S_miao = 0, W_miao = 0, E_miao = 0, my_time=0 ,xianshi_allow =1;
// 延时函数
void DelayMS(uint x)
{
uchar i;
while(x--)
{
for(i=0;i<120;i++);
}
}
// 显示红绿灯倒计时
void show(uint duanma,uint weima)
{
P0=wei[weima];J_wei=1;J_wei=0;
P0=table[duanma];J_duan=1;J_duan=0;DelayMS(5);
}
// 车行道红绿灯
void light_show(uint light_status)
{
switch (light_status)
{
case 1: // 北红灯
P1 = light_H[0]; // 将P1口赋值为0x7B
P2 = (P2 & 0xF0) | light_L[0]; // 先将P2口低四位清零
break;
case 2:
P1 = light_H[1]; // 将P1口赋值为0x7B
P2 = (P2 & 0xF0) | light_L[1]; // 先将P2口低四位清零
break;
case 3:
P1 = light_H[2]; // 将P1口赋值为0x7B
P2 = (P2 & 0xF0) | light_L[2]; // 先将P2口低四位清零
break;
case 4:
P1 = light_H[3]; // 将P1口赋值为0x7B
P2 = (P2 & 0xF0) | light_L[3]; // 先将P2口低四位清零
break;
case 5:
P1 = light_H[4]; // 将P1口赋值为0x7B
P2 = (P2 & 0xF0) | light_L[4]; // 先将P2口低四位清零
break;
case 6:
P1 = light_H[5]; // 将P1口赋值为0x7B
P2 = (P2 & 0xF0) | light_L[5]; // 先将P2口低四位清零
break;
case 7:
P1 = light_H[6]; // 将P1口赋值为0x7B
P2 = (P2 & 0xF0) | light_L[6]; // 先将P2口低四位清零
break;
case 8:
P1 = light_H[7]; // 将P1口赋值为0x7B
P2 = (P2 & 0xF0) | light_L[7]; // 先将P2口低四位清零
break;
}
}
// 定时器时间
void Timer0_Rountine(void) interrupt 1
{
TL0=(65536-50000)%256; // 50ms
TH0=(65536-50000)/256;
Timer_count++; // Timer_count
}
// 路口计时
void Xianshi(void)
{
if(Timer_count==20) // 1
{
Timer_count=0; // 定时器清零
miao++;
}
if(miao>=(0*green_time+0*yellow_time+my_time) & miao<(1*green_time+0*yellow_time+my_time)) // 北绿灯
{
N_miao = 1*green_time+0*yellow_time+my_time - miao; // 北计时
E_miao = 1*green_time+1*yellow_time+my_time - miao;
S_miao = 2*green_time+2*yellow_time+my_time - miao;
W_miao = 3*green_time+3*yellow_time+my_time - miao;
light_show(1);
N_ren = 0;
E_ren = 1;
S_ren = 0;
W_ren = 0;
}
else if(miao>=(1*green_time+0*yellow_time+my_time) & miao<(1*green_time+1*yellow_time+my_time)) // 北黄灯
{
N_miao = 1*green_time+1*yellow_time+my_time - miao; // 北计时
E_miao = 1*green_time+1*yellow_time+my_time - miao;
S_miao = 2*green_time+2*yellow_time+my_time - miao;
W_miao = 3*green_time+3*yellow_time+my_time - miao;
light_show(2);
N_ren = 0;
E_ren = 1;
S_ren = 0;
W_ren = 0;
}
else if(miao>=(1*green_time+1*yellow_time+my_time) & miao<(2*green_time+1*yellow_time+my_time)) // 东绿灯
{
N_miao = 4*green_time+4*yellow_time+my_time - miao;
E_miao = 2*green_time+1*yellow_time+my_time - miao; // 东计时
S_miao = 2*green_time+2*yellow_time+my_time - miao;
W_miao = 3*green_time+3*yellow_time+my_time - miao;
light_show(3);
N_ren = 0;
E_ren = 0;
S_ren = 1;
W_ren = 0;
}
else if(miao>=(2*green_time+1*yellow_time+my_time) & miao<(2*green_time+2*yellow_time+my_time)) // 东黄灯
{
N_miao = 4*green_time+4*yellow_time+my_time - miao;
E_miao = 2*green_time+2*yellow_time+my_time - miao; // 东计时
S_miao = 2*green_time+2*yellow_time+my_time - miao;
W_miao = 3*green_time+3*yellow_time+my_time - miao;
light_show(4);
N_ren = 0;
E_ren = 0;
S_ren = 1;
W_ren = 0;
}
else if(miao>=(2*green_time+2*yellow_time+my_time) & miao<(3*green_time+2*yellow_time+my_time)) // 南绿灯
{
N_miao = 4*green_time+4*yellow_time+my_time - miao;
E_miao = 5*green_time+5*yellow_time+my_time - miao;
S_miao = 3*green_time+2*yellow_time+my_time - miao; // 南计时
W_miao = 3*green_time+3*yellow_time+my_time - miao;
light_show(5);
N_ren = 0;
E_ren = 0;
S_ren = 0;
W_ren = 1;
}
else if(miao>=(3*green_time+2*yellow_time+my_time) & miao<(3*green_time+3*yellow_time+my_time)) // 南黄灯
{
N_miao = 4*green_time+4*yellow_time+my_time - miao;
E_miao = 5*green_time+5*yellow_time+my_time - miao;
S_miao = 3*green_time+3*yellow_time+my_time - miao; // 南计时
W_miao = 3*green_time+3*yellow_time+my_time - miao;
light_show(6);
N_ren = 0;
E_ren = 0;
S_ren = 0;
W_ren = 1;
}
else if(miao>=(3*green_time+3*yellow_time+my_time) & miao<(4*green_time+3*yellow_time+my_time)) // 西绿灯
{
N_miao = 4*green_time+4*yellow_time+my_time - miao;
E_miao = 5*green_time+5*yellow_time+my_time - miao;
S_miao = 6*green_time+6*yellow_time+my_time - miao;
W_miao = 4*green_time+3*yellow_time+my_time - miao; // 西计时
light_show(7);
N_ren = 1;
E_ren = 0;
S_ren = 0;
W_ren = 0;
}
else if(miao>=(4*green_time+3*yellow_time+my_time) & miao<(4*green_time+4*yellow_time+my_time)) // 西黄灯
{
N_miao = 4*green_time+4*yellow_time+my_time - miao;
E_miao = 5*green_time+5*yellow_time+my_time - miao;
S_miao = 6*green_time+6*yellow_time+my_time - miao;
W_miao = 4*green_time+4*yellow_time+my_time - miao; // 西计时
light_show(8);
N_ren = 1;
E_ren = 0;
S_ren = 0;
W_ren = 0;
}
else if(miao==(4*green_time + 4*yellow_time+my_time)) // 所有路口通过清零
{
miao = 0; // 秒清零
}
}
void main()
{
P0=0x00;
TMOD=0X01;
TL0=(65536-50000)%256;
TH0=(65536-50000)/256;
TR0=0; // 关闭中断
ET0=0;
EA=0;
key_state=1; // 初始化按钮状态为0
while(1)
{
if(key_state != K1) // 按键检测 -- 开启中断 -- 开始
{
DelayMS(5); //消抖
key_state=K1; // 按下按键 key_state = K1 = 0
if(key_state ==0)
{
xianshi_allow = 1;
TR0=1;
ET0=1;
EA=1;
}
}
else if(key_state != K2) // 按键检测 -- 暂停
{
DelayMS(5); //消抖
key_state=K2; // 按下按键 key_state = K2 = 0
if(key_state ==0)
{
xianshi_allow = 1;
TR0=0;
ET0=0;
EA=0;
}
}
else if(key_state != K3) // 按键检测 -- 增1
{
DelayMS(100); //消抖
key_state=K3; // 按下按键 key_state = K3 = 0
if(key_state ==0)
{
my_time++;
}
}
else if(key_state != K4) // 按键检测 -- 减1
{
DelayMS(100); //消抖
key_state=K4; // 按下按键 key_state = K4 = 0
if(key_state ==0)
{
my_time--;
}
}
else if(key_state != K5) // 按键检测 -- 紧急事件 -- 全红灯
{
DelayMS(5); //消抖
key_state=K5; // 按下按键 key_state = K5 = 0
if(key_state ==0)
{
TR0=0;
ET0=0;
EA=0;
xianshi_allow = 0; // 全部不显示
P1 = P2= 0x00;
J_wei=1;J_wei=0;
}
}
if(xianshi_allow == 1)
{
Xianshi(); // 计时
show(N_miao/10,0);
show(N_miao%10,1);
show(E_miao/10,2);
show(E_miao%10,3);
show(S_miao/10,4);
show(S_miao%10,5);
show(W_miao/10,6);
show(W_miao%10,7);
}
}
}
如果对你有帮助的话,请给博主点个赞吧👍
如果对你有收获的话,请点个收藏吧?
~~~
2023.12.20
渝北仙桃数据谷