基于51单片机的交通灯设计
指导教师:
学院:
班级:
姓名:
学号:
一、设计目的与任务1、熟练的掌握KeilC51集成开发环境调试功能的使用2、将所学的C51单片机的理论知识运用到实验中3、简单的掌握仿真软件的proteus的应用设计一个以单片机为中心控制系统,以LED灯和数码管显示为外设,实现十字路口交通灯的状态显示。二、设计要求1、以proteus仿真软件为核心,画出原理仿真图。
2、以Keil C51编程软件为主体,编写芯片内部执行程序
三、总体设计思路
本设计以单片机为核心,以LED数码管作为倒计时指示,根据设计的要求我们考虑了各功能模块的几种设计方案,以求最佳方案,实现实时显示系统各种状态,系统还增设了根据交通拥挤情况可分别设置主干道和次干道的通行时间,以提高效率,缓减交通拥挤。系统总体设计框图如图1-1所示。
*
图1-1 系统总体设计框图
1.电源提供方案
为使模块稳定工作,须有可靠电源。本次设计考虑了两种电源方案:
方案一:采用独立的稳压电源。此方案的优点是稳定可靠,且有各种成熟电路可供选用;缺点是各模块都采用独立电源,会使系统复杂,且可能影响电路电平。
方案二:采用单片机控制模块提供电源。该方案的优点是系统简明扼要,节约成本;缺点是输出功率不高。
综上所述,选择第二种方案。
2.显示界面方案
该系统要求完成倒计时功能。基于上述原因,本次设计考虑了两种方案:
方案一:完全采用点阵式LED显示。这种方案功能强大,可方便的显示各种英文字符,汉字,图形等,但实现复杂,且须完成大量的软件工作。
方案二:完全采用数码管显示。这种方案优点是实现简单,可以完成倒计时功能。缺点是功能较少,只能显示有限的符号和数码字符。根据本设计的要求,方案二已经满足了要求,所以本次设计采用方案二以实现系统的显示功能。
3.输入方案
这里同样讨论了两种方案:
方案一:采用8155扩展I/O口、键盘及显示等。该方案的优点是使用灵活可编程,并且有RAM及计数器。若用该方案,可提供较多I/O口,但操作起来稍显复杂。
方案二:直接在I/O口线上接上按键开关。因为设计时精简和优化了电路,所以剩余的端口资源还比较多,我们使用六个按键,分别是P16、P17、P27、P30、P32、P33,依次完成倒计时加1、倒计时减1、调完确认、调时方向切换、南北强行和东西强行等功能。
由于该系统是对交通灯及数码管的控制,只需用单片机本身的I/O口就可实现,且本身的计数器及RAM已经够用,故选择方案二。
硬件设计是整个系统的基础,要考虑的方方面面很多,除了实现交通灯基本功能以外,主要还要考虑如下几个因素:①系统稳定度;②器件的通用性或易选购性;③软件编程的易实现性;④系统其它功能及性能指标;因此硬件设计至关重要。现从各功能模块的实现逐个进行分析探讨。
总体设计
本设计以单片机为控制核心,采用模块化设计,共分以下几个功能模块:单片机控制系统、键盘及状态显示、倒计时模块等。 交通灯的总体设计原理如3-0图所示:
单片机作为整个硬件系统的核心,它既是协调整机工作的控制器,又是数据处理器。它由单片机振荡电路、复位电路等组成。
键盘及状态显示,开关键盘输入交通灯初始时间,通过单片机P1输入到系统。
系统采用双数码管倒计时计数功能,最大显示数字99。
友好的人机界面、灵活的控制方式、优化的物理结构是本设计的亮点。
单片机最小系统
1.振荡电路
AT89C51是内部具有振荡电路的单片机,只需在18脚和19脚之间接上石英晶体,给单片机加工作所需直流电源,振荡器就开始振荡起来。振荡电路就为单片机工作提供了所需要的时钟脉冲信号,是单片机的内部电路、单片机的内部程序(若有)开始工作。振荡电路不工作,整个单片机电路都不能正常工作。AT89C51常外接6MHz、12MHz的石英晶体,18脚和19脚分别对地接了一个20pF的电容,目的是防止单片机自激。若从18脚输入外部时钟脉冲,则19脚接地。
2.复位电路
复位电路就是在RST端(9脚)外接的一个电路,目的是使单片机上的电开始工作时,内部电路从初始状态开始工作,或者在工作中人为让单片机重新从初始状态开始工作。在时钟工作的情况下,只要复位引脚高电平保持在两个机器周期以上的时间,AT89C51便能完成系统重置的各项工作,使得内部特殊功能寄存器的内容均被设置成已知状态,并且从地址0000H处读入程序代码而执行程序。单片机最小系统电路如图3-1所示:
图3-1 单片机最小系统电路原理图
显示及其驱动模块键盘与状态显示功能
键盘在本设计中用于紧急情况的手动控制装置,以及定时时间的设置等功能,起到了不可缺少的重要作用。当定时器定时为1秒时程序跳转到时间显示及信号灯显示子程序,它将依次显示信号灯时间,同时一直显示信号灯的颜色,这时在返回定时子程序定时1秒,在显示黄灯的下一个时间,这样依次把所有的时间显示完后在重新给时间计数器赋初值,重新进入循环。键盘电路如图3-2所示。
图3-2 键盘电路
倒计时计数功能
本系统使用数码管完成倒计时显示功能。以南北方向为例,数码管显示的数值从绿灯的设置时间最大值往下减,每秒钟减1,一直减到1。然后又从红灯的设置时间最大值往下减,一直减到1。接下来又显示绿灯时间,如此循环。
系统共有4个两位的LED数码管,分别放置在模拟交通灯控制板上的四个路口。因为四个方向的数码管应该显示同样的内容,所以我们可以把它们同样对待。也就是说各个方向的数码管个位(把数码管第二位定义为个位,第一位定义为十位)用一根信号线控制,十位用另一根信号线控制。这里采用动态显示。LED数码管如图3-3所示。
图3-3 LED数码管
根据该系统设计的功能要求选择所用元器件
软件在硬件平台上构筑,完成各部分硬件的控制和协调。系统功能是由软硬件共同实现的,由于软件的可伸缩性,最终实现的系统功能可强可弱,差别可能很大。因此,软件是本系统的灵魂。软件采用模块化设计方法,不仅易于编程和调试,也可减小软件故障率和提高软件的可靠性。同时,对软件进行全面测试也是检验错误排除故障的重要手段。这里我们选用了移值性好、结构清晰、能进行复杂运算的C语言来实现编程。
3.1 软件总体设计
软件总体设计主要完成各部分的软件控制和协调。本系统主程序模块主要完成的工作是对系统的初始化,发送显示数据,同时对键盘进行扫描,等待外部中断,以及根据所需要的功能进行相应的操作。其流程图如图4-1所示。
图4-1 软件总体流程图
软件主要子程序设计 紧急状态子程序设计
1.在紧急状态下,只有紧急状态手动控制按键才可以使所有的LED都被置为红灯,车辆禁行、行人通行。紧急情况结束后再转成自动状态。程序流程如图4-2所示。
图4-2 紧急状态子程序
设置状态子程序设计
设置状态子程序如图4-3所示。
图4-3 设置状态子程序
在设置状态,按下按键1(P16)开始设置南北的红灯时间,按下按键2(P17)设置南北的绿灯时间,按下按键3(P27)返回正常运行状态。红灯和绿灯的时间最大可以设为99,超出99的时候会从50开始重新计数。它包含倒计时调整和紧急状态两个状态。主程序中放了一个按键的判断指令,当有按键按下的时候,程序就自动的跳转到按键子程序处理。当检测到按键2(P17)键按下的时候就自动返回到主程序。当出现紧急的情况的时候,按下按键3(P27)就切换到紧急状态,当紧急事件处理完毕的时候,按下按键2(P17),就可以返回正常状态。
键盘模块子程序设计
键盘是人机进行交互的重要接口之一。用户通过按键对仪器下达命令,仪器对按键译码获得相应的键值,并执行相应的命令程序。键盘部分的软件实现主要是指对键盘管理进行编程,从而成功地读取键盘值,实现相应的功能。键盘实现的程序流程图如图4-4所示。
图4-4 键盘实现的程序流程图
根据上述流程图编写程序如下:
#include <reg51.h>
#include<intrins.h>
#define ucharunsigned char
#define uint unsigned int
sbit k1=P1^6;
sbit k2=P1^7;
sbit k3=P2^7;
sbit k4=P3^0;
sbityellowled_nb=P1^4; //南北黄灯
sbityellowled_dx=P1^1; //东西黄灯
uchar codetable[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
uchar data dig; //位选
uchar data led; //偏移量
uchar data buf[4];
uchar datasec_dx=20;//东西数码指示值
uchar datasec_nb=20;//南北数码指示值
uchar dataset_timedx=20;
uchar dataset_timenb=20;//倒计时设置的键值保存
uchar data b;//定时器中断次数
bit time;//灯状态循环标志
bit int0_time;//中断强行标志
bit set;//调时方向切换键标志
void delay(int ms);//延时子程序
void key();//按键扫描子程序
void key_to1();//键处理子程序
void key_to2();
void display();//显示子程序
void main()
{
TMOD=0X01;
TH0=0X3C;
TL0=0XB0;
EA=1;
ET0=1;
TR0=1;
EX0=1;
EX1=1;
P1=0Xf3;// 东西通行
while(1)
{
key(); //调用按键扫描程序
display(); //调用显示程序
}
}
void key() //按键扫描子程序
{
if(k1!=1)
{
delay(10);
if(k1!=1)
{
while(k1!=1);
key_to1();
}
}
if(k2!=1)
{
delay(10);
if(k2!=1)
{
while(k2!=1);
key_to2();
}
}
if(k4!=1)
{
delay(10);
if(k4!=1)
{
while(k4!=1);
set=!set;
}
}
if(k3!=1&&int0_time==1)
{
TR0=1; //启动定时器
sec_nb=20;
sec_dx=20;
int0_time=0;//清标志
} else if(k3!=1&&int0_time==0)
{
char set_timenb,set_timedx;
TR0=1;
set_timenb=sec_nb;
set_timedx=sec_dx; //设置的键值返回保存
}
}
void display()
{
buf[1]=sec_dx/10; //第1位 东西秒十位
buf[2]=sec_dx%10; //第2位 东西秒个位
buf[3]=sec_nb/10; //第3位 南北秒十位
buf[0]=sec_nb%10; //第4位 南北秒个位
P0=table[buf[led]];
delay(2); //先延时,提前显示一位了
P2=dig;
dig=_crol_(dig,1);
led++;
if (led==4)
{led=0;
dig=0xfe;
}
}
void time0(void)interrupt 1 using 1 //定时中断子程序
{
b++;
if(b==10) // 定时器中断次数。
{
b=0;
sec_dx--;
sec_nb--;
/******************南北黄灯闪烁判断*************************/
if(sec_nb==3&&time==0)
{
yellowled_nb=1;//南北黄灯亮
delay(300);
yellowled_nb=0;
}
if(sec_nb==2&&time==0)
{
yellowled_nb=1;//南北黄灯亮
delay(300);
yellowled_nb=0;
}
if(sec_nb==1&&time==0)
{
yellowled_nb=1;
delay(300);
yellowled_nb=0;
}
/*******************东西黄灯闪判断************************/
if(sec_dx==3&&time==1)
{
yellowled_dx=1;//南北黄灯亮
delay(300);
yellowled_dx=0;
}
if(sec_dx==2&&time==1)
{
yellowled_dx=1;//南北黄灯亮
delay(300);
yellowled_dx=0;
}
if(sec_dx==1&&time==1)
{
yellowled_dx=1;
delay(300);
yellowled_dx=0;
}
/*******************************************/
if(sec_dx==0||sec_nb==0) //东西或南北先到达1S时即开始重新计时
{
sec_dx=set_timedx;
sec_nb=set_timenb; //第一次循环结束重置
if(time==1)
{
P1=0XF3; //东西通行
}
else
{
P1=0xde; //南北通行
}
time=!time; //取反
}
}
}
void key_to1()
{
TR0=0; //关定时器
if(set==0)
sec_nb++; //南北加1S
else
sec_dx++;//东西加1S
if(sec_nb==100)
sec_nb=1;
if( sec_dx==100)
sec_dx=1;//加到100置1
}
void key_to2()
{
TR0=0;//关定时器
if(set==0)
sec_nb--; //南北减1S
else
sec_dx--; //东西减1S
if(sec_nb==0)
sec_nb=99;
if( sec_dx==0)
sec_dx=99;//减到1重置99
}
void int0(void)interrupt 0 using 1 //东西强行
{
TR0=0;
P1=0XF3;
sec_dx=88;
sec_nb=88;
int0_time=1;
}
void int1(void)interrupt 2 using 1 //南北强行
{
TR0=0;
P1=0XDE;
sec_nb=88;
sec_dx=88;
int0_time=1;
}
void delay(int ms)
{
uint j,k;
for(j=0;j<ms;j++)
for(k=0;k<124;k++);
}
系统调试与测试系统操作说明
本设计采用的是开关键盘,共6个键。键盘用来输入倒计时时间数字信息;功能菜单选择键则用于主次干道通行时间分别设置、确定、取消(即调时方向的切换、倒计时的加减、东西强行、南北强行,调完确认)等功能。
系统分为两个状态:设置状态和显示状态。利用键盘可以进行两个状态间的切换;开机时,系统为显示状态,此时显示四个路口数码管从默认的倒计时时间开始倒计时;显示状态时,交通灯模组的四个LED数码管进行倒计时;显示过程中按键可以重新进入设置状态。
调试
根据电路功能逐级进行:
1.通行方式功能调试:对行人和行车方向指示灯亮度和驱动电路调试;
2.倒计时功能调试:数码管亮度调试;
3.紧急情况手动控制功能调试:包括按键功能的调试。
调试结果如下图所示:
设计总结
通过本次课程设计,我深深的体会到了作为一个硬件工程师的艰辛。即使做一个小小的项目,都需要做这么多细致入微的工作,必须考虑到问题的任何一个细节,否则最后也将是功败垂成。
原理图设计: 当我们选取了这样一个题目,我们就开始收集相关的各种资料,对题目有个大致的了解,规划一下设计的任务将要完成哪些功能。然后就具体的每一项功能应该怎样具体的设计,例如用什么方法完成这一功能,这种想法是否合理,比较使用哪个芯片来完成这项功能。经过长时间的查阅资料、思索、推敲,最后定出了这次设计的原理图。
硬件焊接:开始制作实物之前,按照老师的要求先进行整板的规划,这是一个非常关键的步骤,因为当你焊接上器件之后将会很难修改。结果发现了真的还有一些不足,比如在画板的过程中我们居然忘记留出电源接口,还有一些两根电源线没有和其他线接到一块,另外我给按键留的引脚的孔太小了,数码管的引脚情况也给弄错了,这些都是因为经验不够和粗心造成的。这也都给以后的学习留下了经验和教训,必须先拿到或熟悉芯片才能确定引脚的间距以及大小,制板过程必须要细心。发现这些错误,在焊接过程中我们采取了一系列的措施来补救这些错误。关于焊接,因为自己的水平确实不怎么样,这需要一定的经验和技巧,但是我却是迟迟把握不到这种技巧。刚开始烙铁和焊锡配合不到一块,然后就是焊锡的量的控制问题,始终达不到老师说明的那种效果,这些都说明了我在实际动手能力方面还有待加强
编程调试:在整个程序的编写过程中,研究每个子程序是否可行,我是通过Keil C和Proteus两个软件来实现的。Proteus是一个单片机的仿真软件,发现它之后真的很受用,通过它可以不用连接硬件就能检查程序是否可行。Keil C则帮助我检查程序是否存在语法错误之类的问题,还可以生成hex文件,供proteus软件仿真使用。通过这两个软件,我完成了整个设计程序的编写与调试工作。
通过上面的这个步骤,把程序调试好,接下来就是真正的硬件连接调试了。程序既然已经在仿真的软件上通过认证,如果连接上硬件不可行的话,说明在硬件上某个部分存在一定的问题。这点得到了验证:硬件模拟的时候,紧急情况用的开关有一个有问题,按下的时候没有反应。用万用表检测发现,开关内部的连接没有错误,但是当开关按下的时候,不是接通的,说明此开关有问题。于是我又将有问题的开关进行了更换,结果硬件连接调试很顺利。
通过这次毕业设计,使我得到了一次用专业知识、专业技能分析和解决问题全面系统的锻炼。使我在单片机的基本原理、单片机应用系统开发过程,以及在常用编程设计思路技巧的掌握方面都能向前迈了一大步,为日后成为合格的应用型人才打下良好的基础。
完整的Word格式文档51黑下载地址:
基于单片机的交通信号灯模拟控制系统.doc
(147 KB, 下载次数: 50)
|