2020-03-10

电子科技大学成都学院

××××系

 



题目名称   基于STC51的车载超声波防撞雷达

学生姓名                                  

学  号                                  

专  业                                  

指导教师                                  

2019年5月制

基于STC51的车载超声波防撞雷达

摘 要


随着中国经济的不断发展与提升,汽车在人们的生活中已经得到了全面的普及,因此与汽车相关的配件以及安全系统的研发在市场上具有非常广泛的需求。基于超声波原理STC51单片机控制的车载防撞雷达在各个方面具有非常明显的优势,这一车载防撞雷达系统目前在汽车配件市场上更是供不应求。这一系统不受光照度、电磁场、图像色彩等多个因素的的影响,加之超声波传感器目前的产品已经趋于成熟,而且成本低廉。

本次课程设计主要是基于STC51单片机为控制系统,超声波传感器为信号采集系统的原理集成设计的。充分利用了超声波本身在车载雷达方面所具有的广泛优势,利用C语言作为软件开发的基础,将软件与硬件充分地进行结合来综合设计。本次课程设计由两个组员一起共同设计开发,产品主要由软件和硬件两个部分集合而成,组员1主要负责硬件方面的设计,组员2主要负责软件开发设计。硬件部分包括了STC51单片机最小系统,超声波发射、接收电路,数码管显示电路,电源电路以及报警电路组成;软件部分则包括了超声波发射接收中断程序、距离测试程序,数码管显示程序等几个模块组成。这一系统经过与汽车嵌入式系统集成以后,可以让驾驶员在停车、倒车、入库等多个易撞击操作中在驾驶舱内做到心中有数,极大地提高了汽车驾驶的安全性、可操作性以及舒适性。


关键词:单片机;防撞报警;超声波;



目 录


1       绪论... 1

1.1       课程设计立项背景... 1

2       系统电路设计... 2

2.1       综合电路设计... 2

2.1.1        超声波发射/接收电路设计... 2

2.1.2        距离显示模块电路... 3

2.1.3        距离碰撞电路报警设计... 4

2.1.4        STC89C51单片机最小系统电路设计... 5

2.2       电路调试以及评估... 6

2.2.1        电路板焊接... 6

2.2.2        电路调试分析... 6

3       雷达系统软件和硬件设计... 7

3.1       硬件与软件设计... 7

3.1.1        硬件设计... 7

3.1.2        软件设计... 8

4       结论... 12

附 录一   系统原理图... 13

附 录二   Proteus软件仿真图... 13

附 录三   C语言代码... 14

[if !supportLists]1                                                                               [endif]绪论

[if !supportLists]1.1      [endif]课程设计立项背景

随着国家经济的以及人民生活水平的不断提高,现在私家车的已经得到了全方位的普及,交通拥挤这一问题也变得越来越严重。而倒车、入库扥一系列问题也成为了一些驾驶技术不是非常熟练的驾驶员的困扰之一。这不仅会给驾驶员带来财产以及经济上的损失以及一些不必要的纠纷,甚至有时还会对驾驶员的生命安全构成一定的威胁。为更加优质高效地解决当前一些驾驶员所面临的倒车入库困境,安全倒车雷达的设计与生产也渐渐地成为一项重要的课题。51单片机不仅具有开发环境成熟,廉价,产品生态环境好等特征,而且在市面上已经得到了非常广泛的应用,同时超声波传感器具有精度高,质量好等优点,经过对自身知识水平的评估,我们小组课程最终确定采用以51单片机为主要的控制系统,以超声波传感器为核心的信息采集原件的设计方案,同时两位组员各自发挥自身的兴趣爱好以及优长,分别负责系统的软件和硬件开发。

本次课程设计主要论述了超声波的测距工作原理。从小的应用方面来说,本课题的研究直接解决了司机倒车时的困扰,更能有效地降低倒车过程中发生的大小事故。但从更广泛的应用来讲,超声波测距系统的研究在许多工业、交通运输业、军事等等方面有着更为广泛显著的应用;并且详细介绍了超声波传感器的工作特性和系统发射和接收等多种电路同时还有单片机的硬件设计与软件设计及其实现,突出以单片机为核心所设计的防撞报警器对于在汽车安全领域的突破与拓展有一定的作用。

















[if !supportLists]2                                                                               [endif]系统电路设计

[if !supportLists]2.1      [endif]综合电路设计

本次课程设计的超声波倒车雷达测距系统主要由超声波发射/接收电路,单片机最小系统复位电路,现实电路,报警电路等几个硬件电路系统组成,下面将逐一地对这几个电路系统进行系统的阐述,在确定最终采用各方面综合性能优越的51单片机的前提之下,进行了最终的电路的设计开发。

[if !supportLists]2.1.1     [endif]超声波发射/接收电路设计

超声波发射和接收电路的设计必须要考虑到传感器的灵敏度问题,对于这一系统的设计与研发,首先的难点在于40KHz超声波信号工作频率的产生,由于超声波倒车雷达所使用的超声波传感器所需的核心频率为40KHz超声波工作频率,只有在这个频段工作的超声波传感器才具有良好的灵敏性。当超声波传感器偏离这一工作频率之时,接收电路的设计不仅会大幅度地增加难度,而且将会使得接收的灵敏度大幅度地降低。因此课程设计关于超声波发射/接收电路的设计原则将会围绕这一思路进行。对于超声波传感器所需要的40KHz电路驱动信号的产生,实现的方法种类非常多,可以采用电容、电感震荡电路来实现与产生,但是综合考虑到其信号驱动的稳定性比较差,因此课程设计最终决定采用单片机来产生驱动信号,由于单片机采用的是晶振作为信号产生的源,因此其具有良好的稳定性以及非常高的稳定性,同时仅仅需要通过对软件编程进行一定的修改,便能够得到不同频率的驱动信号。

在进行超声波接收电路的设计时,通常会以超声波碰撞障碍物所返回的信号值作为距离判断的依据,因此对于超声波传感器的起控点的选择也是本设计成功的关键组成部分,超声波在传播的过程中受到环境的影响因素非常大,其信号强弱与环境因素关系密切,因此在进行接收与发射电路调试的过程中必须小心谨慎,合理地选择电压比较环节的起控点,从而达到当距离小于设定值时警报回响起的报警功能。超声波模块如图2-1-1:

            [if !vml]

[endif]

                        图2-1-1:超声波模块

[if !supportLists]2.1.2     [endif]距离显示模块电路

在进行显示系统电路设计的之时,考虑到显示器应该具有良好的可见性,同时应该显示器产品还需要具有较好的成熟性,因此最终选择了4位的8段数码管最为电路对超声波测量的距离进行显示。这不仅充分地利用了单片机的接口资源,同时也使得显示电路具有非常良好的可见性,在进行显示电路的设计过程中,为了最大限度地利用单片机的接口资源,现实电路采用的是串行驱动的LED驱动方式,运用4个数码管中的三个来对侧脸距离在400cm的超声波测量距离进行数值显示。

LED8段数码管显示器的驱动方式通常可以采用串联驱动和并联驱动两种方式,即我们通常所说的静态驱动和动态驱动两种方式,静态驱动通常需要与一些寄存器来进行配合,通过给每一位的8段LED数码管特定的电流,然后利用余晖效应来进行显示。显示之时单片机需要将显示字符码发送到相应的数码管段端口,然后维持电流即可。如果需要显示新的数字,则可以通过重新发送字符来进行显示。使用这种驱动方式进行显示CPU开支通常非常小,但是当进行多位的数码管显示时不仅会使得连线的数量大幅度的增加,还需要一些寄存器和译码器的支持,因此当多位显示的时候相应的成本自然也会增加。而动态显示一般用在多数码管显示方面,采用动态显示原理的多位数码管的显示通常能够大幅度地节约单片机的接口资源,其采用的分时段显示仅仅需要在软件方面稍微做一下改动就可以实现多位显示,其主要的原理是人类眼睛的余晖效应。LED8位数码管段动态显示的方法可以使得数码管在显示的时候亮度趋于均匀,因为动态显示的方法主要是通过轮流控制单片机各端口来对数码管进行驱动现实的。综合单片机资源以及成本节约的考量,本次课程设计最终决定采用动态显示的方法来对超声波距离测量数据进行显示,显示的过程中采用8155芯片作为单片机的I/O拓展端口,P1作为LED数字字符输出端口,同时经过74LS244反向驱动放大器来进行放大,进一步地提高LED的亮度。

在单片机应用系统中,发光二极管LED显示器常用两种驱动方式;静态显示驱动和动态显示驱动。所谓静态显示驱动,就是给要点亮的LED通过恒定的电流,即每一位LED显示器各引脚都要占用单独的具有锁存功能的I/O接口。单片机只需要把要显示的字形段码发送到接口电路并保持不变即可,如果要显示新的数据,在发送新的自行段码。因此,使用这种方法单片机中的CPU开销小,但这种驱动方法需要寄存器、编译码等硬件设备。当需要显示的位数增加时,所需要的期间和连线也应该增加,成本也增加。而所谓动态显示驱动就是给欲点亮的LED通以脉冲电流,即采用分时的方法,轮流控制各个显示器的COM端,使各个显示器轮流点亮,这是LED的亮度就是通断的平均亮度。考虑各种因素,本设计选用动态驱动显示。设计选用8155芯片作为单片机应用系统拓展的I/O口。PA口作为LED的字形输出口,为提高显示亮度,采用8路反相驱动器74LS244驱动;PC口作为LED的为选控制口,采用共阳极的LED显示器,由于8端全亮时位控线的驱动电流较大,采用6路反应驱动器74LS06以提高驱动能力。LED驱动显示电路的电路设计原理图主要如图2-1-2:

[if !vml]

[endif]

图4-2  显示电路

[if !supportLists]2.1.3     [endif]距离碰撞电路报警设计

报警电路主要由蜂鸣器进行报警,因此报警电路设计相对比较简单,主要是由放大电路以及扬声器电路进行组成,放大电路则采用一个三极管进行放大。由于单片机本身所产生的电流信号比较小,不能够驱动蜂鸣器电路,因此采用一个三极管来对单片机所产生的电流进行放大,通过三极管放大的电流来对蜂鸣器进行驱动。蜂鸣器采用的是有源蜂鸣器,因此其驱动方式相对简单,仅仅需要给其一段加上高电位,另一端加上低电位即可,如果要对蜂鸣器的频率进行控制,则需要简单地对加上高电位的时间进行控制即可,蜂鸣器报警电路的电路设计原理图如图2-1-3:

[if !vml]

[endif]

  图2-1-3  蜂鸣器报警电路

[if !supportLists]2.1.4     [endif]STC89C51单片机最小系统电路设计

单片机最小系统电路当中最为核心的就是复位电路和外部震荡电路,前者主要是给单片机进行复位,类似于电脑的重启功能,而护着主要提供时钟震荡,满足单片机的时序功能的恩需要和定时时频率的需求。主要的硬件包括:复位按键,11.0592频率的晶振,由于使用stc-isp下载,同时也为了降低成本,省去了自动下载调路而用CH340外接电路进行下载。通常,复位电路包括上电时的自动复位和通过按键进行复位两种复位形式。

时钟电路:STC89C52单片机的时钟震荡电路主要包括外接时钟震荡和内部电路时钟震荡两种方式。外部的时钟震荡电路由两个电容串联,然后中间加一个石英晶振即可,两个电容的值一般在5~30pF当中选择,常用的比较典型的值是22pF和30pF,石英晶振的选择值一般在1.2MHz~12MHz当中,典型的选择值是11.0592MHz,6MHz,12MHz,三种值。我们的设计当中采用的是11.0592MHz的设计值。两个电容的作用就是维持外部适中的震荡稳定和快速起振,由两个电容和一个石英晶振构成的自激震荡为内部电路提供有序的时钟脉冲周期信号。

单片机最小系统电路当中最为核心的就是复位电路和外部震荡电路,前者主要是给单片机进行复位,类似于电脑的重启功能,而护着主要提供时钟震荡,满足单片机的时序功能的恩需要和定时时频率的需求。主要的硬件包括:复位按键,11.0592频率的晶振,由于使用stc-isp下载,同时也为了降低成本,省去了自动下载调路而用CH340外接电路进行下载。通常,复位电路包括上电时的自动复位和通过按键进行复位两种复位形式。

时钟电路:STC89C52单片机的时钟震荡电路主要包括外接时钟震荡和内部电路时钟震荡两种方式。外部的时钟震荡电路由两个电容串联,然后中间加一个石英晶振即可,两个电容的值一般在5~30pF当中选择,常用的比较典型的值是22pF和30pF,石英晶振的选择值一般在1.2MHz~12MHz当中,典型的选择值是11.0592MHz,6MHz,12MHz,三种值。我们的设计当中采用的是11.0592MHz的设计值。两个电容的作用就是维持外部适中的震荡稳定和快速起振,由两个电容和一个石英晶振构成的自激震荡为内部电路提供有序的时钟脉冲周期信号。

[if !vml]

[endif]

     图2-1-4  上电复位电路

[if !supportLists]2.2      [endif]电路调试以及评估

[if !supportLists]2.2.1     [endif]电路板焊接

在完成电路设计的基础上,接下来就是将电路设计进行实物焊接,实物焊接时单片机产品设计过程中非常重要的一环,单片机系统设计除了需要优秀的产品设计以外,还需要良好的焊接工艺,只有将优秀的产品设计与良好的焊接工艺相结合,才能顺利地完成单片机的设计,对于单片机元器件的焊接则主要考虑到以下几点:

(1)可靠的电气焊接工艺:焊接座位电子产品从物理上的原理实现到电子产品电气连接的重要一环,电路的连线需要美观,可靠的电气连接来对元器件和电路办的合金层进行固定,从而达到产品电气连接的目的。

(2)连接焊点具有足够的机械强度:连接的重要目的之一便是固定元器件,同时也为了满足电气连接的需要,因此需要有足够的机械强度来对元器件和电路板的焊点进行固定。

(3)整齐光滑的外观,焊接工艺需要让焊点具光滑的外表,良好的焊点对焊接锡料的要求刚好到位,因此焊点上面会比较的光滑,只有整洁光滑的焊点外表才不会出现桥接以及粒尖现象。

[if !supportLists]2.2.2     [endif]电路调试分析

车载单片机防撞雷达系统工作的前提是电源电路模块工作正常,因此首先要对单片机电源部分进行测试,接上电源进行测试所得电源输出部分应该为5V。同时需要对单片机驱动超声波模块进行测试,运用示波器对电路进行测量,测得P01端口的输出频率为39.96KHz,与超声波模块所需的40KHz基本一致,因此符合实际的应用需求。依据超声波传感器在不同环境场合的需要,可在接收转换器上接上滤波电容以提高超声波传感器的抗干扰能力。












[if !supportLists]3                                                                               [endif]雷达系统软件和硬件设计

[if !supportLists]3.1      [endif]硬件与软件设计

[if !supportLists]3.1.1     [endif]硬件设计

STC89C51单片机作为控制中心的控制单元,不仅仅具有价格低廉,超低功耗,可拓展性强等优点。而且在IO驱动能力拓展,性价比,抗电磁干扰,抗噪音干扰等多个方面性能均非常优异。在性能方面,STC89C52是以流行的8051单片机内核为核心,且兼容所有8051单片机的内核程序设计,在硬件不改变得条件下,可以直接使用ISP系统编程,不管是程序的烧写,修改,程序的调动方面,都给我们带来了不言而喻的方便性。

STC89C51 单片机的I/O端口的编程可以依据实际的需要来对其进行相应的软件修改,即对其端口所对应的寄存器端口进行读写编程,具体的步骤主要如下:

(1)初始化的端口数据输出的寄存器,应该避免端口作为输出的时侯,开始阶段显现不确定的状态,影响到外围的电路正常工作;

(2)根据外围的电路功能,确定I/O端口id方向,初始化的端口数据方向寄存器。把用作输入的端口可以不用考虑其方向的初始化,因为I/O复位缺省值是输入;

(3)对于用作输入的I/O管脚,如需上拉,再经过输入上拉让其能寄存器为它内部配置个上拉电阻;

(4)最后对I/O的端口进行输出(写数据输出的寄存器)与输入(读端口)编程,完成对外围的电路的相应功能[8]。

根据系统设计要求,各接口功能如下:

  P1.0:产生输出一个40KHz的脉冲信号。(用于后方的测距电路)

  P1.1:产生输出一个40KHz的脉冲信号。(用于右侧的测距电路)

  P1.2:产生输出一个40KHz的脉冲信号。(用于左侧的测距电路)

   [if !vml]

[endif]:产生中断请求,接后方测距电路。

   [if !vml]

[endif]:产生中断请求,接后方测距电路。

  P1.3:接ICA3输入端,用于中断优先级的判断。

  P1.4:接ICA3输入端,用于中断优先级的判断。

  P0.0~P0.7:用于显示输出,接显示器。

  P2.7:接报警电路。

  P2.0:接报警电路。

  P2.1:接报警电路。

  XTAL1:接入外部晶振的引脚。在单片机的内部,它是一个反相放大器的输入端,                     这一个放大器构成出片内振荡器。采用外部振荡器的时侯,有些引脚应该接地。

  XTAL2:接入外部晶振的引脚。在片内接到振荡器反相放大器输出端与内部时钟发生器的输入端。当采用外部振荡器的时侯,此引脚接外部振荡的信号输入。

  RST:STC89C51复位信号的输入引脚,高电位的工作,当要对芯片复位的时侯,只须将此引脚电位提至高电位,并且持续不变两个机器的周期以上时间,STC89C51就能完成系统的复位各项工作,使内部特殊的功能寄存器内部都被设成已知状态。整体的电路硬件连接图如下:

[if !vml]

[endif]

图3-1-1:硬件原理图

[if !supportLists]3.1.2     [endif]软件设计

主程序为单片机程序主体,整一个单片机端的系统的软件功能的实现都在其中完成,在此过程里主程序调用子程序和中断服务程序。程序第一步完成初始化过程,第二步是一个重复控制发射信号的过程,即调用发射子程序几遍,并且次次发射的周期结束会判断在发射的信号后延时等待过程中是否会发生;中断,即是否回波的产生判断程序的流程。

[if !vml]

[endif]

图5-2  单片机软件主程序流程

[if !vml]

[endif] 

                          图5-3(a)  单片机软件子程序流程图

功能说明�:TH0*256时间值+TLO中读取出来的时间差数据并不能作为距离值直接显示输出,因为时间差值与实际的距离值之间转换公式为Outcome=TH0*256+TL0; Outcome=(Outcome*1.7)/100。其中,V为声音在常温下的传播速度,T为发射信号到接收之间经历的时间,在这个部分中,信号处理包括计数值与距离值换算,二进制与十进制转换。


[if !vml][endif][if !vml][endif][if !vml]

[endif]

          图5-3(b) 单片机软件子程序流程图

功能说明�:显示报警程序中,当小车距离障碍物大于5cm且小于40cm时,车上左右灯闪烁,会报警鸣声处于警告区;当小车距离障碍物小于5cm时,车上左右灯显示红色并且会报警鸣声比之前的大,处于危险区;当小车距离障碍物大于40cm时,车上左右灯绿色,处于安全区。

在系统硬件表现出的超声波测距基本功能的同时,系统软件所实现功能主要是系统功能的实现和数据处理与应用。根据上节所述系统硬件设计和所完成的功能,系统软件需要       实现以下功能:

一、信号控制

在系统的硬件中,已完成的发射电路、接收电路、检测电路、显示电路等设计。在系统软件里,要完成出增益控制信号与门控信号、发射脉冲信号与峰值采集信号及远近控制信号的时序及输出。

二、数据存储

为得到发射信号和接收回波两者之间时间差,须读出此刻计数器里的计数值,接着存储在 RAM 中,并且每次的发射周期的开始,必须对计数器进行清零操作,以备后续的处理。

三、信号处理

RAM 里存储的计数值不能作为距离值的直接地显示输出,计数值和实际距离值之间转换

公式为:距离=高电平时间*声速(340M/S)/2                      (5-1)

四、数据传输与显示

通过软件的处理得到距离送显示输出,用三位 LED 显示。因为采用单片机STC89C51并且考虑了系统的控制流程,所以整一个系统软件都是 STC89C51系列单片机的汇编语言实现。由于距离值的得出和显示是在中断子程序里完成的,因此在初始化的发射程序后进入到中断响应的等待过程。继中断响应后,原始数据经过计数值和距离值换算子程序与二进制和十进制转换子程序之后显示输出。整一个系统软件的功能实现可以分为主程序、中断服务程序等主要的部分。






















[if !supportLists]4                                                                               [endif]结论

本次课程设计在分析了汽车业现状的基础上,提出了汽车防撞报警设计及其重要性。设计中对车载防撞报警系统的设计可应用在汽车倒车等多种场合,用于告知驾驶者在倒车的时候能准确的避开可能对倒车过程中有着的危害和障碍物与行人,有一定较强实用性,提高驾驶员的安全性。















附 录一   系统原理图

附 录二   Proteus软件仿真图

[if !vml]

[endif]


附 录三   C语言代码

#include //器件配置文件

#include

#include "eeprom52.h"

//传感器接口

sbit RX = P2^3;

sbit TX = P2^2;

//按键声明

sbit S1 = P1^4;

sbit S2 = P1^5;

sbit S3 = P1^6;

sbit S4=P1^1;

sbit S5=P1^2;

sbit S6=P1^3;

bit msflag=0;

sbit light=P3^6;

sbit ms=P3^7;


sbit jg=P3^0;

sbit yg=P3^1;



sbit DIAN=P0^5;

//蜂鸣器

sbit Feng= P2^0;


//变量声明

unsigned int  time=0;

unsigned int  timer=0;

unsigned char posit=0;

unsigned long S=0;

unsigned long BJS;//报警距离

char num=0;

//模式 0正常模式 1调整

char Mode=0;

bit flag=0,flag_BJ;


unsigned char const discode[] ={0x5F,0x44,0x9D,0xD5,0xC6,0xD3,0xDB,0x47,0xDF,0xD7,0x80};     //数码管显示码0123456789-和不显示


unsigned char disbuff[4]         ={0,0,0,0};             //数组用于存放距离信息

unsigned char disbuff_BJ[4]  ={0,0,0,0};//报警信息

sbit W0=P2^4;

sbit W1=P2^5;

sbit W2=P2^6;

sbit W3=P2^7;


/******************把数据保存到单片机内部eeprom中******************/

void write_eeprom()

{

       SectorErase(0x2000);

       byte_write(0x2000,BJS%255);

       byte_write(0x2001,BJS/255);

       byte_write(0x2060,a_a);     

}


/******************把数据从单片机内部eeprom中读出来*****************/

void read_eeprom()

{

       BJS   = (byte_read(0x2001)*255)+byte_read(0x2000);

       a_a      = byte_read(0x2060);

}


/**************开机自检eeprom初始化*****************/

void init_eeprom()

{

       read_eeprom();             //先读

       if(a_a!= 1)            //新的单片机初始单片机内问eeprom

       {

              BJS   = 50;

              a_a= 1;

              write_eeprom();        //保存数据

       }    

}

//延时100ms(不精确)

void delay(void)

{

   unsigned char a,b,c;

   for(c=10;c>0;c--)

       for(b=38;b>0;b--)

           for(a=130;a>0;a--);

}


//按键扫描

void Key_()

{

       ms=~msflag;

       if(S4==0){

              delay();      //延时去抖

                     if(S4==0){

       msflag=~msflag;

                            while(!S4);

              }

       }

       if(msflag==0){

              if(S5==0){

                     delay();      //延时去抖

                            if(S5==0){

                                   if(jg==1&&yg==1){

                                                 jg=0;

                                   }elseif(jg==0 && yg==1){

                                                 jg=1;yg=0;

                                   }elseif(yg==0 && jg==1){

                                                 jg=0;yg=1;

                                   }

                                   while(!S5);

                     }

              }

                     if(S6==0){

                            delay();      //延时去抖

                                   if(S6==0){

                                          jg=1;yg=1;

                                          while(!S6);

                            }

                     }

       }else{

              if(light==0){

                     //距离小于报警距

                     if(S<=BJS)                   //距离小于报警值

                     {

                             jg=0;yg=1;

                     }

                     else                       //距离大于报警值

                     {

                            yg=0;jg=1;

                     }

              }else{

                     jg=1;yg=1;

              }

       }



       //+

       if(S1==0)

       {

              delay();      //延时去抖

              delay();      //延时去抖

              while(S1==0)

              {

                     P1=P1|0x0f;

              }

                     BJS++;   //报警值加

              if(BJS>500)//最大500

              {

                     BJS=1;

              }

              write_eeprom();                      //保存数据

       }

       //-

       elseif(S2==0)

       {

              delay();

              delay();      //延时去抖

              while(S2==0)

              {

                     P1=P1|0x0f;

              }

                     BJS--;     //报警值减

              if(BJS<1)       //最小1

              {

                     BJS=500;

              }

              write_eeprom();                      //保存数据

       }

       //功能

       elseif(S3==0)        //设置键

       {

              delay();

              delay();      //延时去抖

              while(S3==0)

              {

                     P1=P1|0x0f;

              }

                     Mode++;        //模式加

                     num=0;

              if(Mode>=2)          //加到2时清零

              {

                     Mode=0;

              }    

       }

}

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

//扫描数码管

void Display(void)                     

{

       //正常显示

       if(Mode==0)

       {

              num++;

              if(num==1)

              {

                     W3=1;

                     W0=1;

                     P0=~discode[disbuff[0]];

                     DIAN=0;

                     W1=0;   

              }

              elseif(num==2)

              {

                     W1=1;

                     P0=~discode[disbuff[1]];

                     W2=0;

              }

              elseif(num>=3)

              {

                     W2=1;

                     P0=~discode[disbuff[2]];

                     W3=0;

                     num=0;

              }

       }

       //报警显示

       else

       {

              num++;

              if(num==1)

              {

                     W3=1;

                     P0=~0xCE;            //11001110

                     W0=0;

              }

              elseif(num==2)

              {

                     W0=1;

                     P0=~discode[disbuff_BJ[0]];

                     DIAN=0;

                     W1=0;   

              }

              elseif(num==3)

              {

                     W1=1;

                     P0=~discode[disbuff_BJ[1]];

                     W2=0;

              }

              elseif(num>=4)

              {

                     W2=1;

                     P0=~discode[disbuff_BJ[2]];

                     W3=0;

                     num=0;

              }

       }

}

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

//计算

void Conut(void)

{

       time=TH0*256+TL0;       //读出T0的计时数值

       TH0=0;

       TL0=0;                           //清空计时器

       S=(time*1.7)/100;     //算出来是CM


       if(Mode==0)                   //非设置状态时

       {

              if((S>=700)||flag==1)//超出测量范围显示“-”

              {    

                     flag=0;

                     disbuff[0]=10;         //“-”

                     disbuff[1]=10;         //“-”

                     disbuff[2]=10;         //“-”

              }

              else

              {

                     //距离小于报警距

                     if(S<=BJS)                   //距离小于报警值

                     {

                             flag_BJ=1;           //报警变量置一,定时器开始报警

                     }

                     else                       //距离大于报警值

                     {

                            flag_BJ=0;            //关闭报警

                            Feng=1;                //蜂鸣器关闭

                     }

                     disbuff[0]=S%1000/100;              //将距离数据拆成单个位赋值

                     disbuff[1]=S%100/10;

                     disbuff[2]=S%10;

              }

       }

       else

       {

                     Feng=1;

                     flag_BJ=0;                                           //报警关闭

                     disbuff_BJ[0]=BJS%1000/100;

                     disbuff_BJ[1]=BJS%100/10;

                     disbuff_BJ[2]=BJS%10;

       }

}

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

//定时器0

void zd0() interrupt 1           //T0中断用来计数器溢出,超过测距范围

{

       flag=1;                                       //中断溢出标志

}

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

//定时器1

void zd3() interrupt 3           //T1中断用来扫描数码管和计800MS启动模块

{

       TH1=0xf8;

       TL1=0x30;                          //定时2ms

       Key_();                               //扫描按键

       Display();                            //扫描显示

       timer++;                       //变量加

       if(flag_BJ==1)                              //报警开

       {

              Feng=0;

       }

       if(timer>=400)                     //400次就是800ms

       {

              timer=0;

              TX=1;                             //800MS  启动一次模块

              _nop_();

              _nop_();

              _nop_();

              _nop_();

              _nop_();

              _nop_();

              _nop_();

              _nop_();

              _nop_();

              _nop_();

              _nop_();

              _nop_();

              _nop_();

              _nop_();

              _nop_();

              _nop_();

              _nop_();

              _nop_();

              _nop_();

              _nop_();

              _nop_();

              TX=0;

       }

}

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

//主函数

void main(void)

       TMOD=0x11;          //设T0为方式1,GATE=1;

       TH0=0;

       TL0=0;         

       TH1=0xf8;              //2MS定时

       TL1=0x30;

       ET0=1;                        //允许T0中断

       ET1=1;                    //允许T1中断

       TR1=1;                    //开启定时器

       EA=1;                                 //开启总中断

       init_eeprom();  //开始初始化保存的数据 

       while(1)

       {

              while(!RX);           //当RX为零时等待

              TR0=1;                 //开启计数

              while(RX);            //当RX为1计数并等待

              TR0=0;                 //关闭计数

              Conut();                //计算

       }

}




nG�RoE/

你可能感兴趣的:(2020-03-10)