找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1644|回复: 1
打印 上一主题 下一主题
收起左侧

交通灯

[复制链接]
跳转到指定楼层
楼主
ID:369892 发表于 2018-7-12 08:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一、设计内容
本设计以单片机为核心,以LED数码管作为倒计时指示,根据设计的要求我们考虑了各功能模块的几种设计方案,以求最佳方案,实现实时显示系统各种状态,系统还增设了根据交通拥挤情况可分别设置主干道和次干道的通行时间,以提高效率,缓减交通拥挤。系统总体设计框图如图所示。
交通灯控制的框图如下图所示,主要有控制电路、按键电路、晶振电路、复位电路、显示电路、电源电路等电路组成。
二、设计方案1.       总体方案
本设计以单片机为核心,以LED数码管作为倒计时指示,根据设计的要求我们考虑了各功能模块的几种设计方案,以求最佳方案,实现实时显示系统各种状态,系统还增设了根据交通拥挤情况可分别设置主干道和次干道的通行时间,以提高效率,缓减交通拥挤。系统总体设计框图如图所示。
交通灯控制的框图如下图所示,主要有控制电路、按键电路、晶振电路、复位电路、显示电路、电源电路等电路组成。


   

电源提供方案
为使模块稳定工作,须有可靠电源。本次设计考虑了两种电源方案:
方案一:采用独立的稳压电源。此方案的优点是稳定可靠,且有各种成熟电路可供选用;缺点是各模块都采用独立电源,会使系统复杂,且可能影响电路电平。
方案二:采用单片机控制模块提供电源。该方案的优点是系统简明扼要,节约成本;缺点是输出功率不高。
综上所述,选择第二种方案。
显示界面方案
该系统要求完成倒计时功能。基于上述原因,本次设计考虑了两种方案:
方案一:完全采用点阵式LED显示。这种方案功能强大,可方便的显示各种英文字符,汉字,图形等,但实现复杂,且须完成大量的软件工作。
方案二:完全采用数码管显示。这种方案优点是实现简单,可以完成倒计时功能。缺点是功能较少,只能显示有限的符号和数码字符。根据本设计的要求,方案二已经满足了要求,所以本次设计采用方案二以实现系统的显示功能。
输入方案
这里同样讨论了两种方案:
方案一:采用8155扩展I/O口、键盘及显示等。该方案的优点是使用灵活可编程,并且有RAM及计数器。若用该方案,可提供较多I/O口,但操作起来稍显复杂。
方案二:直接在I/O口线上接上按键开关。因为设计时精简和优化了电路,所以剩余的端口资源还比较多。
由于该系统是对交通灯及数码管的控制,只需用单片机本身的I/O口就可实现,且本身的计数器及RAM已经够用,故选择方案二。
2.       硬件电路设计
硬件设计是整个系统的基础,要考虑的方方面面很多,除了实现交通灯基本功能以外,主要还要考虑如下几个因素:①系统稳定度;②器件的通用性或易选购性;③软件编程的易实现性;④系统其它功能及性能指标;因此硬件设计至关重要。现从各功能模块的实现逐个进行分析探讨。
总体设计
本设计以单片机为控制核心,采用模块化设计,共分以下几个功能模块:单片机控制系统、键盘及状态显示、倒计时模块等。
单片机作为整个硬件系统的核心,它既是协调整机工作的控制器,又是数据处理器。它由单片机振荡电路、复位电路等组成。
系统采用双数码管倒计时计数功能,最大显示数字99。
友好的人机界面、灵活的控制方式、优化的物理结构是本设计的亮点。
单片机的选择
单片机微型计算机是微型计算机的一个重要分支,也是颇具生命力的机种。单片机微型计算机简称单片机,特别适用于控制领域,故又称为微控制器。
通常,单片机由单块集成电路芯片构成,内部包含有计算机的基本功能部件:中央处理器、存储器和I/O接口电路等。因此,单片机只需要和适当的软件及外部设备相结合,便可成为一个单片机控制系统。
单片机经过1、2、3、3代的发展,正朝着多功能、高性能、低电压、低功耗、低价格、大存储容量、强I/O功能及较好的结构兼容性方向发展。其发展趋势不外乎以下几个方面:
1、多功能         单片机中尽可能地把所需要的存储器和I/O口都集成在一块芯片上,使得单片机可以实现更多的功能。比如A/D、PWM、PCA(可编程计数器阵列)、WDT(监视定时器---看家狗)、高速I/O口及计数器的捕获/比较逻辑等。    有的单片机针对某一个应用领域,集成了相关的控制设备,以减少应用系统的芯片数量。例如,有的芯片以51内核为核心,集成了USB控制器、SMART CARD接口、MP3解码器、CAN或者I*I*C总线控制器等,LED、LCD或VFD显示驱动器也开始集成在8位单片机中。2、高效率和高性能为了提高执行速度和执行效率,单片机开始使用RISC、流水线和DSP的设计技术,使单片机的性能有了明显的提高,表现为:单片机的时钟频率得到提高;同样频率的单片机运行效率也有了很大的提升;由于集成度的提高,单片机的寻址能力、片内ROM(FLASH)和RAM的容量都突破了以往的数量和限制。 由于系统资源和系统复杂程度的增加,开始使用高级语言(如C语言)来开发单片机的程序。使用高级语言可以降低开发 难度,缩短开发周期,增强软件的可读性和可移植性,便于改进和扩充功能。3、低电压和低功耗   单片机的嵌入式应用决定了低电压和低功耗的特性十分重要。由于CMOS等工艺的大量采用,很多单片机可以在更低的电压下工作(1.2V或0.9V),功耗已经降低到uA级。这些特性使得单片机系统可以在更小电源的支持下工作更长的时间。4、低价格    单片机应用面广,使用数量大,带来的直接好处就是成本的降低。目前世界各大公司为了提高竞争力,在提高单片机性能的同时,十分注意降低其产品的价格。下面大致介绍一下单片机的主要应用领域和特点。(1)家用电器领域    用单片机控制系统取代传统的模拟和数字控制电路,使家用电器(如洗衣机、空调、冰箱、微波炉、和电视机等)功能更完善,更加智能化和易于使用。(2)办公自动化领域   单片机作为嵌入式系统广泛应用于现代办公设备,如计算机的键盘、磁盘驱动、打印机、复印机、电话机和传真机等。(3)商业应用领域    商业应用系统部分与家用和办公应用系统相似,但更加注重设备的稳定性、可靠性和安全性。商用系统中广泛使用的电子计量仪器、收款机、条形码阅读器、安全监测系统、空气调节系统和冷冻保鲜系统等,都采用了单片机构成的专用系统。与通用计算机相比,这些系统由于比较封闭,可以更有效地防止病毒和电磁干扰等,可靠性更高。(4)工业自动化    在工业控制和机电一体化控制系统中,除了采用工控计算机外,很多都是以单片机为核心的单片机和多机系统。(5)智能仪表与集成智能传感器    目前在各种电气测量仪表中普遍采用了单片机应用系统来代替传统的测量系统,使得测量系统具有存储、数据处理、查询及联网等智能功能。将单片机和传感器相结合,可以构成新一代的智能传感器。它将传感器变换后的物理量作进一步的变化和处理,使其成为数字信号,可以远距离传输并与计算机接口。(6)现代交通与航空航天领域    通常应用于电子综合显示系统、动力监控系统、自动驾驶系统、通信系统以及运行监视系统等。这些领域对体积、功耗、稳定性和实时性的要求往往比商用系统还要高,因此采用单片机系统更加重要。单片机的基本结构
   AT89S52单片机是一款低功耗、低电压、高性能CMOS8位单片机,片内含8KB(可经受1000次擦写周期)的FLASH可编程可反复擦写的只读程序存储器(EPROM),器件采用CMOS工艺和ATMEL公司的高密度,非易失性存储器(NURAM)技术制造,其输出引脚和指令系统都与MCS-51兼容,片内的FLASH存储器允许在系统内可改编程序或用常规的非易失性存储编程器来编程。因此,AT89C52是一种功能强,灵活性高且价格合理的单片机,可方便的应用在各个控制领域[1]。
AT89S52具有以下主要性能:
1.8KB可改编程序FLASH存储器;
2.全表态工作 :0~24HZ;
3.256X8字节内部RAM;
4.32个外部双向输入,输出(I、O)口;
引脚说明如图2-2。


   

引脚功能说明如下[2]:
VCC:电源电压。
GND:地。
P0口:P0口是一组8位漏极开路型双向I/O口,也即地址/数据线复用口。作为输出口时,每位能吸收电流的方式驱动8个TTL逻辑门电路,对端口写“1”可作为高阻抗输入端。
在访问外部数据储存器或程序储存器时,这组口线分时转换地址(低8位)和数据总线复用,在访问期间激活内部上拉电阻。FLASH编程时,P0口接收指令字节,而在程序校验时,输出指令字节,校验时,要求外接上拉电阻。
P1口:P1是一个带内部上拉电阻的8位双向I/O口,P1的输出缓冲级可驱动(吸收或输出电流)4个TTL逻辑门电路。对端口写“1”,通过内部的上拉电阻把端口拉到高电平,此时可作为输入口。作为输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出一个电流。FLASH编程和程序校验期间,P1接收低8位地址。
P2口:P2是一个带内部上拉电阻的8位双向I/O口,P2的输出缓冲级可驱动(吸收或输出电流)4个TTL逻辑门电路。对端口写“1”,通过内部的上拉电阻把端口拉到高电平,此时可作为输入口。作为输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出一个电流。在访问外部程序储存器或16位地址的外部数据储存器(例如执行MOVX@DPTR指令)时,P2口送出高8位地址数据。在访问8位地址的外部数据储存器(例如执行MOVX@RI指令)时,P2口线上的内容(也即特殊功能寄存器(SFR)区中R2寄存器的内容),在整个访问期间不改变。P3口:P3是一个带内部上拉电阻的8位双向I/O口,P3的输出缓冲级可驱动(吸收或输出电流)4个TTL逻辑门电路。对端口写“1”,通过内部的上拉电阻把端口拉到高电平,此时可作为输入口。作为输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出一个电流。
P3除了作为一般的I/O口线外,更重要的用途是它的第二功能,具体功能说明如表2-1。
P3口还接收一些用于FLASH闪速存储器编程和程序校的控制信号。
RST:复位输入。当振荡器工作时,RST引脚出现两个机器周期以上高电平将使单片机复位
ALE/PROG:当访问外部程序存储器或数据存储器时,ALE(地址锁存允许)输出脉冲用于锁存地址的低8位字节。
表2-1 P3口的第二功能表
  
端口引脚
      
第二功能
  
P3.0
      
RXD(穿行输出口)
  
P3.1
      
TXD(穿行输入口)
  
P3.2
      
INT0(外部中断0)
  
  
P3.3
      
INT1(外部中断1)
  
P3.4
      
T0(定时/计数器0)
  
P3.5
      
T1(定时/计数器0)
  
P3.6
      
WR(外部数据写选通)
  
P3.7
      
RD(外部数据读选通)
不访问外部存储器,ALE仍以是时钟振荡频率的1/6输出固定的正脉冲信号,因此他可对外输出时钟或用于定时目的。要注意的是:每当访问外部数据存储器时将跳过一个ALE脉冲。对FLASH存储器编程期间,该引脚还用于输入编程脉冲(PROG)。
如有必要,可通过对特殊功能寄存器(SFR)区中的8EH单元的D0位置位,可禁止ALE操作。该位置位后,只有一条MOVX和MOVC指令ALE才会被激活。此外,该引脚会被微弱拉高,单片机执行外部程序时,应设置ALE无效。
PSEN:程序储存允许(PSEN)输出是外部程序存储器的读选通信号,当AT80C51由外部程序存储器取指令(或数据)时,每个机器周期两次PSEN有效,即输出两个脉冲。在此期间,当访问外部数据存储器,这两次有效的PSEN信号不出现。
EA/VPP:外部访问允许。欲使CPU仅访问外部程序储存器(地址为0000H-FFFFH),EA端必须保持低电平(接地)。需要注意的是:如果加密位LB1被编程,复位时内部会锁存EA端状态。如EA端为高电平(Vcc端),CPU则执行内部程序储存器中的指令。
FLASH储存器编程时,该引脚加上+12V的编程允许电源Vpp,当然这必须是该器件是使用12v编程电压。
XTAL1:振荡器反相放大器的及内部时钟发生器的输入端。
XTAL2:振荡器反相放大器的输出端
单片机外围电路设计复位电路设计
MCS-51的复位输入引脚RST为MCS-51提供了初始化的手段,可以使程序从指定处开始执行,在MCS-51的时钟电路工作后,只要RST引脚上出现超过两个机器周期以上的高电平时,即可产生复位的操作,只要RST保持高电平,则MCS-51循环复位,只有单RET由高电平变成低电平以后,MCS-51才从0000H地址开始执行程序,本系统采用按键复位方式的复位电路。
                                 
外部晶振时钟电路设计
MCS-51的时钟可以由两种方式产生,一种是内部方式,利用芯片内部的振荡电路;另外一种为外部方式,本论文根据实际需要和简便,采用内部振荡方式,MCS-51内部有一个用于构成振荡器的高增益反相放大器,引脚XTAL1和XTAL2分别是此放大器的输入端和输出端,这个放大器与作为反馈元件的片外晶体或陶瓷谐振器一起构成了一个自激振荡器。
MCS-51虽然有内部振荡电路,但要形成时钟,必须外接元件,所以实际构成的振荡时钟电路,外接晶振以及电容C1和C2构成了并联谐振电路接在放大器的反馈回路中,对接电容的值虽然没有严格的要求,但电容的大小会影响振荡频率的高低,振荡器的稳定性,起振的快速性和温度的稳定性。晶振的频率可在1.2MHZ~12MHZ之间任选,电容C1和C2的典型值在20pf~100pf之间选择,由于本系统用到定时器,为了方便计算,采用了12MHZ的晶振,采用电容选择30pf。
显示模块电路设计
该模块由共阳LED数码管组成,利用数码管的动态扫描原理,由三极管进行锁存,当控制数码管的IO口P20和P21为低电平时(及三极管基极为低电平),则三极管导通,VCC通三极管给数码管供电,则数码管被点亮,利用数码管点亮的余辉和人眼的视觉暂留原理,则看起来数码管是同时被点亮的。
        
从设计完成的任务与要求来看,显示通行时间必须用二位数码管,从节省硬件资源的角度考虑,可采用扫描的方式来处理,对于7段数码管,占用7个单片机的I/O口,另外设置2个电子开关对2位显示进行配合,占用2个I/O端口,十字路口共需4组红绿灯,加上转换黄灯,一共是12只灯,须用12个端口进行控制,加上两个方向的紧急通行按钮,占2个I/O端口和一个蜂鸣器端口,因此实际占用的单片机I/O口为24个,为此,我们可以选用51系列单片机中的ATAT89S52来作为中央处理器。这款单片机的I/O口作为输出时,具有较大的吸收电流能力,因此我们可以选用共阳型数码管,这样由单片机的I/O口就可以直接驱动,能简化硬件电路的设计。
三、软件设计交通信号灯控制系统的设计
交通信号灯由红灯、绿灯、黄灯组成。红灯表示禁止通行,绿灯表示准许通行,黄灯表示警示。交通信号灯分为机动车信号灯、非机动车信号灯、人行横道信号灯、车道信号灯、方向指示信号灯、闪光警告信号灯、道路与铁路平面交叉道口信号灯。交通信号灯用于道路平面交叉路口,通过对车辆、行人发出行进或停止的指令,使各同时到达的人、车交通流尽可能减少相互干扰,从而提高路口的通行能力,保障路口畅通和安全。因此必须合理的设计路口主干道的系统。
十字路口交通信号灯具体的控制要求
    (1) 交通信号灯分布于东南西北,每个路口均有三个。南北方向绿灯和东西方向的绿灯不能同时亮;如果同时亮,则应自动立即关闭信号灯系统,并立即发出报警信号。系统工作后,首先南北红灯亮并维持30s;与此同时,东西绿灯亮,并维持25s时间,到25s时,东西绿灯熄灭。在东西绿灯熄灭时,东西黄灯亮并维持5s,然后东西黄灯熄灭,东西红灯亮,同时南北红灯熄灭,南北绿灯亮;东西红灯亮并维持30s;与此同时,南北绿灯亮并维持15s;然后,南北绿灯熄灭南北绿灯熄灭时,南北黄灯亮维持5s后熄灭;同时南北红灯亮,东西绿灯亮。至此,结束一个工作循环,如下交通信号灯变化表:
  
交通信号灯变化表
  
  
东西
      
绿灯亮
   
黄灯亮
   
红灯亮
25S
   
5S
   
20S
  
南北
      
红灯亮
   
绿灯亮
   
黄灯亮
30S
   
15S
   
5S
(2)在交通信号灯亮和闪烁的同时,路口设有两位七段码的显示器倒数计时,让车辆行人能够清楚地知道再过多久信号灯就会发生变化。以便于司机和行人能够在有限的时间内准确的通行。
十字路口交通信号灯示意图
    交通信号灯共有12盏,每个路口各有红,黄,绿三盏,具体分布如下图所示:
交通信号灯控制系统程序编制 软件设计应用环境
本设计软件的设计是在Keil C51的环境下编译的。Keil C51是美国KeilSoftware公司出品的51系列兼容单片机C语言软件开发系统,软件提供丰富的库函数和功能强大的集成开发调试工具,全Windows界面。另外重要的一点,只要看一下编译后生成的汇编代码,就能体会到KeilC51生成的目标代码效率非常之高,多数语句生成的汇编代码很紧凑,容易理解。在开发大型软件时更能体现高级语言的优势。C语言有以下特点:
1、语言简洁、紧凑、使用方便、灵活。C语言一共只有32个关键字,9种控制语句,程序书写自由,主要用小写字母表示,压缩了一切不必要的成分。
2、运算符丰富。C的运算符包含的范围很广泛,共有34种运算符,使得C的运算类型极其丰富,表达式类型多样化,灵活使用各种运算符可以实现在其他高级语言中难以实现的运算。
3、数据结构丰富,具有现代化语言的各种数据结构,能用来实现各种复杂的数据结构的运算。
4、具有结构化的控制语句,用函数作为程序的模块单位,便于实现程序的模块化。
5、语法限制不太严格,程序设计自由度大。
6、C语言能进行位操作,能实现汇编语言的大部分功能,可以直接对硬件进行操作。因此,C既具有高级语言的功能,又具有低级语言的许多功能,可用来写系统软件。C语言的这种双重性,使它既是成功的系统描述语言,又是通用的程序设计语言。
7、生成目标代码质量高,程序执行效率高。
8、用C语言写的程序可移植性好。基本上不用修改就能用于各种型号的计算机和各种操作系统。
对操作系统和系统实用程序以及需要对硬件进行操作的场合,用C语言明显地优势于其他高级语言,有的大型应用软件也用C语言来编写。
软件设计流程
软件总体设计主要完成各部分的软件控制和协调。本系统主程序模块主要完成的工作是对系统的初始化,发送显示数据,同时对键盘进行扫描,等待外部中断,以及根据所需要的功能进行相应的操作。
交通灯根据其显示情况可以分为四个状态,可以通过定时来控制每个状态的时间;通过定时也可以向LED数码管中每隔1秒送一个数,显示该状态剩余的时间。其流程图如图所示。
        图4-1  主程序框图
交通灯定时器模块
AT89S52单片机内部有3个定时器T0,T1和T2,本次设计中使用T0工作在方式1,即16位定时器,定时50ms,20次中断产生秒信号,从而控制红绿灯的点亮时间。
    工作方式寄存器TMOD用来设置T0、T1的工作方式。这次实习中设置TMOD=0x01,即T0工作于方式0(16位定时器)。
内部定时器/计数器用作定时器时,是对机器周期计数,每个机器周期的长度是12个振荡周期。定时常数的设置可用一下方式计算:
机器周期=12/12MHz=1us
(65536-定时常数)*1.0us=50ms
所以定时常数是50000。
源程序代码
#include <reg52.h>                 //调用单片机头文件
#define uchar unsigned char   //宏定义"uchar"代替"unsignedchar"。
#define uint  unsigned int      //宏定义"uint"用来定义无符号整型数。
//数码管段选定义 0     1    2   3    4     5         6        7      8     9         
uchar codesmg_du[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
//                                           A        B       C      D     E   F         不显示
                                             0x88,0x83,0xc6,0xa1,0x86,0x8e,0xff};        //断码   
uchar dis_smg[8] ={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8};      
uchar smg_i = 4;    //显示数码管的个位数
//数码管位选定义
sbit smg_we1 = P2^0;        //数码管位选定义
sbit smg_we2 = P2^1;
sbit smg_we3 = P3^6;
sbit smg_we4 = P3^7;
char dx_s = 0; //东西  南北 倒计时变量
sbit dx_red    = P2^4;     //东西红灯
sbit dx_green  = P2^3;          //东西绿灯
sbit dx_yellow = P2^2;            //东西黄灯
sbit nb_red    = P2^7;          //南北红灯
sbit nb_green  = P2^6;          //南北绿灯
sbit nb_yellow = P2^5;            //南北黄灯     
uchar flag_jtd_mode;  //交通灯的模式 根据时间
bit flag_1s = 0;
bit flag_500ms;
bit flag_dx_nb;                  //东西南北模式
uchar flag_5m_value;
uchar i;
uchar flag_alarm;   //模式
uchar dx_time = 30,nb_time = 20;   //东西、南北的时间
uchar flag_jdgz ;     //交通管制
/***********************数码位选函数*****************************/
void smg_we_switch(uchar i)
{
         switch(i)
         {
                  case0: smg_we1 = 0;  smg_we2 = 1; smg_we3 =1;  smg_we4 = 1; break;
                  case1: smg_we1 = 1;  smg_we2 = 0; smg_we3 =1;  smg_we4 = 1; break;
                  case2: smg_we1 = 1;  smg_we2 = 1; smg_we3 =0;  smg_we4 = 1; break;
                  case3: smg_we1 = 1;  smg_we2 = 1; smg_we3 =1;  smg_we4 = 0; break;
         }      
}
/********************************************************************
* 名称 : delay_1ms()
* 功能 : 延时1ms函数
* 输入 : q
* 输出 : 无
***********************************************************************/
void delay_1ms(uint q)
{
         uinti,j;
         for(i=0;i<q;i++)
                  for(j=0;j<110;j++);
}
/********************************************************************
* 名称 : display()
* 功能 : 数码管显示
* 输入 : 无
* 输出 : 无
***********************************************************************/
void display()
{
         uchari;
         for(i=0;i<smg_i;i++)
         {               
                  P0= 0xff;                   //消隐
                  smg_we_switch(i);         //位选
                  P0= dis_smg;        //段选   
                  delay_1ms(3);
         }
}
/*********************定时器0、定时器1初始化******************/
void time0_init()      
{
         EA  = 1;            //开总中断
         TMOD= 0X11;           //定时器0、定时器1工作方式1
         ET0= 1;              //开定时器0中断
         TR0= 1;              //允许定时器0定时
//     ET1= 1;              //开定时器1中断
//     TR1= 1;              //允许定时器1定时         
}
/*********************交通灯处理函数*********************************/
void jiaotongdeng_dis()
{
         if(flag_1s== 1)
         {
                  flag_1s= 0;
                  if(dx_s== 0)
                  {
                          if(flag_dx_nb== 1)
                                   dx_s= nb_time;        //南北时间
                          else
                                   dx_s= dx_time;         //东西时间
                          flag_dx_nb= ~flag_dx_nb;
                  }
                  dx_s--;
         }
         dis_smg[0]= smg_du[dx_s % 10] ;
         dis_smg[1]= smg_du[dx_s / 10] ;
         dis_smg[2]= smg_du[dx_s % 10] ;
         dis_smg[3]= smg_du[dx_s / 10] ;
/***********************南北时间*********************************/
                  if(flag_dx_nb== 0)  
                  {
                          if(dx_s> 5)
                          {
                                   dx_red    = 1; //灭
                                   dx_green  =   0;     //亮
                                   dx_yellow= 1;         //灭
                                   nb_red    = 0; //亮
                                   nb_green  =  1;     //灭
                                   nb_yellow= 1;         //灭
                                   flag_5m_value= 0;         
                          }elseif(dx_s <= 5)             //当小于5秒时  黄灯要闪了
                          {
                                   dx_red    = 1;   //灭
                                   dx_green  =   1;       //灭
                                   nb_red    = 0;   //亮
                                   nb_green  =  1;       //灭
                                   nb_yellow= 1;           //灭
                                   if(flag_500ms== 0)
                                   {
                                            dx_yellow= 0;//亮
                                   }
                                   else
                                   {
                                            dx_yellow= 1;//灭
                                   }
                          }
                  }
/***********************东西时间*********************************/
                  if(flag_dx_nb== 1)  
                  {
                          if(dx_s> 5)
                          {
                                   dx_red    = 0;    //亮
                                   dx_green  =   1;        //灭
                                   dx_yellow= 1;            //灭
                                   nb_red    = 1;    //灭
                                   nb_green  =  0;        //亮
                                   nb_yellow= 1;            //灭
                                   flag_5m_value = 0;         
                          }elseif(dx_s <= 5)             //当小于5秒时  黄灯要闪了
                          {
                                   dx_red    = 0;    //灭
                                   dx_green  =   1;        //灭
                                   dx_yellow= 1;            //灭
                                   nb_red    = 1;    //灭
                                   nb_green  =  1;        //灭
                                   if(flag_500ms== 0)            //黄灯闪烁
                                   {
                                            nb_yellow= 0;         //亮
                                   }
                                   else
                                   {
                                            nb_yellow= 1;         //灭
                                   }
                          }
         }                        
}
/********************独立按键程序*****************/
uchar key_can;         //按键值
void key()         //独立按键程序
{
         staticuchar key_new;
         key_can= 20;                   //按键值还原
         P1|= 0x1f;
         if((P1& 0x1f) != 0x1f)              //按键按下
         {
                  delay_1ms(1);            //按键消抖动
                  if(((P1& 0x1f) != 0x1f) && (key_new == 1))
                  {                                                   //确认是按键按下
                          key_new= 0;
                          switch(P1& 0x1f)
                          {
                                   case0x1e:  key_can = 1;  break;        //得到按键值
                                   case0x1d:  key_can = 2;  break;        //得到按键值
                                   case 0x1b:  key_can = 3; break;         //得到按键值
                                   case0x17:  key_can = 4;  break;        //得到按键值
                          }
                  }                        
         }
         else
                  key_new= 1;   
}
uchar menu_1,flag_s;
/********************设置函数*****************/
void key_with()
{
         if(key_can== 4)   //交通管制按键
         {
                  flag_jdgz++;
                  if(flag_jdgz> 5)
                          flag_jdgz= 0;  
                  if(flag_jdgz== 1)      //  全部亮红灯
                  {
                          dx_red    = 0; //亮
                          dx_green  =   1;     //灭
                          dx_yellow= 1;         //灭
                          nb_red    = 0; //亮
                          nb_green  =  1;     //灭
                          nb_yellow= 1;         //灭                  
                  }
                  if(flag_jdgz== 2)      //  东西红灯  南北绿灯
                  {
                          dx_red    = 0; //亮
                          dx_green  =   1;     //灭
                          dx_yellow= 1;         //灭
                          nb_red    = 1; //灭
                          nb_green  =  0;     //亮
                          nb_yellow= 1;         //灭                  
                  }
                  if(flag_jdgz== 3)      //  南北红灯  东西绿灯
                  {
                          dx_red    = 1; //灭
                          dx_green  =   0;     //亮
                          dx_yellow= 1;         //灭
                          nb_red    = 0; //亮
                          nb_green  =  1;     //灭
                          nb_yellow= 1;         //灭                  
                  }
                  if(flag_jdgz== 4)      //  南北绿灯  东西绿灯
                  {
                          dx_red    = 1; //灭
                          dx_green  =   0;     //亮
                          dx_yellow= 1;         //灭
                          nb_red    = 1; //灭
                          nb_green  =  0;     //亮
                          nb_yellow= 1;         //灭                  
                  }
                  if(flag_jdgz== 5)      //  南北黄灯  东西黄灯
                  {
                          dx_red    = 1; //灭
                          dx_green  =   1;     //灭
                          dx_yellow= 0;         //亮
                          nb_red    = 1; //灭
                          nb_green  =  1;     //灭
                          nb_yellow= 0;         //亮                  
                  }
         }
         if(key_can== 1)         //设置键
         {
                  menu_1++;
                  if(menu_1>= 3)
                  {
                          menu_1  = 0;
                  }
         }
         if(menu_1== 1)          //设置东西的时间
         {
                  if(key_can== 2)
                  {
                          dx_time++ ;             //加1
                          if(dx_time> 99)
                                   dx_time= 99;
                  }
                  if(key_can== 3)
                  {
                          dx_time-- ;              //减1
                          if(dx_time<= 10)
                                   dx_time= 10;
                  }
                  dis_smg[0]= smg_du[10] ;    //显示为A
                  dis_smg[1]= smg_du[10] ;    //显示为A
                  dis_smg[2]= smg_du[dx_time % 10] ;           //显示东西设置的时候
                  dis_smg[3]= smg_du[dx_time / 10] ;   
         }      
         if(menu_1== 2)          //设置南北的时间
         {
                  if(key_can== 2)
                  {
                          nb_time++ ;            //加1
                          if(nb_time> 99)
                                   nb_time= 99;
                  }
                  if(key_can== 3)
                  {
                          nb_time-- ;              //减1
                          if(nb_time<= 10)
                                   nb_time= 10;
                  }
                  dis_smg[0]= smg_du[11] ;    //显示为B
                  dis_smg[1]= smg_du[11] ;    //显示为B
                  dis_smg[2]= smg_du[nb_time % 10] ;          //显示东西设置的时候
                  dis_smg[3]= smg_du[nb_time / 10] ;   
         }
}
/********************************************************************
* 名称 : main()
* 功能 : 实现灯的闪烁
* 输入 : 无
* 输出 : 无
***********************************************************************/
void main()
{
         time0_init();
         dx_s= nb_time;        //东西时间
         while(1)
         {
                  key();
                  if(key_can< 20)
                          key_with();
//              menu_dis();
                  if((menu_1== 0) && (flag_jdgz == 0))
                          jiaotongdeng_dis();
                  display();
         }
}  
/*********************定时器0中断服务程序************************/
void time0_int() interrupt 1  
{                                                      
         staticuchar value;                    //定时10ms中断一次
         TH0= 0x3c;
         TL0= 0xb0;     //50ms
         value++;
         flag_5m_value++;
         if(flag_5m_value% 10 == 0)
                  flag_500ms= ~flag_500ms;
         if(value>= 20)
         {
                  value= 0;
                  flag_1s= 1;
         }
}
3.       测试
三、设计总结
本论文介绍了一种基于AT89S52单片机的交通灯的设计方法,本论文完成了系统的硬件设计与制作,详细介绍了系统硬件设计的过程,并结合软件系统完成了整个系统的软、硬件联调,系统工作良好,实现了基本功能。
通过本次设计,巩固了我学习过的专业知识,也使我把理论与实践从真正意义上相结合了起来,锻炼了借助互联网络搜集、查阅相关文献资料和组织材料的综合能力,从中我也认识到自己的不足之处,我会在日后的学习中加以改进与提高。
经过这次设计,我在各方面都有很大的提高。学到了很多不曾学过的东西,也使我学会了更好地利用一些资源和工具如图书馆及一些软件查阅资料。在设计过程中也遇到很多的困难,遇到一些原理性不懂的时候就要去有针对性地查找资料或者请教知道老师和其他同学,然后加以吸收利用,提高了自己的应用能力,扩充了自己的知识储备,同时提高了动手能力。
四、参考文献
[1] 刘勇.数字电路[M].电子工业出版社.2004
[2] 杨子文.单片机原理及应用[M].西安电子科技大学出版社.2006
[3] 刘华东
一、设计内容
本设计以单片机为核心,以LED数码管作为倒计时指示,根据设计的要求我们考虑了各功能模块的几种设计方案,以求最佳方案,实现实时显示系统各种状态,系统还增设了根据交通拥挤情况可分别设置主干道和次干道的通行时间,以提高效率,缓减交通拥挤。系统总体设计框图如图所示。
交通灯控制的框图如下图所示,主要有控制电路、按键电路、晶振电路、复位电路、显示电路、电源电路等电路组成。
二、设计方案1.       总体方案
本设计以单片机为核心,以LED数码管作为倒计时指示,根据设计的要求我们考虑了各功能模块的几种设计方案,以求最佳方案,实现实时显示系统各种状态,系统还增设了根据交通拥挤情况可分别设置主干道和次干道的通行时间,以提高效率,缓减交通拥挤。系统总体设计框图如图所示。
交通灯控制的框图如下图所示,主要有控制电路、按键电路、晶振电路、复位电路、显示电路、电源电路等电路组成。


   

电源提供方案
为使模块稳定工作,须有可靠电源。本次设计考虑了两种电源方案:
方案一:采用独立的稳压电源。此方案的优点是稳定可靠,且有各种成熟电路可供选用;缺点是各模块都采用独立电源,会使系统复杂,且可能影响电路电平。
方案二:采用单片机控制模块提供电源。该方案的优点是系统简明扼要,节约成本;缺点是输出功率不高。
综上所述,选择第二种方案。
显示界面方案
该系统要求完成倒计时功能。基于上述原因,本次设计考虑了两种方案:
方案一:完全采用点阵式LED显示。这种方案功能强大,可方便的显示各种英文字符,汉字,图形等,但实现复杂,且须完成大量的软件工作。
方案二:完全采用数码管显示。这种方案优点是实现简单,可以完成倒计时功能。缺点是功能较少,只能显示有限的符号和数码字符。根据本设计的要求,方案二已经满足了要求,所以本次设计采用方案二以实现系统的显示功能。
输入方案
这里同样讨论了两种方案:
方案一:采用8155扩展I/O口、键盘及显示等。该方案的优点是使用灵活可编程,并且有RAM及计数器。若用该方案,可提供较多I/O口,但操作起来稍显复杂。
方案二:直接在I/O口线上接上按键开关。因为设计时精简和优化了电路,所以剩余的端口资源还比较多。
由于该系统是对交通灯及数码管的控制,只需用单片机本身的I/O口就可实现,且本身的计数器及RAM已经够用,故选择方案二。
2.       硬件电路设计
硬件设计是整个系统的基础,要考虑的方方面面很多,除了实现交通灯基本功能以外,主要还要考虑如下几个因素:①系统稳定度;②器件的通用性或易选购性;③软件编程的易实现性;④系统其它功能及性能指标;因此硬件设计至关重要。现从各功能模块的实现逐个进行分析探讨。
总体设计
本设计以单片机为控制核心,采用模块化设计,共分以下几个功能模块:单片机控制系统、键盘及状态显示、倒计时模块等。
单片机作为整个硬件系统的核心,它既是协调整机工作的控制器,又是数据处理器。它由单片机振荡电路、复位电路等组成。
系统采用双数码管倒计时计数功能,最大显示数字99。
友好的人机界面、灵活的控制方式、优化的物理结构是本设计的亮点。
单片机的选择
单片机微型计算机是微型计算机的一个重要分支,也是颇具生命力的机种。单片机微型计算机简称单片机,特别适用于控制领域,故又称为微控制器。
通常,单片机由单块集成电路芯片构成,内部包含有计算机的基本功能部件:中央处理器、存储器和I/O接口电路等。因此,单片机只需要和适当的软件及外部设备相结合,便可成为一个单片机控制系统。
单片机经过1、2、3、3代的发展,正朝着多功能、高性能、低电压、低功耗、低价格、大存储容量、强I/O功能及较好的结构兼容性方向发展。其发展趋势不外乎以下几个方面:
1、多功能         单片机中尽可能地把所需要的存储器和I/O口都集成在一块芯片上,使得单片机可以实现更多的功能。比如A/D、PWM、PCA(可编程计数器阵列)、WDT(监视定时器---看家狗)、高速I/O口及计数器的捕获/比较逻辑等。    有的单片机针对某一个应用领域,集成了相关的控制设备,以减少应用系统的芯片数量。例如,有的芯片以51内核为核心,集成了USB控制器、SMART CARD接口、MP3解码器、CAN或者I*I*C总线控制器等,LED、LCD或VFD显示驱动器也开始集成在8位单片机中。2、高效率和高性能为了提高执行速度和执行效率,单片机开始使用RISC、流水线和DSP的设计技术,使单片机的性能有了明显的提高,表现为:单片机的时钟频率得到提高;同样频率的单片机运行效率也有了很大的提升;由于集成度的提高,单片机的寻址能力、片内ROM(FLASH)和RAM的容量都突破了以往的数量和限制。 由于系统资源和系统复杂程度的增加,开始使用高级语言(如C语言)来开发单片机的程序。使用高级语言可以降低开发 难度,缩短开发周期,增强软件的可读性和可移植性,便于改进和扩充功能。3、低电压和低功耗   单片机的嵌入式应用决定了低电压和低功耗的特性十分重要。由于CMOS等工艺的大量采用,很多单片机可以在更低的电压下工作(1.2V或0.9V),功耗已经降低到uA级。这些特性使得单片机系统可以在更小电源的支持下工作更长的时间。4、低价格    单片机应用面广,使用数量大,带来的直接好处就是成本的降低。目前世界各大公司为了提高竞争力,在提高单片机性能的同时,十分注意降低其产品的价格。下面大致介绍一下单片机的主要应用领域和特点。(1)家用电器领域    用单片机控制系统取代传统的模拟和数字控制电路,使家用电器(如洗衣机、空调、冰箱、微波炉、和电视机等)功能更完善,更加智能化和易于使用。(2)办公自动化领域   单片机作为嵌入式系统广泛应用于现代办公设备,如计算机的键盘、磁盘驱动、打印机、复印机、电话机和传真机等。(3)商业应用领域    商业应用系统部分与家用和办公应用系统相似,但更加注重设备的稳定性、可靠性和安全性。商用系统中广泛使用的电子计量仪器、收款机、条形码阅读器、安全监测系统、空气调节系统和冷冻保鲜系统等,都采用了单片机构成的专用系统。与通用计算机相比,这些系统由于比较封闭,可以更有效地防止病毒和电磁干扰等,可靠性更高。(4)工业自动化    在工业控制和机电一体化控制系统中,除了采用工控计算机外,很多都是以单片机为核心的单片机和多机系统。(5)智能仪表与集成智能传感器    目前在各种电气测量仪表中普遍采用了单片机应用系统来代替传统的测量系统,使得测量系统具有存储、数据处理、查询及联网等智能功能。将单片机和传感器相结合,可以构成新一代的智能传感器。它将传感器变换后的物理量作进一步的变化和处理,使其成为数字信号,可以远距离传输并与计算机接口。(6)现代交通与航空航天领域    通常应用于电子综合显示系统、动力监控系统、自动驾驶系统、通信系统以及运行监视系统等。这些领域对体积、功耗、稳定性和实时性的要求往往比商用系统还要高,因此采用单片机系统更加重要。单片机的基本结构
   AT89S52单片机是一款低功耗、低电压、高性能CMOS8位单片机,片内含8KB(可经受1000次擦写周期)的FLASH可编程可反复擦写的只读程序存储器(EPROM),器件采用CMOS工艺和ATMEL公司的高密度,非易失性存储器(NURAM)技术制造,其输出引脚和指令系统都与MCS-51兼容,片内的FLASH存储器允许在系统内可改编程序或用常规的非易失性存储编程器来编程。因此,AT89C52是一种功能强,灵活性高且价格合理的单片机,可方便的应用在各个控制领域[1]。
AT89S52具有以下主要性能:
1.8KB可改编程序FLASH存储器;
2.全表态工作 :0~24HZ;
3.256X8字节内部RAM;
4.32个外部双向输入,输出(I、O)口;
引脚说明如图2-2。


   

引脚功能说明如下[2]:
VCC:电源电压。
GND:地。
P0口:P0口是一组8位漏极开路型双向I/O口,也即地址/数据线复用口。作为输出口时,每位能吸收电流的方式驱动8个TTL逻辑门电路,对端口写“1”可作为高阻抗输入端。
在访问外部数据储存器或程序储存器时,这组口线分时转换地址(低8位)和数据总线复用,在访问期间激活内部上拉电阻。FLASH编程时,P0口接收指令字节,而在程序校验时,输出指令字节,校验时,要求外接上拉电阻。
P1口:P1是一个带内部上拉电阻的8位双向I/O口,P1的输出缓冲级可驱动(吸收或输出电流)4个TTL逻辑门电路。对端口写“1”,通过内部的上拉电阻把端口拉到高电平,此时可作为输入口。作为输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出一个电流。FLASH编程和程序校验期间,P1接收低8位地址。
P2口:P2是一个带内部上拉电阻的8位双向I/O口,P2的输出缓冲级可驱动(吸收或输出电流)4个TTL逻辑门电路。对端口写“1”,通过内部的上拉电阻把端口拉到高电平,此时可作为输入口。作为输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出一个电流。在访问外部程序储存器或16位地址的外部数据储存器(例如执行MOVX@DPTR指令)时,P2口送出高8位地址数据。在访问8位地址的外部数据储存器(例如执行MOVX@RI指令)时,P2口线上的内容(也即特殊功能寄存器(SFR)区中R2寄存器的内容),在整个访问期间不改变。P3口:P3是一个带内部上拉电阻的8位双向I/O口,P3的输出缓冲级可驱动(吸收或输出电流)4个TTL逻辑门电路。对端口写“1”,通过内部的上拉电阻把端口拉到高电平,此时可作为输入口。作为输入口使用时,因为内部存在上拉电阻,某个引脚被外部信号拉低时会输出一个电流。
P3除了作为一般的I/O口线外,更重要的用途是它的第二功能,具体功能说明如表2-1。
P3口还接收一些用于FLASH闪速存储器编程和程序校的控制信号。
RST:复位输入。当振荡器工作时,RST引脚出现两个机器周期以上高电平将使单片机复位
ALE/PROG:当访问外部程序存储器或数据存储器时,ALE(地址锁存允许)输出脉冲用于锁存地址的低8位字节。
表2-1 P3口的第二功能表
  
端口引脚
      
第二功能
  
P3.0
      
RXD(穿行输出口)
  
P3.1
      
TXD(穿行输入口)
  
P3.2
      
INT0(外部中断0)
  
  
P3.3
      
INT1(外部中断1)
  
P3.4
      
T0(定时/计数器0)
  
P3.5
      
T1(定时/计数器0)
  
P3.6
      
WR(外部数据写选通)
  
P3.7
      
RD(外部数据读选通)
不访问外部存储器,ALE仍以是时钟振荡频率的1/6输出固定的正脉冲信号,因此他可对外输出时钟或用于定时目的。要注意的是:每当访问外部数据存储器时将跳过一个ALE脉冲。对FLASH存储器编程期间,该引脚还用于输入编程脉冲(PROG)。
如有必要,可通过对特殊功能寄存器(SFR)区中的8EH单元的D0位置位,可禁止ALE操作。该位置位后,只有一条MOVX和MOVC指令ALE才会被激活。此外,该引脚会被微弱拉高,单片机执行外部程序时,应设置ALE无效。
PSEN:程序储存允许(PSEN)输出是外部程序存储器的读选通信号,当AT80C51由外部程序存储器取指令(或数据)时,每个机器周期两次PSEN有效,即输出两个脉冲。在此期间,当访问外部数据存储器,这两次有效的PSEN信号不出现。
EA/VPP:外部访问允许。欲使CPU仅访问外部程序储存器(地址为0000H-FFFFH),EA端必须保持低电平(接地)。需要注意的是:如果加密位LB1被编程,复位时内部会锁存EA端状态。如EA端为高电平(Vcc端),CPU则执行内部程序储存器中的指令。
FLASH储存器编程时,该引脚加上+12V的编程允许电源Vpp,当然这必须是该器件是使用12v编程电压。
XTAL1:振荡器反相放大器的及内部时钟发生器的输入端。
XTAL2:振荡器反相放大器的输出端
单片机外围电路设计复位电路设计
MCS-51的复位输入引脚RST为MCS-51提供了初始化的手段,可以使程序从指定处开始执行,在MCS-51的时钟电路工作后,只要RST引脚上出现超过两个机器周期以上的高电平时,即可产生复位的操作,只要RST保持高电平,则MCS-51循环复位,只有单RET由高电平变成低电平以后,MCS-51才从0000H地址开始执行程序,本系统采用按键复位方式的复位电路。
                                 
外部晶振时钟电路设计
MCS-51的时钟可以由两种方式产生,一种是内部方式,利用芯片内部的振荡电路;另外一种为外部方式,本论文根据实际需要和简便,采用内部振荡方式,MCS-51内部有一个用于构成振荡器的高增益反相放大器,引脚XTAL1和XTAL2分别是此放大器的输入端和输出端,这个放大器与作为反馈元件的片外晶体或陶瓷谐振器一起构成了一个自激振荡器。
MCS-51虽然有内部振荡电路,但要形成时钟,必须外接元件,所以实际构成的振荡时钟电路,外接晶振以及电容C1和C2构成了并联谐振电路接在放大器的反馈回路中,对接电容的值虽然没有严格的要求,但电容的大小会影响振荡频率的高低,振荡器的稳定性,起振的快速性和温度的稳定性。晶振的频率可在1.2MHZ~12MHZ之间任选,电容C1和C2的典型值在20pf~100pf之间选择,由于本系统用到定时器,为了方便计算,采用了12MHZ的晶振,采用电容选择30pf。
显示模块电路设计
该模块由共阳LED数码管组成,利用数码管的动态扫描原理,由三极管进行锁存,当控制数码管的IO口P20和P21为低电平时(及三极管基极为低电平),则三极管导通,VCC通三极管给数码管供电,则数码管被点亮,利用数码管点亮的余辉和人眼的视觉暂留原理,则看起来数码管是同时被点亮的。
        
从设计完成的任务与要求来看,显示通行时间必须用二位数码管,从节省硬件资源的角度考虑,可采用扫描的方式来处理,对于7段数码管,占用7个单片机的I/O口,另外设置2个电子开关对2位显示进行配合,占用2个I/O端口,十字路口共需4组红绿灯,加上转换黄灯,一共是12只灯,须用12个端口进行控制,加上两个方向的紧急通行按钮,占2个I/O端口和一个蜂鸣器端口,因此实际占用的单片机I/O口为24个,为此,我们可以选用51系列单片机中的ATAT89S52来作为中央处理器。这款单片机的I/O口作为输出时,具有较大的吸收电流能力,因此我们可以选用共阳型数码管,这样由单片机的I/O口就可以直接驱动,能简化硬件电路的设计。
三、软件设计交通信号灯控制系统的设计
交通信号灯由红灯、绿灯、黄灯组成。红灯表示禁止通行,绿灯表示准许通行,黄灯表示警示。交通信号灯分为机动车信号灯、非机动车信号灯、人行横道信号灯、车道信号灯、方向指示信号灯、闪光警告信号灯、道路与铁路平面交叉道口信号灯。交通信号灯用于道路平面交叉路口,通过对车辆、行人发出行进或停止的指令,使各同时到达的人、车交通流尽可能减少相互干扰,从而提高路口的通行能力,保障路口畅通和安全。因此必须合理的设计路口主干道的系统。
十字路口交通信号灯具体的控制要求
    (1) 交通信号灯分布于东南西北,每个路口均有三个。南北方向绿灯和东西方向的绿灯不能同时亮;如果同时亮,则应自动立即关闭信号灯系统,并立即发出报警信号。系统工作后,首先南北红灯亮并维持30s;与此同时,东西绿灯亮,并维持25s时间,到25s时,东西绿灯熄灭。在东西绿灯熄灭时,东西黄灯亮并维持5s,然后东西黄灯熄灭,东西红灯亮,同时南北红灯熄灭,南北绿灯亮;东西红灯亮并维持30s;与此同时,南北绿灯亮并维持15s;然后,南北绿灯熄灭南北绿灯熄灭时,南北黄灯亮维持5s后熄灭;同时南北红灯亮,东西绿灯亮。至此,结束一个工作循环,如下交通信号灯变化表:
  
交通信号灯变化表
  
  
东西
      
绿灯亮
   
黄灯亮
   
红灯亮
25S
   
5S
   
20S
  
南北
      
红灯亮
   
绿灯亮
   
黄灯亮
30S
   
15S
   
5S
(2)在交通信号灯亮和闪烁的同时,路口设有两位七段码的显示器倒数计时,让车辆行人能够清楚地知道再过多久信号灯就会发生变化。以便于司机和行人能够在有限的时间内准确的通行。
十字路口交通信号灯示意图
    交通信号灯共有12盏,每个路口各有红,黄,绿三盏,具体分布如下图所示:
交通信号灯控制系统程序编制 软件设计应用环境
本设计软件的设计是在Keil C51的环境下编译的。Keil C51是美国KeilSoftware公司出品的51系列兼容单片机C语言软件开发系统,软件提供丰富的库函数和功能强大的集成开发调试工具,全Windows界面。另外重要的一点,只要看一下编译后生成的汇编代码,就能体会到KeilC51生成的目标代码效率非常之高,多数语句生成的汇编代码很紧凑,容易理解。在开发大型软件时更能体现高级语言的优势。C语言有以下特点:
1、语言简洁、紧凑、使用方便、灵活。C语言一共只有32个关键字,9种控制语句,程序书写自由,主要用小写字母表示,压缩了一切不必要的成分。
2、运算符丰富。C的运算符包含的范围很广泛,共有34种运算符,使得C的运算类型极其丰富,表达式类型多样化,灵活使用各种运算符可以实现在其他高级语言中难以实现的运算。
3、数据结构丰富,具有现代化语言的各种数据结构,能用来实现各种复杂的数据结构的运算。
4、具有结构化的控制语句,用函数作为程序的模块单位,便于实现程序的模块化。
5、语法限制不太严格,程序设计自由度大。
6、C语言能进行位操作,能实现汇编语言的大部分功能,可以直接对硬件进行操作。因此,C既具有高级语言的功能,又具有低级语言的许多功能,可用来写系统软件。C语言的这种双重性,使它既是成功的系统描述语言,又是通用的程序设计语言。
7、生成目标代码质量高,程序执行效率高。
8、用C语言写的程序可移植性好。基本上不用修改就能用于各种型号的计算机和各种操作系统。
对操作系统和系统实用程序以及需要对硬件进行操作的场合,用C语言明显地优势于其他高级语言,有的大型应用软件也用C语言来编写。
软件设计流程
软件总体设计主要完成各部分的软件控制和协调。本系统主程序模块主要完成的工作是对系统的初始化,发送显示数据,同时对键盘进行扫描,等待外部中断,以及根据所需要的功能进行相应的操作。
交通灯根据其显示情况可以分为四个状态,可以通过定时来控制每个状态的时间;通过定时也可以向LED数码管中每隔1秒送一个数,显示该状态剩余的时间。其流程图如图所示。
        图4-1  主程序框图
交通灯定时器模块
AT89S52单片机内部有3个定时器T0,T1和T2,本次设计中使用T0工作在方式1,即16位定时器,定时50ms,20次中断产生秒信号,从而控制红绿灯的点亮时间。
    工作方式寄存器TMOD用来设置T0、T1的工作方式。这次实习中设置TMOD=0x01,即T0工作于方式0(16位定时器)。
内部定时器/计数器用作定时器时,是对机器周期计数,每个机器周期的长度是12个振荡周期。定时常数的设置可用一下方式计算:
机器周期=12/12MHz=1us
(65536-定时常数)*1.0us=50ms
所以定时常数是50000。
源程序代码
#include <reg52.h>                 //调用单片机头文件
#define uchar unsigned char   //宏定义"uchar"代替"unsignedchar"。
#define uint  unsigned int      //宏定义"uint"用来定义无符号整型数。
//数码管段选定义 0     1    2   3    4     5         6        7      8     9         
uchar codesmg_du[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
//                                           A        B       C      D     E   F         不显示
                                             0x88,0x83,0xc6,0xa1,0x86,0x8e,0xff};        //断码   
uchar dis_smg[8] ={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8};      
uchar smg_i = 4;    //显示数码管的个位数
//数码管位选定义
sbit smg_we1 = P2^0;        //数码管位选定义
sbit smg_we2 = P2^1;
sbit smg_we3 = P3^6;
sbit smg_we4 = P3^7;
char dx_s = 0; //东西  南北 倒计时变量
sbit dx_red    = P2^4;     //东西红灯
sbit dx_green  = P2^3;          //东西绿灯
sbit dx_yellow = P2^2;            //东西黄灯
sbit nb_red    = P2^7;          //南北红灯
sbit nb_green  = P2^6;          //南北绿灯
sbit nb_yellow = P2^5;            //南北黄灯     
uchar flag_jtd_mode;  //交通灯的模式 根据时间
bit flag_1s = 0;
bit flag_500ms;
bit flag_dx_nb;                  //东西南北模式
uchar flag_5m_value;
uchar i;
uchar flag_alarm;   //模式
uchar dx_time = 30,nb_time = 20;   //东西、南北的时间
uchar flag_jdgz ;     //交通管制
/***********************数码位选函数*****************************/
void smg_we_switch(uchar i)
{
         switch(i)
         {
                  case0: smg_we1 = 0;  smg_we2 = 1; smg_we3 =1;  smg_we4 = 1; break;
                  case1: smg_we1 = 1;  smg_we2 = 0; smg_we3 =1;  smg_we4 = 1; break;
                  case2: smg_we1 = 1;  smg_we2 = 1; smg_we3 =0;  smg_we4 = 1; break;
                  case3: smg_we1 = 1;  smg_we2 = 1; smg_we3 =1;  smg_we4 = 0; break;
         }      
}
/********************************************************************
* 名称 : delay_1ms()
* 功能 : 延时1ms函数
* 输入 : q
* 输出 : 无
***********************************************************************/
void delay_1ms(uint q)
{
         uinti,j;
         for(i=0;i<q;i++)
                  for(j=0;j<110;j++);
}
/********************************************************************
* 名称 : display()
* 功能 : 数码管显示
* 输入 : 无
* 输出 : 无
***********************************************************************/
void display()
{
         uchari;
         for(i=0;i<smg_i;i++)
         {               
                  P0= 0xff;                   //消隐
                  smg_we_switch(i);         //位选
                  P0= dis_smg;        //段选   
                  delay_1ms(3);
         }
}
/*********************定时器0、定时器1初始化******************/
void time0_init()      
{
         EA  = 1;            //开总中断
         TMOD= 0X11;           //定时器0、定时器1工作方式1
         ET0= 1;              //开定时器0中断
         TR0= 1;              //允许定时器0定时
//     ET1= 1;              //开定时器1中断
//     TR1= 1;              //允许定时器1定时         
}
/*********************交通灯处理函数*********************************/
void jiaotongdeng_dis()
{
         if(flag_1s== 1)
         {
                  flag_1s= 0;
                  if(dx_s== 0)
                  {
                          if(flag_dx_nb== 1)
                                   dx_s= nb_time;        //南北时间
                          else
                                   dx_s= dx_time;         //东西时间
                          flag_dx_nb= ~flag_dx_nb;
                  }
                  dx_s--;
         }
         dis_smg[0]= smg_du[dx_s % 10] ;
         dis_smg[1]= smg_du[dx_s / 10] ;
         dis_smg[2]= smg_du[dx_s % 10] ;
         dis_smg[3]= smg_du[dx_s / 10] ;
/***********************南北时间*********************************/
                  if(flag_dx_nb== 0)  
                  {
                          if(dx_s> 5)
                          {
                                   dx_red    = 1; //灭
                                   dx_green  =   0;     //亮
                                   dx_yellow= 1;         //灭
                                   nb_red    = 0; //亮
                                   nb_green  =  1;     //灭
                                   nb_yellow= 1;         //灭
                                   flag_5m_value= 0;         
                          }elseif(dx_s <= 5)             //当小于5秒时  黄灯要闪了
                          {
                                   dx_red    = 1;   //灭
                                   dx_green  =   1;       //灭
                                   nb_red    = 0;   //亮
                                   nb_green  =  1;       //灭
                                   nb_yellow= 1;           //灭
                                   if(flag_500ms== 0)
                                   {
                                            dx_yellow= 0;//亮
                                   }
                                   else
                                   {
                                            dx_yellow= 1;//灭
                                   }
                          }
                  }
/***********************东西时间*********************************/
                  if(flag_dx_nb== 1)  
                  {
                          if(dx_s> 5)
                          {
                                   dx_red    = 0;    //亮
                                   dx_green  =   1;        //灭
                                   dx_yellow= 1;            //灭
                                   nb_red    = 1;    //灭
                                   nb_green  =  0;        //亮
                                   nb_yellow= 1;            //灭
                                   flag_5m_value = 0;         
                          }elseif(dx_s <= 5)             //当小于5秒时  黄灯要闪了
                          {
                                   dx_red    = 0;    //灭
                                   dx_green  =   1;        //灭
                                   dx_yellow= 1;            //灭
                                   nb_red    = 1;    //灭
                                   nb_green  =  1;        //灭
                                   if(flag_500ms== 0)            //黄灯闪烁
                                   {
                                            nb_yellow= 0;         //亮
                                   }
                                   else
                                   {
                                            nb_yellow= 1;         //灭
                                   }
                          }
         }                        
}
/********************独立按键程序*****************/
uchar key_can;         //按键值
void key()         //独立按键程序
{
         staticuchar key_new;
         key_can= 20;                   //按键值还原
         P1|= 0x1f;
         if((P1& 0x1f) != 0x1f)              //按键按下
         {
                  delay_1ms(1);            //按键消抖动
                  if(((P1& 0x1f) != 0x1f) && (key_new == 1))
                  {                                                   //确认是按键按下
                          key_new= 0;
                          switch(P1& 0x1f)
                          {
                                   case0x1e:  key_can = 1;  break;        //得到按键值
                                   case0x1d:  key_can = 2;  break;        //得到按键值
                                   case 0x1b:  key_can = 3; break;         //得到按键值
                                   case0x17:  key_can = 4;  break;        //得到按键值
                          }
                  }                        
         }
         else
                  key_new= 1;   
}
uchar menu_1,flag_s;
/********************设置函数*****************/
void key_with()
{
         if(key_can== 4)   //交通管制按键
         {
                  flag_jdgz++;
                  if(flag_jdgz> 5)
                          flag_jdgz= 0;  
                  if(flag_jdgz== 1)      //  全部亮红灯
                  {
                          dx_red    = 0; //亮
                          dx_green  =   1;     //灭
                          dx_yellow= 1;         //灭
                          nb_red    = 0; //亮
                          nb_green  =  1;     //灭
                          nb_yellow= 1;         //灭                  
                  }
                  if(flag_jdgz== 2)      //  东西红灯  南北绿灯
                  {
                          dx_red    = 0; //亮
                          dx_green  =   1;     //灭
                          dx_yellow= 1;         //灭
                          nb_red    = 1; //灭
                          nb_green  =  0;     //亮
                          nb_yellow= 1;         //灭                  
                  }
                  if(flag_jdgz== 3)      //  南北红灯  东西绿灯
                  {
                          dx_red    = 1; //灭
                          dx_green  =   0;     //亮
                          dx_yellow= 1;         //灭
                          nb_red    = 0; //亮
                          nb_green  =  1;     //灭
                          nb_yellow= 1;         //灭                  
                  }
                  if(flag_jdgz== 4)      //  南北绿灯  东西绿灯
                  {
                          dx_red    = 1; //灭
                          dx_green  =   0;     //亮
                          dx_yellow= 1;         //灭
                          nb_red    = 1; //灭
                          nb_green  =  0;     //亮
                          nb_yellow= 1;         //灭                  
                  }
                  if(flag_jdgz== 5)      //  南北黄灯  东西黄灯
                  {
                          dx_red    = 1; //灭
                          dx_green  =   1;     //灭
                          dx_yellow= 0;         //亮
                          nb_red    = 1; //灭
                          nb_green  =  1;     //灭
                          nb_yellow= 0;         //亮                  
                  }
         }
         if(key_can== 1)         //设置键
         {
                  menu_1++;
                  if(menu_1>= 3)
                  {
                          menu_1  = 0;
                  }
         }
         if(menu_1== 1)          //设置东西的时间
         {
                  if(key_can== 2)
                  {
                          dx_time++ ;             //加1
                          if(dx_time> 99)
                                   dx_time= 99;
                  }
                  if(key_can== 3)
                  {
                          dx_time-- ;              //减1
                          if(dx_time<= 10)
                                   dx_time= 10;
                  }
                  dis_smg[0]= smg_du[10] ;    //显示为A
                  dis_smg[1]= smg_du[10] ;    //显示为A
                  dis_smg[2]= smg_du[dx_time % 10] ;           //显示东西设置的时候
                  dis_smg[3]= smg_du[dx_time / 10] ;   
         }      
         if(menu_1== 2)          //设置南北的时间
         {
                  if(key_can== 2)
                  {
                          nb_time++ ;            //加1
                          if(nb_time> 99)
                                   nb_time= 99;
                  }
                  if(key_can== 3)
                  {
                          nb_time-- ;              //减1
                          if(nb_time<= 10)
                                   nb_time= 10;
                  }
                  dis_smg[0]= smg_du[11] ;    //显示为B
                  dis_smg[1]= smg_du[11] ;    //显示为B
                  dis_smg[2]= smg_du[nb_time % 10] ;          //显示东西设置的时候
                  dis_smg[3]= smg_du[nb_time / 10] ;   
         }
}
/********************************************************************
* 名称 : main()
* 功能 : 实现灯的闪烁
* 输入 : 无
* 输出 : 无
***********************************************************************/
void main()
{
         time0_init();
         dx_s= nb_time;        //东西时间
         while(1)
         {
                  key();
                  if(key_can< 20)
                          key_with();
//              menu_dis();
                  if((menu_1== 0) && (flag_jdgz == 0))
                          jiaotongdeng_dis();
                  display();
         }
}  
/*********************定时器0中断服务程序************************/
void time0_int() interrupt 1  
{                                                      
         staticuchar value;                    //定时10ms中断一次
         TH0= 0x3c;
         TL0= 0xb0;     //50ms
         value++;
         flag_5m_value++;
         if(flag_5m_value% 10 == 0)
                  flag_500ms= ~flag_500ms;
         if(value>= 20)
         {
                  value= 0;
                  flag_1s= 1;
         }
}
3.       测试
三、设计总结
本论文介绍了一种基于AT89S52单片机的交通灯的设计方法,本论文完成了系统的硬件设计与制作,详细介绍了系统硬件设计的过程,并结合软件系统完成了整个系统的软、硬件联调,系统工作良好,实现了基本功能。
通过本次设计,巩固了我学习过的专业知识,也使我把理论与实践从真正意义上相结合了起来,锻炼了借助互联网络搜集、查阅相关文献资料和组织材料的综合能力,从中我也认识到自己的不足之处,我会在日后的学习中加以改进与提高。
经过这次设计,我在各方面都有很大的提高。学到了很多不曾学过的东西,也使我学会了更好地利用一些资源和工具如图书馆及一些软件查阅资料。在设计过程中也遇到很多的困难,遇到一些原理性不懂的时候就要去有针对性地查找资料或者请教知道老师和其他同学,然后加以吸收利用,提高了自己的应用能力,扩充了自己的知识储备,同时提高了动手能力。
四、参考文献
[1] 刘勇.数字电路[M].电子工业出版社.2004
[2] 杨子文.单片机原理及应用[M].西安电子科技大学出版社.2006
[3] 刘华东.单片机原理与应用(第2版)[M].电子工业出版社.2006.8
[4] 胡汉才.单片机原理及其接口技术[M].清华大学出版社,2006.
[5] 沈精虎.电路设计与制版Protel99入门与提高[M].人民邮电出版社,2004.
[6] 范风强,兰婵丽.单片机语言C51应用实战集锦[M].电子工业出版社.,2001.
[7] 顾曙敏.单片机与串行时钟DS1307的接口设计[J].现代电子技术,2003,26(14)85-87.
[8] 孙晓燕.基于8051单片机的交通灯控制系统设计与模拟[J].南宁职业技术学院学报,2007年03期.
[9] 陈毅,许飞,王学飞.基于单片机的交通灯智能控制系统[J].中国高新技术企业,2009年第15期.
.单片机原理与应用(第2版)[M].电子工业出版社.2006.8
[4] 胡汉才.单片机原理及其接口技术[M].清华大学出版社,2006.
[5] 沈精虎.电路设计与制版Protel99入门与提高[M].人民邮电出版社,2004.
[6] 范风强,兰婵丽.单片机语言C51应用实战集锦[M].电子工业出版社.,2001.
[7] 顾曙敏.单片机与串行时钟DS1307的接口设计[J].现代电子技术,2003,26(14)85-87.
[8] 孙晓燕.基于8051单片机的交通灯控制系统设计与模拟[J].南宁职业技术学院学报,2007年03期.
[9] 陈毅,许飞,王学飞.基于单片机的交通灯智能控制系统[J].中国高新技术企业,2009年第15期.


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:370231 发表于 2018-7-26 15:17 | 只看该作者
好贴   ,简直就是神操作,让那些学生直接搬运过去
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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