单片机论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 15029|回复: 11
收起左侧

单片机的交通灯课程设计报告 自己动手DIY 电路原理图+程序

  [复制链接]
wlxf 发表于 2018-12-4 23:13 | 显示全部楼层 |阅读模式
附件里面有 程序  原理图    pcb    实物图   有兴趣的小伙伴  可以看看  

制作出来的实物图如下:
0.png 0.png


摘要
现今,随着我国经济水平的不断提升,汽车已成为人们工作生活的重要工具,汽车数量的不断上升给现有城市交通带来不小的压力。
本文主要通过51单片机实现对交叉路口的红绿灯的控制,利用单片机的定时器计时产生中断,通过数码管刷新显示倒计时,为司机和行人提供活动参考,单片机根据当前的系统状态切换到下一个状态。主干道和支干道是两个互斥的状态,详细介绍了系统的工作原理、工作流程,第三章介绍了系统的硬件设计以及器件选型,硬件包括电源部分,单片机控制模块设计部分,数码管显示部分,按键部分等。第四章是对软件设计方面的介绍,包括对程序主流程的介绍,以及中断程序模块、数码管显示模块分析介绍,最后还有二极管之间连接电路图、二极管与LED显示器的连接电路图、整体交通灯电路图,总结了系统还存在的可扩展性和不足之处。第五章用Proteus仿真软件实现了主干道每次放行15秒,支干道每次放行10秒;每次绿灯变红之前,黄灯先亮3秒,此时另一干道上的红灯并闪烁,并且主、支干道交替进行,以及仿真图片。实践表明,该系统能够安全有效的实现交通秩序的控制和疏解。

目  录
移通学院毕业设计(论文)任务书
前  言
第一章  研究背景和意义
第二章  单片机控制的交通灯的设计方案
第一节  系统工作原理和方案
第二节  本课题主要内容
第三章  交通灯的硬件设计
第一节  电源模块设计
第二节  单片机控制模块设计
一、方案选择
二、复位电路
三、晶振电路
第三节  LED显示模块
一、LED数码管介绍
二、LED数码管显示原理
第四节  按键设置模块
第四章  交通灯的软件设计
第一节  主函数流程
第二节  中断程序模块
第三节  数码管显示模块
第四节  交通灯电路
第五节  倒计时显示器电路
第六节  交通灯设计总电路图
第五章  Proteus仿真
第一节  Proteus软件介绍
第二节  Proteus仿真图片
第六章  调试心得
结  论
致  谢
参考文献
附  录
一、英文原文
The General Situation of AT89C51
二、英文翻译
AT89C51概述
三、源程序

前  言

交叉路口的交通控制系统保证了车辆的安全,对于路口交通的控制管理,科学的管理和控制是一个重要而又影响深远的研究课题。在一定程度上它能保证交通安全和畅通更好利用交叉路口的交通资源,是解决城市交通问题的有效途径。交叉路口信号灯的出现是人类历史上的一个重大变革,对人们的生活产生了太多的影响。在汽车日益增多的今天,交叉路口信号灯使流量能够得到一定控制,疏导拥堵的交通,减少交通压力,以及对交通事故的减少有显著的效果。随着越来越多的私家车的使用,交通拥堵已成为严重影响人们生活的一个重大问题。如何使用适当的控制方法,以最大限度地利用良好的城市的公路建设,缓解主路和匝道以及城市周边地区的交通拥堵,已成为交管部门和城市规划部门要解决的当下难题。随着电子技术的发展,采用单片机技术,能够智能地管理交通信号灯,它已成为目前广泛使用的方法。
随着社会经济的发展,城市交通承受着越来越大的压力,各大城市的设计规划部门会主导修建更多的高速公路,在完成高速公路的初期建设,会对交通状况的改善起积极作用,然而,随着全球汽车的快速增长,高速道路并没能发挥出建设者预期的效果。并且,修建公路以来需要庞大的资金支持,二来在现在大中城市寸土寸金的今天,过多的道路是对土地资源的一种浪费。城市交通控制系统是在现有城市硬件的基础上配套的软件设施,它能够智能化的疏导车流量,缓解车流拥堵,是未来城市交通发展的必然趋势。交通灯控制是其中的一个部分。
本文主要介绍了基于AT80C51单片机控制的交通灯控制系统的设计过程,首先介绍了关于交通灯出现和发展的历史和现状,然后对本文将要实现的交通灯系统的工作原理和流程做了介绍,并明确了需要实现的功能。第三章介绍了系统的硬件设计以及器件选型,硬件包括电源部分,单片机部分,数码管显示部分,按键部分等。第四章是对软件设计方面的介绍,包括对程序主流程的介绍,以及各个程序模块的分析介绍,最后总结了系统还存在的可扩展性和不足之处。

第一章 研究背景和意义

据国家统计局2011年3月1日的官方统计数据表明,直到2010年底,民用汽车的国内保有量达到9086万(包括三轮车和低速货车1284万),增幅比上年同期增加19.3%,其中,私家车同比增加25.3%,保有量达到6539万。其中民用汽车4029万,增幅比上年增长28.4%,3443万的私家车,增幅比上年同期增长32.2%。

另一组数据显示, 2009年北京中心城区早晚高峰平均车速分别为24.3千米每小时和20.4千米每小时,上海中心城区、延安路高架在高峰时间段双向平均拥堵速度20-30kra /小时,单程不到20 千米每小时,重庆,武汉,天津,广州等城市,在高峰时段平均速度主干道为20公里/小时,北京主干道高峰时段接近饱和1.0,上海,南京,成都等城市均超过0.8。北京市民在上班路上耗费的平均时间为50-70分钟,广州,上海,深圳,天津等城市在40分钟以上。北京交通发展研究中心2010年8月在座谈会上给出了一组数据:据北京汽车保有量的发展趋势,到2015年,城市的机动车保有量将达到700万,将严重的超过现有路网最大容量,如果不加以控制和引导,2015年平均每天的速度会比15公里每小时更低。此外,根据公安部交管局信部公布的数据显示,截至2010年底,直到2010年9月底,667个大中城市,约有三分之二的城市交通拥堵的发生高峰期。

这些数据表明,一方面,中国的汽车保有量非常大的上升的比例;而在另一方面,许多中国各大城市交通拥堵问题十分严重,已经成为常态,并有逐年上升的趋势,一些二三线城市正在迅速推动了“拥堵时代”。

自从1858年英国人发明了原有的机械扳手红绿灯,随后一百年,红绿灯在人们的日常生活中占据着重要的地位,随着人们越来越多的社会活动,经济发展,导致汽车数量呈现井喷式的增长,这也造成了城市道路的日益拥挤。这种情况下交叉路口信号灯更显示出它的功能,缓解交通压力,道路运进行能力得到提高,对交通事故的发生有显著减少效果。现今,安装在每个交叉口,缓解车辆拥堵的信号灯已成为最直接和最有效的方法。

1858年,在伦敦出现了世界上第一个红绿灯,它是以燃煤气为光源,能够出红色和蓝色两种光,人们将这种机械扳手式信号灯安装在街头交叉路口,用于指挥车辆运输和行人行走,这是世界上第一个红绿灯。1868年,在英国伦敦的国会大厦广场出现了一种由红色,绿色两种颜色玻璃组成,可通过旋钮进行旋转的红绿灯,它的发明者是英国机械工程师纳伊特,人们规定红色的意思是“停止”,绿色的意思是“注意”。 但是这种红绿灯存在巨大的安全隐患,在使用不久就因为发生爆炸,导致警员受伤,随后被取消。

1914年,在美国又出现了一种电气方式启动的交通灯。这种红绿灯由红色,绿色和黄色的圆形发射器组成,安装在纽约市的第五大道。红灯是停止的意思,绿灯是允许通行的意思。

在1918年,已经发明了交通灯和红外线灯的控制系统。交通灯控制原理有几种,一种是安装一个可以检测压力的检测元件,当车辆靠近时,红灯会变成绿色;另一种是安装音量检测元件启动红绿灯,司机遇到红灯时可以按下喇叭,红灯就会熄灭绿灯亮。还有一种红外线红绿灯,在路面下安装压面传感器,路面有行人走过,压敏传感器可以检测到,红外可延长红色光束的时间,延迟车辆通行,以免发生交通事故。

交通信号灯的问世,使车流量能够得到一定控制,减少交通压力,保障道路主要通行能力,在减少交通事故方面有显著的效果。 1968年,对各种信号灯颜色的含义,联合国“道路交通信号和道路标志的协议”作出了规定。交通信号为绿色,表示车辆可以通行,直,左,右转,除非另一个标志禁止特定的转变。左、右转车辆必须遵循交通法规,使行人优先通过人行横道。红色是禁行意思,遇到红灯车辆必须停在路口停止线后,黄色是警告意思,遇到黄灯汽车不能越过停车线。

随着经济社会的快速发展,一些传统的方法根本解决不了交通的问题。道路异常拥堵影响人们的工作和出行,给人们越来越多的经济损失,现在的交通控制系统已不能满足高速发展的需要。随着生活需求的提高,对运输安全和服务质量提出了更高的要求。在交通管理控制方面,引进智能控制的红绿灯交通管理可以有效的提高运输安全,提高运输管理服务的质量,并可以在某些程度上减少因交通拥堵造成不必要的经济损失,同时也降低了交管人员的劳动强度。

汽车数目对于中国正在不断的增加,未来交通方面的压力势必是越来越大的,从智慧交通控制的角度去缓解这一压力是一条更加便捷,更加经济的道路。交通灯的智能管理会比修一条路更加经济,而且对改善交通的运行速度方面都有积极的效果,资源能更好的节约,从而使交管部门人员有更多的时间精力投入到管理整个城市交通控制的问题上,实现更大的社会经济效益,为我们城市打造一个更美好的明天而发挥重要作用。








第二章 单片机控制的交通灯的设计方案

第一节 系统工作原理和方案

设计的系统应用在一个车流量大的十字交叉路口,纵向南北方向作为主干道,横向东西方向为支干道。主、支干道交替通行,两个干道上的交通灯工作方式同时进行,主干道每次放行15秒,支干道每次放行10秒;每次绿灯变红之前,黄灯先亮3秒,此时另一干道上的红灯并闪烁。

主干道和支干道各由一组三色交通灯来控制,分别是主干道方向的红、黄、绿以及支干道方向的红、黄、绿。逻辑分析可知,当主干道为绿灯通行时,支干道必须为红灯禁行;绿灯结束后,主干道进入黄灯等待状态,支干道红灯闪烁;黄灯结束后,主干道变为红灯禁行,支干道变为绿灯通行;支干道绿灯结束后,支干道进入黄灯等待状态,主干道红灯闪烁,如此循环。从这个过程中可以看出,交通灯控制共分4个状态,分别为:S1状态,主干道方向为绿灯,支干道方向为红灯;S2状态,主干道方向为黄灯,支干道红灯闪烁;S3状态,主干道方向为红灯,支干道方向为绿灯;S4状态,支干道方向为黄灯,主干道红灯闪烁,这四个状态不断循环。由此我们可以列出4个状态的列表和做出4个状态的流程图。

表2.1  信号灯状态表


主干道方向

支干道方向

说明

绿

绿

S1

12s常亮

S2

闪烁

S1->S2

S3

7s常亮

S4

闪烁

S3->S4






图2.1 交通灯流程图


系统设置有4个按键,分别为Enter键,+键,-键和Shift键。Enter键是对设置的确认,+和-是对设置参数做调整,Shift键是对程序运行和参数设置两种状态的切换。当系统上电或手动复位之后,默认模式下会按照断电前程序里记录的参数运行。若此时Shift键按下,则设置为参数设置状态,数码管上显示原本记录的参数并闪烁,可通过+或-键对参数进行修改,最后按下Enter键将新参数保存。


图2.2 系统整体框架图

然后系统控制状态灯和LED数码管的显示,将状态码值以及显示的时间值的个位和十位送到相应IO口,通过定时器设定1s定时,当定时时间达到时产生定时器中断,在中断中将时间减一,然后刷新LED数码管的显示。直到时间值被减为0,判断下一个指示灯状态并装入对应的状态代码和时间值的状态。


图2.2状态灯和LED显示图



第二节 本课题主要内容

本课题的主要内容是设计了一种基于AT89C51单片机的控制的交通灯设计。这次设计以单片机为主要控制器,可以方便的实现十字路口交通灯的控制,实现行人与车流的分流,该系统控制期间各路转弯不再进行。拟解决的主要问题:

①模拟交通信号灯的交替变换。

②系统硬件设计与实现。

③系统软件设计。

④系统软硬件综合调试。

研究主要方法:

本设计根据实际交通法则模拟基本的交通控制系统,用红色LED表示禁行,绿色LED表示通行,黄色LED表示等待的信号,每个方向有一组LED数码管,可以倒计时显示提醒行驶者。据此,本设计系统以单片机为控制核心,连接成最小系统,和按键设置模块等产生输入,信号灯状态模块,LED倒计时模块。

研究要求:

①单片机型号:AT89C51

②纵向为主干道,横向为支干道。主、支干道交替通行,两个干道上的交通灯工作方式同时进行。

③主干道每次放行15秒,支干道每次放行10秒。

④每次绿灯变红之前,黄灯先亮3秒,此时另一干道上的红灯并闪烁。

⑤给出整个系统的结构图、软硬件流程


第三章 交通灯的硬件设计

第一节 电源模块设计

系统要想正常而稳定的运行,必须要有一套稳定的电源电路。为了给单片机和各种芯片提供工作电压,需要将交流220V转换为直流5V。

根据模拟电路学到的知识,转换过程如图3.1所示:

变压器经过一个保险丝连接电源,变压器或后面的电路如果发生短路,保险丝会因大电流引发的高温溶化而断开,从而保证后续电路不会受大电流的损坏。

变压器后面是一个桥式整流电路,整流后会得到一个纹波很大的直流电源,还需要接一个1000uF/25V的电解电容滤除纹波。

变压器输出端的电压经过桥式整流并电容滤波,如果电容两端直接接负载,当负载变化或交流电源电压出现波动时,电解电容C1两端的电压会发生较大幅度变化,要得到一个比较稳定的电压,需要在这里接一个三端稳压器。

当负载电流大时稳压器内的电阻会变小,当负载电流变小时三端稳压器内的电阻又会变大,使的稳压器的输出电压基本保持不变。

单片机和大多数功能芯片的输入电压都是直流5V,这里我们需要将交流220V经过变压器转换为9V的电压,整流后经7805稳压成直流5V。LM7805最大输出电流为1A,内部有限流式短路保护,短时间内输出端对地(2脚)短路不会烧坏7805。

三端稳压器后面接一个104的瓷片电容,起滤波和阻尼作用。


图3.1 220V交流稳压成5V直流原理


第二节 单片机控制模块设计

一、方案选择

方案一:AVR单片机。AVR不是一个简单的外设功能的叠加,但更多的模型以满足不同设计开发者的实际需要,同时可以提供一个低成本的OTP芯片。此外,PIC是低功耗的睡眠功能、深度睡眠、上电、掉电复位电路、看门狗电路,外围设备,占用空间小;成本低,安全技术也非常可靠,能够最大程度地满足开发者的实际要求。因此,在工业控制,PIC单片机被广泛的应用到各行各业的控制中,其稳定性、系统功耗等都为广大开发者认可。价格相比同性能产品在中上游水平。

方案二:PIC24H64GP506是16位RISC混合信号处理器,具有以下特点:

工作电压低,最低工作电压1.8V下正常工作。

功耗小,在运行模式下,只有200mA的工作电流,在休眠和待机模式下只有3ma的电流,在power off状态下只需要用0.1mA;运行状态中包含提供6种运行模式,3个时钟信号,包括1个高频率的时钟,1个低频时钟和1的DCO,灵活的时钟选择使系统能够在最合理的时钟工作,大大降低了系统功耗,便于系统的设计。

丰富的外设接口,包括标准的UART,SPI、I2C接口,可以和具有相同接口的设备连接进行通讯采集相关外设的数据。该MCU,具有256位RAM和8 kbit Flash内部;中断唤醒功能,可以通过中断使单片机从睡眠模式到主动模式

方案三:选择价格低廉的51系列单片机,具有51内核的低功耗、高性能的8位单片机,内含4K字节Flash只读程序存储器,兼容MCS-51指令和80C5l引脚结构,功能强大的微型计算机的AT89C51为工业控制应用系统提供低成本、高可靠性的解决方案。它具有如下特点:128字节内部RAM,32个I/O口线,看门狗,两个16位定时和计数单元,一个5两级中断结构的向量,一个UART通信口,内部晶振和时钟电路。

根据系统实际需要,最终选择成本低廉,便于操作的51系列单片机,型号为STC80C51。如图3.2所示为51系列单片机内核示意图,图3.3所示为AT80C51单片机最小系统电路图。



图3.2 8051单片机内核结构示意图

图3.3 STC80C51单片机最小系统电路图

二、复位电路

单片机最小系统是指一个微控制器系统可以正常工作需要具备的最少的元件构成的系统。51系列单片机的最小系统一般应包括:单片机,晶振电路,复位电路。

复位电路由电阻电容和电阻串联组成,根据电容电压不能突然改变的性质可以知道,一个系统上电,RST引脚默认为低电平,RC电路来决定高电平的时间。一个典型的51单片机,当RST引脚为高电平两个机器周期以上的将被重置,所以RC值要选择适当,才能确保可靠的复位,根据t=R*C,t要大于两个机器周期,选择电阻阻值为10k,电容容值为10uF。当然还有其他的参数组合,只要满足原理使RC组合可以产生在RST引脚置高至少两个机器周期。至于如何具体量化的计算,可以参考电路分析的书籍。

单片机复位电路就像电脑的重启,按下复位按钮内部的程序将从头开始运行。单片机系统在运行中,可能因为环境干扰等因素导致运行失控,就可以通过复位按键实现对单片机系统的重新启动。

在电路图中,电容器的容值为10uF,电阻器阻值为10k。所以根据公式,充电电容器增大到0.7倍电源电压,即设备电源是5V,充电电容器电压增长到5*0.7=3.5V这一过程所需要的时间是10K * 10UF = 0.1S。

也就是说,在计算机启动0.1S的过程中,电容两端的电压会从0增大到3.5V。这段时间内在电阻10K两端的电压会降低到1.5V(串联周围电路中的电压和总电压)。所以在0.1S,RST引脚电压为5V?1.5V。微控制器启动之后0.1S,电容C连续充电到5V,这是10K电阻两端的电压接近0V,RST在低电平,以使系统正常工作。当按下按钮时,该开关被接通时,这时在电容器两端形成环路,电容器被短路,电容器放电。随着时间的推移,电容器两端的电压,从5V释放成为1.5V,或甚至更小。这时10K电阻器两端的电压达到3.5V,或甚至更多,所以RST引脚变为高电平,单片机系统自动复位。

原则是微控制器复位电路RST引脚接收超过2US的高电平信号,只要电容器充电和放电时间大于2US,即可复位,该电路的电容值和电阻值可以根据实际电路做修改。按复位键,使电容短路,释放之前储存的能量,使电阻两端电压升高,从而给RST引脚一个高电平。


三、晶振电路

晶振电路是由振荡晶体和两个电容组成,为单片机提供指令时钟。对于51系统,外部晶振通常选择11.0592MHz,这样可以产生精准的微秒级别的机器时间,准确地得到9600bps和19200bps,用于有串口通讯的场合,方便定时操作。晶振电路在PCB布线设计时一定要尽量靠近单片机,并且两个引脚到单片机的走线尽量一样长,如果偏差太大会导致起振不良,或者计时不准确。晶振电路的地一定要和单片机的地共地,51单片机最小系统晶振在正常工作的情况下可以采用更高频率的晶振,51单片机最小系统晶振的振荡频率直接影响单片机的处理速度,频率越大处理速度越快。在晶振频率的选择上,在能够满足系统需要的前提下尽可能的选择低频率的晶振,晶振频率越低其功耗的能量越低,所以并不是晶振频率越高越好,要根据实际情况对频率和功耗进行取舍。

单片机的外部晶振如果单独跟单片机连接,理论上也是可以起振使单片机工作的,只是这样的结构会使电路中产生很多其他频率的谐波,谐波会降低时钟振荡器的稳定性。因此,在外部晶振的旁边会通过加一对起振电容去过滤谐波。起振电容的容值没有特别固定的值,根据不同的单片机会有不同的选择范围,51系列单片机的起振电容一般在15~30pF,在做PCB布线时起振电容离晶振越近越好,而晶振离单片机也是越近越好




第三节 LED显示模块
一、LED数码管介绍

LED数码管是由多个发光二极管被封装在一起,以形成“8”字形的装置,引线被连接在内部,每个二极管有自己的一个引脚,他们共同具有一个公共电极。数码管里有显示7段和一个小数点的8个发光二极管,就会看到相应的数码管段被点亮。

当一个特定的段的LED被施加电压时,这些特定的段将被点亮,以形成我们眼睛看到的图像。8段LED数码管只能显示简单的0~9的阿拉伯数字和A~F的英文字母,有一些段数比较多的LED可以显示更多的内容,总之,数码管还是以显示数字和字母为主,复杂的显示信息还是需要考虑使用液晶之类的更为复杂的电子器件。如图3.4所示为8段LED数码管示意图。


图3.4 LED数码管示意图


二、LED数码管显示原理

LED数码管主要是通过点亮相应段的发光二极管,在视觉上给人们显示出各个数字和字母的形状,驱动LED数码管的方式有两种,一种是静态显示驱动,另一种是动态显示驱动。静态显示驱动,也被称为直流驱动。静态驱动的装置,每个段需要由单片机的一个I / O口来驱动,或者作为BCD码两用。静态驱动的优点是编程简单,显示亮度高,缺点是占用I/ O端口多,加入需要驱动4个8段的数码管,则需要4*8=32个IO口,而51单片机可用的I/O端口一共只有32。我们在实际应用中必须增加的编解码驱动器,来减少I/O口的浪费,同时也增加了硬件电路的复杂性。第二种是动态显示驱动,数码管动态显示方式在微控制器中被广泛使用。动态显示是利用了人眼具有视觉停留现象,即人眼在看到某一景物后,在很短的时间内,即使该景物消失,在人眼中还会保留该景物的像。动态显示就是将数字按照个十百千位的格式分开,根据各个位的数字分别控制点亮对应数码管的发光二极管的段。每次只点亮一个位对应的数码管,其他位的数码管被熄灭。

通过依次控制每个LED数码管的COM端,它使每一个对应的数字显示,这是一个动态的过程。反过来显示,每位数码管点亮时间为1?2毫秒,由于人的视觉和发光二极管的余辉效应的持续性的现象,尽管你不是在同一时间点亮数码管,但事实只要扫描速度足够快,给人的印象是一组稳定的显示数据,不会有闪烁感,动态显示和静态显示的效果是一样的,但是可以节省大量的I / O端口,以及更低功耗。因此动态显示更为广泛的被应用。

第四节 按键设置模块

键盘是最常用的单片机系统的人机界面,根据组合形式可分为两种:独立式和阵列式。独立式键盘由于一个按键需要对应一个IO口,因此适合用于按键数量少的场合;阵列式是通过横向和纵向交叉检测,可以将IO口的使用数量呈指数减少,例如三根横向和三根纵向线交叉可以实现9个键码的分辨,如果按独立式键盘设计,需要9个IO口,而阵列式键盘只需要6个IO口,按键数量越多,可以节省的IO口就越多,所以阵列式非常适用于需要按键较多的情况,本系统需要小按钮控制,单片机的I / O端口足够,可直接使用独立式设计。按键电路原理图如图3.7所示。


图3.7 独立式按键电路

键盘开关矩阵由多个按钮组成,是单芯片系统中最常用的输入装置,可以将命令,地址和数据输入给单片机。通常单片机系统采用非编码键盘,非编码键盘由软件识别的键盘上的按键,它具有结构简单,灵活的特点,因此被广泛应用于微处理器系统。键盘按钮分为接触式和非接触式两种,微控制器应用的按键通常由一个机械键盘接触组成。

当开关K没有被按下时,KeyIn由于通过4.7K的上拉电阻与5V电源连接,因此输入为高,当K闭合后,KeyIn与GND短接,输入为低电平。也就是说,程序检测按键是否按下的方法是检测对应IO由高电平变成低电平,就表示该按键被按下。

但是由于按键结构采用的是机械触点,机械触电在状态变化的瞬间会产生电压的波动,这种抖动对于人的感知来说是极快的,根本感觉不到,但对于处理速度达到微秒级甚至纳秒级的单片机来说,这就是一段很长的时间了,在这段时间里,所有的电压波动都能被单片机一一检测到,单纯的只是检测IO的边沿变化就会在机械触电处于不稳定状态时误认为是按键被按下,而且会出现多次。如果设置为中断查询,程序就是频繁的进入中断函数。

解决这种问题的方法也很简单,就是我们通常所说的去抖。原理就是避开机械触点物理上会产生不稳定电压的时间段,再去检测IO口的电平。不管是通过轮询检测还是中断检测,一旦检测到按键IO口电平状态相比默认状态发生改变,则加入一小段延时,一般为几十个毫秒,延时过后,再去检测IO的电平,如果又变回默认状态,就说明这属于干扰导致的按键抖动,不需要处理;反之,则是真正的按键被按下的信号。

根据去抖的原理,我们也可以发现,去抖的延时时间也不能设置太长,否则会出现延时结束时按键早已经被松开,这样就导致有按键被按下却无法识别到。按钮在实际应用中千差万别,要根据实际按键的方式以及硬件电路等多方面因素去灵活运用,但以上的去抖原则是一定要遵循的。

第四章  交通灯的软件设计
第一节 主函数流程

在主函数流程中,首先单片机要实现自身寄存器的初始化,定时器初始化以及数码管和红绿灯状态显示控制,因为在运行过程中,数码管需要显示倒计时的时间,单片机可利用定时器T0和T1进行计时,设置定时器中断,在中断函数中对时间进行刷新。对于系统按键的检测可以使用主循环轮询方式,也可以采用外部中断处理方式。为了更加快速的响应按键信息,在程序中通过外部中断来实现按键的检测。

根据系统程序运行的特点分析,每个交通灯的状态都是从S1->S2->S3->S4->S1,如此循环往复,这些状态是固定的,而从一个状态转变为另一个状态的条件也是固定的,所以,在编程时采用状态机的处理方式是最合适的,状态机会比普通的逻辑罗列要清楚的多,也不易于出现逻辑上的错误,只是需要把各个状态都考虑清楚,不要留有状态上的漏洞。如图4.1所示为系统主函数流程图。


图4.1 系统主函数流程图

状态机是在软件程序设计中的一个重要的概念。例如,一个按钮命令,它可以被看作是一个状态机:一个状态为A,按下按钮后切换到B状态;然后触发另一个键切换到C的状态,或者返回的状态。这是关键的状态机的最简单的例子。实际分析方法比这些要复杂的多,但是这并不影响我们的状态机的理解。此外,按键本身可以被看作是一个状态机。一个小按键,包括:释放,抖动,闭合,抖动等状态。

要保证程序高效稳定的运行,除了各个功能模块程序,还需要一个重要的模块就是看门狗。在单片机系统中,由于微控制器的操作可能会受到来自外部电磁场的干扰,使程序失控陷入死循环中,程序的正常运行被中断,由MCU控制的系统不能继续工作,这将导致整个系统停顿,造成不可预料的后果,因此为了对微控制器的运行状况进行实时监控,单片机中有一个专门的硬件电路,俗称“看门狗”。

加入看门狗电路的目的是使微控制器可以实现连续工作,避免进入程序跑飞的死循环,看门狗功能模块是内嵌在单片机内部的,与单片机的I / O引脚相连,该引脚可以通过程序的控制,定期向单片机引脚送出高电平或低电平。一旦受到干扰,单片机程序跑飞,并陷入一个无限循环,看门狗引脚发送电平的功能不能被执行,这个时候,看门狗电路会由于缺乏由MCU发出的信号,向跟它连在一起的复位电路的引脚发送一个复位信号,使微控制器重新从程序存储器的起始位置执行代码,这样就实现了单芯片自动复位。

以前,看门狗电路需要一个特殊的看门狗芯片连接到单片机来实现,但是这会带来复杂的电路设计。随着技术的不断进步,现在的单片机基本都内置看门狗电路,看门狗定时器寄存器,查看其相应的功能知识点。




第二节 中断程序模块

单片机的定时器可以根据程序设置的分频频率进行计数,当计数达到某个设定值时,可以产生一个中断事件。比如51单片机外部晶振12M,最大计数两个字节,也就是65535,计一个数的时间为1/12M秒,就算计数值设为最大值的65535,也不可能计时1s,因此,需要在进入定时中断后对次数进行累加,比如中断累计20次,就表示当前计时为20*65535/12M=0.109225s。因此想要延时1s,需要将计数值设置为60000的情况下,进入中断200次。

MCS-51的工作频率通常情况为12MHz,机器周期与单片机工作频率相关,机器周期是12倍的工作频率,因此一个机器周期的时间长度为12 *(1 / 12MHZ)= 1微秒。我们可以知道每个指令周期的特定数目,这样我们就可以由一个指令执行的数量确定需要的时间。

中断程序分为定时器中断和外部中断。中断初始化函数和中断处理服务函数模块如下:

/**************定时器0初始化***********************

* 名称 : Time0_Init()

* 功能 : 定时器的初始化,12MZ晶振,50ms

* 输入 : 无

* 输出 : 无

****************************************************/

void Time0_Init()

{

TMOD = 0x11;

TH1 = 0xec;

TL1 = 0x78;

EA = 1;

ET0 = 1;

TR0 = 1;                           

}

/************外部中断0 的初始化***********************

* 名称 : Outside_Init()

* 功能 : 外部中断0 的初始化

* 输入 : 无

* 输出 : 无

*******************************************************/

void Outside_Init(void)

{

EX0 = 1;  //开外部中断0

IT0 = 1;  //负边沿触发

EA = 1;  //开总中断

}

/*****************定时器1***********************************

* 名称 : Time1_Int()

* 功能 : 显示定时器,工作方式1

* 输入 : 无

* 输出 : 无

****************************************************************/

void Time1_Int() interrupt 3

{

TH1 = 0xec;

TL1 = 0x78;

TR1=1;

if(key1<=3)

display();

else

ndisplay();                                         

}

中断0服务程序

/****************外部中断0 服务函数********************************

* 名称 : Outside_Int()

* 功能 : 外部中断0 的中断处理

* 输入 : 无

* 输出 : 无

*******************************************************************/

void Outside_Int(void) interrupt 0

{

EX0 = 0;

delay(30); //对按键进行抗干扰处理

if(key1 < 6)

{  key1++;}

else

key1=0;

delay(30);

EX0 = 1;            

}




第三节 数码管显示模块

表4.1为数码管显示数字与各个段的对应表:

表4.1 数码管段位对照表

显示数值

a

b

c

d

e

f

g

dp

驱动代码(16进制)

0

1

1

1

1

1

1

0

0

0xFC

1

0

0

0

1

1

0

0

0

0x18

2

1

0

1

1

0

1

1

0

0xC6

3

1

1

1

0

0

1

1

0

0xE6

4

1

1

0

0

1

0

1

0

0xDA

5

0

1

1

0

1

1

1

0

0x6E

6

0

1

1

1

1

1

1

0

0x7E

7

1

1

0

0

0

1

0

0

0xD4

8

1

1

1

1

1

1

1

0

0xFE

9

1

1

1

0

1

1

1

0

0xEE





第四节 交通灯电路

设计中采用发光二极管作为交通灯来使用,单片机的I/O接口直接和交通灯(发光二极管)连接。在十字路口的四组红、黄、绿三色交通灯中,东西方向道路上的两组同色灯连接在一起,南北方向道路上的两组同色的灯也彼此连接在,受单片机P2.2~P2.7控制。单片机的I/O接口与交通灯电路的具体连接方式为:P2.5~P2.7分别接东西方向的红、黄、绿共6个放光二极管,P2.2~P2.4分别接南北方向的红、黄、绿共6个发光二极管。12个发光二极管采用了共阴极的连接方式,因此I/O口输出高电平时,与之相连的发光二极管会亮,I/O口输出低电平时,相应的发光二极管会灭。交通灯电路原理图如下图所示。


            

图4.2交通灯电路图



第五节倒计时显示器电路

该显示器选用双位数码管来显示交通灯转换的剩余时间,根据设计的要求,每个路口需要1个数码管,这样就要4个数码管。我们可以选用共阴型数码管。四个路口倒计时显示被置在同一时刻显示不同的数字。电路如下图

图4.3倒计时显示器电路图



第六节交通灯设计总电路图

我们把倒计时显示器电路图、单片机、其他硬件连接起来,就有了总的电路图。以下是交通灯总电路图和PCB图。


图4.4 交通灯总电路图

  

图4.5 交通灯PCB图
第五章  Proteus仿真

第一节  Proteus软件介绍

Proteus软件是英国Labcenter electronics公司出版的EDA工具软件,它不仅具有其它EDA工具软件的仿真功能,还能仿真单片机及外围器件。它是目前最好的仿真单片机及外围器件的工具。虽然目前国内推广刚起步,但已受到单片机爱好者、从事单片机教学的教师、致力于单片机开发应用的科技工作者的青睐。Proteus是世界上著名的EDA工具(仿真软件),从原理图布图、代码调试到单片机与外围电路协同仿真,一键切换到PCB设计,真正实现了从概念到产品的完整设计。是目前世界上唯一将电路仿真软件、PCB设计软件和虚拟模型仿真软件三合一的设计平台,其处理器模型支持8051、HC11、PIC10/12/16/18/24/30/DsPIC33、AVR、ARM、8086和MSP430等,2010年即将增加Cortex和DSP系列处理器,并持续增加其他系列处理器模型。在编译方面,它也支持IAR、Keil和MPLAB等多种编译器。本次设计就是用该软件成功仿真程序运行。




第二节  Proteus仿真图片

软件运行后,交通灯开始工作(二极管显示红、黄、绿三色灯,LED显示倒计时),系统自动进入状态S1:纵向南北主干道方向绿灯亮,横向东西支干道方向红灯亮,南北主干道LED倒计时12秒,东西支干道LED倒计时7秒后,系统进入(S1~S2)然后南北方向黄灯亮3秒,东西方向红灯闪烁。仿真图片如下。











图4.6 S1状态

图4.7 S1~S2

3秒之后,系统进入S3状态,纵向南北方向红灯亮,横向东西方向绿灯亮,仿真图如下。

图4.8 S3状态

7秒后系统进入转换阶段,纵向南北方向红灯闪烁,横向东西方向黄灯亮3秒,仿真图如下。


图4.9 转换阶段


第六章  调试心得

在整个系统的调试过程中,由于自身经验的缺乏,不管是在硬件方面还是软件方面,都遇到了很多问题,经过各方查阅资料和老师同学的帮助,终于将问题一一解决,并总结了一些经验教训。

焊接时首先焊接电源部分的器件,如果发现电源部分工作电压异常,要立即断电,检查焊接线和器件的焊接方向是否正确。确保电源正常后,再焊接电路其他部分,避免其他器件被高电压损坏。如果焊接一个功能模块后发现调试不正常时候,首先应该先检查原理图连线是否正确,在查看原理图和焊接的板子是否一致。如果都是正确的,就应该确定原理图和芯片手册的引脚对应是否正确,检查是否有漏焊、虚焊、引脚短路的现象出现。可以利用示波器芯片引脚的电平进行测试,找到问题所在。有时我们可以将现在IO口转到别的上去看是否是IO口出现问题引起的。在焊接时候最好一起焊接两个板子进行对比,排除因为人为焊接原因造成错误发生。软件和硬件的调试时相互配合的,如果遇到问题时候不一定都是硬件出现问题造成系统错误。

软件调试首先根据系统的整体要求绘制出系统的程序流程图,根据程序流程图里的相关要求,利用KEIL编译软件利用C语言对系统硬件进行驱动首先要配置单片机各个寄存器的状态,配置相关的IO口,调试过程中尽量使用LED灯来观察程序的运行状态以判断单片机IO口是否已根据程序的要求输出相应的电平。控制继电器驱动时候要注意电路的控制,以避免外部的输入干扰对单片机系统造成影响,同时系统运行过程中要加如看门狗,当程序跑飞的时候及时复位单片机,是系统能够正常的运行,在按键检测电路的时候要注意对按键的抖动造成程序误操作。










结  论

通过这次设计,我对所学的专业知识有了更深的理解,尤其是单片机方面。在51单片机方面做了很多的资料方面的学习,掌握了单片机的基本工作的方法,以及焊接调试的流程。在设计过程中,查阅了大量的中外文资料,解决了不少难题,使我在分析问题解决问题的能力方面有了提升,增强了对学习的信心,并对电子专业产生了浓厚的兴趣,相信这对我以后的工作和学习有重要的帮助。

本次设计初步实现了51单片机控制十字路口交通等,实现行人与车流的分流的目的。运用了传统的8位MCU、性能全面、成本造价低、能够在室温下安全可靠运行,运行电子制图软件和KEIL编程软件,同时完成系统原理图和MCU的底层驱动代码的编写。能够在设计过程中完成对电子专业的各个节本技能的强化和所有应用课程的实践应用,其中包括单片机课程、数字电路、模拟电路、单片机c语言编程的各个专业课程的综合运用,在设计完成时我对自己本专业的四年所有科目进行的简单并全面的运行。

系统由于能力和精力的限制,整个系统还存在很多的不足,还可以实现更多的扩展,比如可以加入一些测量道路经过车辆数量的传感器,根据传感器的数据可以更加智能的实现对红绿灯时间的设置,使道路的利用率更高;还可以将单片机通过有线或无线的形式与交通指挥中心实现通信,使指挥中心可以根据实际交通情况实时的调整红绿灯的时间参数等等,我会在以后的学习中继续完善知识体系,尽可能的改善不足。随着单片机技术的进一步发展,这些问题都将被继续研究解决。


致  谢

经过几个月资料的查找和对本毕业设计相关知识的学习,已经完成整个系统的设计,在这个毕业设计过程中曝露出我许多的问题,由于对有些专业知识的了解不够深入,设计有些方面还是不够完善。在老师的帮助下,解决了遇到的很多设计难题,才使得毕业设计能够顺利的完成。再次对我的指导教师表示深深的感谢,老师在忙碌的工作中,对我毕业设计的进行耐心的指导,从设计最初我查找资料的时候,给我很大帮助让我在众多的资料中梳理出需要的知识的重点,在毕业设计的中期我提出系统的设计方案和解决方法,老师对我的设计方案进行了评估,指导我方案中出现的我的问题,并提出了宝贵的经验。在毕业设计后期对我设计电路和程序进行了指导。使我对单片机硬件电路和软件程序有了更深入的了解。把我繁琐的设计变得简洁、系统功能更合理。深深感受到了张清蓉老师对整个系统全局统筹性很强,使我也从中学到很多在课堂上学不到设计经验。在此,对张老师的严谨的治学态度和对学生负责的态度表示深深钦佩。其次对和我一起做毕设的同学表示深深的感谢,当我遇到问题时候,帮助我解决好多我能力之外的困难,如果没有他们的帮助我能这么顺利的完成我毕业设计。
最后感谢大学所有任课教师,他们在我在学校的四年里耐心的传授我知识,对我的各个方面能力培养付出太多的艰辛工作。为我在以后的工作中更好的学习打下了坚实的基础,同时感谢所有的同学们正式有你们鼓励和支持,才让我在做毕业设计这段时间不断改掉缺点,努力的把我的毕业设计认真的完成。


单片机源程序如下:

  1. <font style="font-size: 12pt">#include <reg52.h>                 //调用单片机头文件
  2. #define uchar unsigned char   //宏定义"uchar"代替"unsigned char"。
  3. #define u8 unsigned char   //宏定义"uchar"代替"unsigned char"。
  4. #define uint  unsigned int          //宏定义"uint"用来定义无符号整型数。

  5. //上下南北主干道
  6. //左右东西辅干道

  7. u8 code DisplayOther[]={
  8. 0xff,                 //0                空
  9. 0x7f,                 //1                "."
  10. 0xbf,                        //2                "-"
  11. 0xa7                        //3                c
  12. };

  13. //数码管段选定义                                                0                        1                2                        3                4                        5                6                        7                8                        9                A                        b                C                        d                        E                F                -
  14. uchar code smg_du[17] = {
  15. 0xc0,                //0
  16. 0xf9,                //1
  17. 0xa4,                //2
  18. 0xb0,                //3
  19. 0x99,                //4
  20. 0x92,                //5
  21. 0x82,                //6
  22. 0xf8,                //7
  23. 0x80,                //8
  24. 0x90,                //9
  25. 0x88,                //A
  26. 0x83,                //b
  27. 0xc6,                //C
  28. 0xa1,                //d
  29. 0x86,                //E
  30. 0x8e                //F
  31. };               
  32. uchar dis_smg[8 ] = {0xc0,0xf5,0x8c,0x94,0xb1,0x92,0x82,0xf4};               
  33. uchar smg_i = 4;    //显示数码管的个位数

  34. //数码管位选定义
  35. sbit smg_we1 = P2^0;            //东西数码管2
  36. sbit smg_we2 = P2^1;                        //东西数码管1
  37. sbit smg_we3 = P2^3;                        //南北数码管2
  38. sbit smg_we4 = P2^2;                        //南北数码管1


  39. char dx_s = 0;        //东西  南北 倒计时变量

  40. sbit nb_red    = P1^0;                //南北红灯
  41. sbit nb_green  = P1^2;                //南北绿灯
  42. sbit nb_yellow = P1^1;                //南北黄灯        1

  43. sbit dx_red    = P1^3;            //东西红灯
  44. sbit dx_green  = P1^5;                //东西绿灯1
  45. sbit dx_yellow = P1^4;                //东西黄灯1

  46. uchar flag_jtd_mode;  //交通灯的模式 根据时间
  47. bit flag_1s = 1;                //进入南北方向切换的标志位
  48. bit flag_500ms;
  49. bit flag_dx_nb;                 //东西南北模式
  50. uchar flag_5m_value;
  51. uchar i;
  52. uchar flag_alarm;        //模式
  53. //uchar dx_time = 30,nb_time = 20;   //东西、南北的时间
  54. uchar dx_time = 20,nb_time = 30;   //东西、南北的时间
  55. uchar flag_jdgz ;     //交通管制

  56. /********************************************************************
  57. * 名称 : u8 ChangeFor(u8 dat)
  58. * 功能 : 交换一个字节位的位置,用于数码管显示
  59. * 输入 : 需要改变的数
  60. * 输出 : 改变后的数
  61. ***********************************************************************/
  62. #define LED_a                6        //数码管段选的a段接在段选IO口的第0位
  63. #define LED_b                5
  64. #define LED_c                0
  65. #define LED_d                2
  66. #define LED_e                1
  67. #define LED_f                4
  68. #define LED_g                3
  69. #define LED_dp        7

  70. u8 ChangeFor(u8 dat)
  71. {
  72.         u8 temp=0;
  73.         if(dat&0x01)                //判断数据的第一位是否为1
  74.                 temp|=0x01<<LED_a;//如果为1,放到控制数码管a段的位置
  75.         if(dat&0x02)
  76.                 temp|=0x01<<LED_b;
  77.         if(dat&0x04)
  78.                 temp|=0x01<<LED_c;
  79.         if(dat&0x08)
  80.                 temp|=0x01<<LED_d;
  81.         if(dat&0x10)
  82.                 temp|=0x01<<LED_e;
  83.         if(dat&0x20)
  84.                 temp|=0x01<<LED_f;
  85.         if(dat&0x40)
  86.                 temp|=0x01<<LED_g;
  87.         if(dat&0x80)
  88.                 temp|=0x01<<LED_dp;
  89.         return temp;
  90. }

  91. /***********************数码位选函数*****************************/
  92. //i:        0,东西数码管2
  93. //                1,东西数码管1
  94. //                2,南北数码管2
  95. //                3,南北数码管1
  96. void smg_we_switch(uchar i)
  97. {
  98.         switch(i)
  99.         {
  100.                 case 0: smg_we1 = 0;  smg_we2 = 1; smg_we3 = 1;  smg_we4 = 1; break;
  101.                 case 1: smg_we1 = 1;  smg_we2 = 0; smg_we3 = 1;  smg_we4 = 1; break;
  102.                 case 2: smg_we1 = 1;  smg_we2 = 1; smg_we3 = 0;  smg_we4 = 1; break;
  103.                 case 3: smg_we1 = 1;  smg_we2 = 1; smg_we3 = 1;  smg_we4 = 0; break;
  104.         }        
  105. }


  106. /********************************************************************
  107. * 名称 : delay_1ms()
  108. * 功能 : 延时1ms函数
  109. * 输入 : q
  110. * 输出 : 无
  111. ***********************************************************************/
  112. void delay_1ms(uint q)
  113. {
  114.         uint i,j;
  115.         for(i=0;i<q;i++)
  116.                 for(j=0;j<110;j++);
  117. }


  118. /********************************************************************
  119. * 名称 : display()
  120. * 功能 : 数码管显示
  121. * 输入 : 无
  122. * 输出 : 无
  123. ***********************************************************************/
  124. void DisplayScan()
  125. {
  126.         static uchar i;
  127. //        if(T_MS_SCAN>=3)
  128.         {
  129.                 {               
  130.                 P0 = 0xff;                  //消隐
  131.                         smg_we_switch(i);                                    //位选
  132.                 P0 =        ChangeFor(dis_smg[i]);                  //段选         
  133.                 delay_1ms(3);
  134.                 }
  135.                 i++;
  136.                 if(i>=4)
  137.                         i=0;
  138. //                T_MS_SCAN=0;
  139.         }
  140. }
  141. /*********************定时器0、定时器1初始化******************/
  142. void time0_init()         
  143. {
  144.         TMOD = 0x01;                    //设置定时器0为工作模式1 (16-bit)
  145.         TL0 = 15536;                    //给定时器低位赋初始值                65536-15536=50000us=50ms,即50ms一个中断
  146.         TH0 = 15536 >> 8;               //给定时器高位赋初始值
  147.         TR0 = 1;                        //开启定时器0
  148.         ET0 = 1;                        //允许定时器0中断
  149.         EA = 1;                         //开启全局中断
  150. }

  151. /*********************交通灯处理函数*********************************/
  152. void jiaotongdeng_dis()
  153. {
  154.         if(flag_1s == 1)//如果切换标志为1
  155.         {
  156.                 flag_1s = 0;        //清零标志位
  157.                 if(dx_s == 0)
  158.                 {
  159.                         if(flag_dx_nb == 1)
  160.                                 dx_s = nb_time;          //南北时间
  161.                         else
  162.                                 dx_s = dx_time;          //东西时间
  163.                         flag_dx_nb = ~flag_dx_nb;                //切换南北时间
  164.                 }
  165.                 dx_s --;
  166.         }

  167. /***********************南北时间*********************************/
  168.                 if(flag_dx_nb == 0)  
  169.                 {
  170.                         if(dx_s > 3)
  171.                         {
  172.                                 dis_smg[0] = smg_du[dx_s % 10] ;
  173.                                 dis_smg[1] = smg_du[dx_s / 10] ;
  174.                                 dis_smg[2] = smg_du[(dx_s-3) % 10] ;
  175.                                 dis_smg[3] = smg_du[(dx_s-3) / 10] ;

  176.                                 dx_red    = 1;  //灭
  177.                                 dx_yellow = 1;        //灭
  178.                                 nb_green  =        1;        //灭
  179.                                 nb_yellow = 1;        //灭
  180.                                 dx_green  =        0;        //亮
  181.                                 nb_red    = 0;  //亮
  182.                                 flag_5m_value = 0;        
  183.                         }else if(dx_s <= 3)                 //当小于3秒时  黄灯要闪了
  184.                         {
  185.                                 dis_smg[0] = smg_du[dx_s % 10] ;
  186.                                 dis_smg[1] = smg_du[dx_s / 10] ;
  187.                                 dis_smg[2] = smg_du[dx_s % 10] ;
  188.                                 dis_smg[3] = smg_du[dx_s / 10] ;

  189.                                 dx_red    = 1;    //灭
  190.                                 dx_green  =        1;          //灭
  191.                                 nb_green  =        1;          //灭
  192.                                 nb_yellow = 1;          //灭
  193.                                 nb_red    = 0;    //亮
  194.                                 if(flag_500ms == 0)
  195.                                 {
  196.                                         dx_yellow = 0;//亮        
  197.                                 }
  198.                                 else
  199.                                 {
  200.                                         dx_yellow = 1;//灭        
  201.                                 }
  202.                         }
  203.                 }
  204. /***********************东西时间*********************************/
  205.                 if(flag_dx_nb == 1)  
  206.                 {
  207.                         if(dx_s > 3)
  208.                         {
  209.                                 dis_smg[2] = smg_du[dx_s % 10] ;
  210.                                 dis_smg[3] = smg_du[dx_s / 10] ;
  211.                                 dis_smg[0] = smg_du[(dx_s-3) % 10] ;
  212.                                 dis_smg[1] = smg_du[(dx_s-3) / 10] ;

  213.                                 dx_red    = 0;     //亮
  214.                                 nb_green  =        0;           //亮
  215.                                 nb_yellow = 1;           //灭
  216.                                 dx_green  =        1;           //灭
  217.                                 dx_yellow = 1;           //灭
  218.                                 nb_red    = 1;     //灭
  219.                                 flag_5m_value = 0;        
  220.                         }else if(dx_s <= 3)                 //当小于3秒时  黄灯要闪了
  221.                         {
  222.                                 dis_smg[0] = smg_du[dx_s % 10] ;
  223.                                 dis_smg[1] = smg_du[dx_s / 10] ;
  224.                                 dis_smg[2] = smg_du[dx_s % 10] ;
  225.                                 dis_smg[3] = smg_du[dx_s / 10] ;

  226.                                 dx_red    = 0;     //灭
  227.                                 dx_green  =        1;           //灭
  228.                                 dx_yellow = 1;           //灭
  229.                                 nb_red    = 1;     //灭
  230.                                 nb_green  =        1;           //灭
  231.                                 if(flag_500ms == 0)           //黄灯闪烁
  232.                                 {
  233.                                         nb_yellow = 0;        //亮        
  234.                                 }
  235.                                 else
  236.                                 {
  237.                                         nb_yellow = 1;        //灭        
  238.                                 }
  239.                         }
  240.         }                        
  241. }
  242. uchar key_can;         //按键值

  243. //按键
  244. sbit Key1=P1^6;                                 //设置键
  245. sbit Key2=P1^7;                                 //加按键
  246. sbit Key3=P3^2;                                 //减按键
  247. sbit Key4=P3^3;                                 //交通管制键
  248. //========================================================================
  249. // 函数: u8 Key_Scan()
  250. // 应用: temp=u8 Key_Scan();
  251. // 描述: 按键扫描并返回按下的键值
  252. // 参数: NONE
  253. // 返回: 按下的键值
  254. // 版本: VER1.0
  255. // 日期: 2015-05-29
  256. // 备注: 该函数带松手检测,按下键返回一次键值后返回0,直至第二次按键按下
  257. //========================================================================
  258. u8 Key_Scan()
  259. {         
  260.         static u8 key_up=1;//按键按松开标志
  261.         if(key_up&&(Key1==0||Key2==0||Key3==0||Key4==0))
  262.         {
  263.                 delay_1ms(10);//去抖动
  264.                 key_up=0;
  265.                 if(Key1==0)                        return 1;
  266.                 else if(Key2==0)return 2;
  267.                 else if(Key3==0)return 3;
  268.                 else if(Key4==0)return 4;
  269.         }
  270.         else if(Key1==1&&Key2==1&&Key3==1&&Key4==1)
  271.                 key_up=1;            
  272.          return 0;// 无按键按下
  273. }


  274. uchar flag_s;
  275. uchar menu_1;//纵横加减标示


  276. /********************设置函数*****************/
  277. void key_with()
  278. {
  279.         if(key_can == 4)   //交通管制按键
  280.         {
  281.                 flag_jdgz ++;
  282.                 if(flag_jdgz > 5)
  283.                         flag_jdgz = 0;        
  284.                 if(flag_jdgz == 1)         //  全部亮红灯
  285.                 {
  286.                         dx_red    = 0;  //亮
  287.                         nb_red    = 0;  //亮
  288.                         dx_green  =        1;        //灭
  289.                         dx_yellow = 1;        //灭
  290.                         nb_green  =        1;        //灭
  291.                         nb_yellow = 1;        //灭                        
  292.                 }
  293.                 if(flag_jdgz == 2)         //  东西绿灯  南北红灯
  294.                 {
  295.                         dx_red    = 0;  //亮
  296.                         nb_green  =        0;        //亮
  297.                         dx_green  =        1;        //灭
  298.                         dx_yellow = 1;        //灭
  299.                         nb_red    = 1;  //灭
  300.                         nb_yellow = 1;        //灭                        
  301.                 }
  302.                 if(flag_jdgz == 3)         //  南北绿灯  东西红灯
  303.                 {
  304.                         dx_green  =        0;        //亮
  305.                         nb_red    = 0;  //亮
  306.                         dx_red    = 1;  //灭
  307.                         dx_yellow = 1;        //灭
  308.                         nb_green  =        1;        //灭
  309.                         nb_yellow = 1;        //灭                        
  310.                 }
  311.                 if(flag_jdgz == 4)         //  南北绿灯  东西绿灯
  312.                 {
  313.                         dx_green  =        0;        //亮
  314.                         nb_green  =        0;        //亮
  315.                         dx_red    = 1;  //灭
  316.                         dx_yellow = 1;        //灭
  317.                         nb_red    = 1;  //灭
  318.                         nb_yellow = 1;        //灭                        
  319.                 }
  320.                 if(flag_jdgz == 5)         //  南北黄灯  东西黄灯
  321.                 {
  322.                         dx_red    = 1;  //灭
  323.                         dx_green  =        1;        //灭
  324.                         nb_red    = 1;  //灭
  325.                         nb_green  =        1;        //灭
  326.                         nb_yellow = 0;        //亮                        
  327.                         dx_yellow = 0;        //亮
  328.                 }
  329.         }
  330.         if(key_can == 1)          //设置键
  331.         {
  332.                 menu_1 ++;
  333.                 if(menu_1 >= 3)
  334.                 {
  335.                         menu_1  = 0;
  336.                 }
  337.         }

  338.         if(menu_1 == 1)           //设置东西的时间
  339.         {
  340.                 if(key_can == 2)
  341.                 {
  342.                         dx_time ++ ;                //加1
  343.                         if(dx_time > 99)        //时间最大值为99s
  344.                                 dx_time = 99;
  345.                 }
  346.                 if(key_can == 3)
  347.                 {
  348.                         dx_time -- ;                //减1
  349.                         if(dx_time <= 5)//时间最小值为5s
  350.                                 dx_time = 5;
  351.                 }
  352.                 dis_smg[0] = smg_du[(dx_time-1) % 10] ;        //显示为A
  353.                 dis_smg[1] = smg_du[(dx_time-1) / 10] ;        //显示为A
  354.                 dis_smg[2] = DisplayOther[2] ;                //显示东西设置的时候
  355.                 dis_smg[3] = DisplayOther[2] ;        
  356.         }        
  357.         if(menu_1 == 2)           //设置南北的时间
  358.         {
  359.                 if(key_can == 2)
  360.                 {
  361.                         nb_time ++ ;                //加1
  362.                         if(nb_time > 99)//时间最大值为99s
  363.                                 nb_time = 99;
  364.                 }
  365.                 if(key_can == 3)
  366.                 {
  367.                         nb_time -- ;                //减1
  368. ……………………

  369. …………限于本文篇幅 余下代码请从51黑下载附件…………
  370. </font>
复制代码

所有资料51hei提供下载:

交通灯全套资料.rar (5.87 MB, 下载次数: 196)

评分

参与人数 2黑币 +62 收起 理由
tieq1952 + 12 赞一个!
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

tieq1952 发表于 2018-12-5 07:53 | 显示全部楼层
谢谢分享!!!
回复

使用道具 举报

土豆子00 发表于 2019-4-7 10:11 | 显示全部楼层
楼主太棒啦,谢谢分享!
回复

使用道具 举报

juice123456 发表于 2019-4-9 08:36 | 显示全部楼层
感谢楼主分享
回复

使用道具 举报

无线强大 发表于 2019-4-24 17:46 | 显示全部楼层
非常感谢啊,,我也会努力学习的
回复

使用道具 举报

cyf123 发表于 2019-5-13 22:52 | 显示全部楼层
谢谢分享
回复

使用道具 举报

1250266916 发表于 2019-5-31 00:51 来自手机 | 显示全部楼层
厉害了
回复

使用道具 举报

摸鱼师兄 发表于 2019-6-5 17:59 | 显示全部楼层
请问一下,有pcb封装的文件吗? 不要截图的那种
回复

使用道具 举报

cczy 发表于 2019-6-5 21:16 | 显示全部楼层
感谢分享。。。
回复

使用道具 举报

cloudewey 发表于 2019-6-7 13:49 | 显示全部楼层
谢谢分享!
回复

使用道具 举报

fantasty_w 发表于 2019-6-14 14:09 | 显示全部楼层
课程设计很好的例子
回复

使用道具 举报

呃呃呃呃 发表于 2019-6-28 09:12 | 显示全部楼层
感谢楼主分享
回复

使用道具 举报

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

本版积分规则

QQ|手机版|小黑屋|单片机论坛 |51Hei单片机16群 联系QQ:125739409;技术交流QQ群7344883

Powered by 单片机教程网

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