超声雷达系统设计

一时心起,想起来分享下当年做的小玩意,今天就来个倒车雷达,要不然在电脑里早晚我得删了他,哼!要是哪天哪个小伙伴也被逼着做这种东西,来这!

背景
车辆在倒车时,由于驾驶员无法看到车辆后方的状况,存在 一定的安全隐患。倒车雷达是一种能够在倒车时检测车辆后方障碍物的电子装置,该装置一般使用超声波探测技术,利用超声探头发出超声波,超声波遇到障碍物后部分反射回超声探头,通过检测超声探头从发出超声波到接收到反射回来的超声波的时间即可判断是否存在障碍物并计算出车辆与障碍物之间的距离,系统将探测结果以声音或显示的方式告知车辆驾驶员,从而保障了驾驶安全。
超声雷达系统设计_第1张图片

设计任务
超声雷达系统设计_第2张图片
使用给定的关键器件设计并制作一种如图2所示的超声雷达系统。系统仿照倒车雷达的工作原理,能够检测到附近的障碍物和雷达与障碍物之间的距离,当雷达与障碍物之间的距离达到规定的警戒距离时,通过声、光发出报警
(1)用蜂鸣器的鸣叫声指示超声雷达与障碍物之间的距离。当距离超声探头正前方1m 以内没有障碍物时,蜂鸣器不发声;当距离超声探头正前方 1m 以内有障碍物时,蜂鸣器发出“嘀……嘀……”的间歇性鸣叫,随着超声探头与障碍物之间的距离缩短,鸣叫的间隔逐渐缩短,直至距离缩短至 0.5m 以内时变为长鸣。障碍物距离与蜂鸣器鸣叫的对应关系如表 所示。
(2)用10段LED发光条指示超声雷达与障碍物之间的距离。当距离超声探头正前方1m以内没有障碍物时,10段LED发光条所有指示灯全部熄灭;当距离超声探头正前方1m以内有障碍物时,随着超声探头与障碍物之间的距离缩短,LED发光条10个指示灯由绿色到红色顺次逐个点亮,直至距离缩短至0.5m以内时变为全亮。障碍物距离与指示灯发光的对应关系如表所示.
(3)增加障碍物距离数字显示功能,单位cm,精度1cm。
(4)增加自动测温声速补偿功能,提高距离测量的准确度。
(5)系统使用直流5V单电源供电
超声雷达系统设计_第3张图片

超声雷达系统设计_第4张图片
设计方案:
系统包括超声波谐振频率调理电路、超声波回波接收处理电路、LED数码显示模组、单片机及电源四部分。超声波测距仪主要以STC单片机为控制核心,其发射器是利用压电晶体的谐振带动周围空气振动来工作的.超声波发射器向某一方向发射超声波,在发射的同时开始计时 ,超声波在空气中传播,途中碰到障碍物就立即返回来,超声波接收器接收到反射波就立即停止计时。一般情况下,超声波在空气中的传播速度为340m/s,根据计时器记录的时间t ,就可以计算出发射点距障碍物的距离 s,即s=340×t/2, 这就是常用的时差法测距。在测距计数电路设计中,采用了相关计数法,其主要原理是:测量时单片机系统先给发射电路提供脉冲信号,单片机计数器处于等待状态,不计数;当信号发射一段时间后,由单片机发出信号使系统关闭发射信号,计数器开始计数,实现起始时的同步;当接收信号的最后一个脉冲到来后,计数器停止计数。
显示模块是一个8位段数码显示的LED和一个十段发光条;测量结果的显示用到四位数字段码,电源采用5V的DC直流稳压电源输入,供系统各部分电路使用。
超声波测距模块使用74LS04和CX20106芯片实现所需功能,其中,发射电路主要由反向器74LS04和超声波发射换能器T构成,单片机P1. 0端口输出的40 kHz方渡信号一路经一级反向器后送到超声波换能器的一个电极,另一路经两级反向器后进到超声波换能器的另一个电极。用这种推挽形式将方波信号加到超声波换能器两端,可以提高超声波的发射强度。输出端采用两个反向器并联,用以提高驱动能力。上拉电阻R10、R11,一方面可以提高反向器74LS04输出高电平的驱动能力,另一方面可以增加超声换能器的阻尼效果,缩短其自由振荡的时间;接收电路采用集成电路CX20106A。这是一款红外线检波接收的专用芯片,常用于电视机红外遥控接收器。考虑到红外遥控常用的载波频率38kHz 与测距超声波频率40kHz 较为接近,可以利用它作为超声波检测电路。实验证明,其具有很高的灵敏度和较强的抗干扰能力。适当改变C1 的大小,可改变接收电路的灵敏度和抗干扰能力。R1 和C5 控制CX20106A内部的放大增益,R2 控制带通滤波器的中心频率。一般取R1=4.7 Ω,C5=3.3μF。其余元件按图3-5取值。超声波接收头,当收到超声波时产生一个下降沿,接到单片机的外部中断INT0上。当超声波接收头接收到40kHz方波信号时,将会将此信号通过CX20106A驱动放大送入单片机的外部中断0口。单片机在得到外部中断0的中断请求后,会转入外部中断0 的中断服务程序进行处理,在移动机器人的避障工作中,可以在中断服务程序设定需要单片机处理的最短距离,比如1.0m。对于距离大于1.0m的障碍物,可以不做处理直接跳出中断服务程序;对于距离小于或等于1.0m.又做另外一种处理等。使用 CX20106A 作为超声波接收处理的典型电路。当 CX20106A 接收到40KHz的信号时,会在第7脚产生一个低电平下降脉冲,这个信号可以接到单片机的外部中断引脚作为中断信号输入。 使用CX20106A集成电路对接收探头受到的信号进行放大、滤波。其总放大增益80db
电路设计图如下图
超声雷达系统设计_第5张图片
总体设计方案框图如下图
超声雷达系统设计_第6张图片
最小系统电路就省略啦,太简单,讲一下显示电路和发射接收电路
超声波测距仪显示模块电路如图所示。通过单片机的21、22、23、24四个管脚的信号控制四个三极管的B极,利用三极管的开关特性,实现数码管的点亮,从而实现动态显示。采用LED 动态显示,数据经过芯片的计算后传到LED上,显示精度是厘米。
单片机STC89C52RC采用12MHz高精度的晶振,以获得较稳定的时钟频率,减少测量误差。单片机用P1.0端口输出超声波换能器所需的40KHz方波信号,利用外中断0口检测超声波接收电路输出的返回信号。显示电路采用简单实用的4位共阳LED数码管,用于显示车尾障碍物的距离,由单片机P0.0—P0.6接LED的a~g七个笔段,单片机的P0.7口接LED的dp段,P2.0~P2.3接四个8550三极管的公共端,通过软件以动态扫描方式显示。段码用74LS04驱动,位码用PNP三极管8550驱动
超声雷达系统设计_第7张图片
超声波发射电路
发射电路通常分为调谐式和非调谐式。在调谐式电路中有调谐线圈(有时装在探头内),谐振频率由调谐电路的电感、电容决定,发射的超声脉冲频带较窄。在非调谐式电路中没有调谐元件,发射出的超声频率主要由压电晶片的固定参数决定,频带较宽。将一定频率、隔度的交流电压加到发射传感器的固有频率40KHz,使其工作在谐振频率,达到最优的特性。发射电压从理论上说是越高越好,因为对同一支发射传感器而言,电压越高,发射的超声功率就越大,这样能够在接受传感器上接受的回波功率就比较大,对于接受电路的设计就相对简单一些。但是每一支实际的发生传感器有其工作电压的极限值,同时发射电路中的阻尼电阻决定了电路的阻尼情况。通常采用改变阻尼电阻的方法来改变发射强度。
发射部件的点脉冲电压很高,但是由于障碍物回波引起的压电晶片产生的射频电压不过几十毫伏,要对这样小的信号进行处理就必须放大到一定的幅度。接收部分就是由两级放大电路,检波电路及锁相环构成,其中包括杂波抑制电路。最终达到对回波进行放大检测,产生一个单片机(STC89C51RC)能够识别的中断信号作为回波到达的标志。
超声波发射电路原理图如下图所示
超声雷达系统设计_第8张图片
发射电路主要由反向器74LS04和超声波发射换能器T构成,单片机P1. 0端口输出的40 kHz方渡信号一路经一级反向器后送到超声波换能器的一个电极,另一路经两级反向器后进到超声波换能器的另一个电极。用这种推挽形式将方波信号加到超声波换能器两端,可以提高超声波的发射强度。输出端采用两个反向器并联,用以提高驱动能力。上拉电阻R10、R11,一方面可以提高反向器74LS04输出高电平的驱动能力,另一方面可以增加超声换能器的阻尼效果,缩短其自由振荡的时间
发射部分电路硬件接线图如图
超声雷达系统设计_第9张图片
超声波接收电路
电路采用集成电路CX20106A。这是一款红外线检波接收的专用芯片,常用于电视机红外遥控接收器。考虑到红外遥控常用的载波频率38kHz 与测距超声波频率40kHz 较为接近,可以利用它作为超声波检测电路。实验证明,其具有很高的灵敏度和较强的抗干扰能力。适当改变C1 的大小,可改变接收电路的灵敏度和抗干扰能力。R1 和C5 控制CX20106A内部的放大增益,R2 控制带通滤波器的中心频率。一般取R1=4.7 Ω,C5=3.3μF。其余元件按图3-5取值。超声波接收头,当收到超声波时产生一个下降沿,接到单片机的外部中断INT0上。当超声波接收头接收到40kHz方波信号时,将会将此信号通过CX20106A驱动放大送入单片机的外部中断0口。单片机在得到外部中断0的中断请求后,会转入外部中断0 的中断服务程序进行处理,在移动机器人的避障工作中,可以在中断服务程序设定需要单片机处理的最短距离,比如1.0m。对于距离大于1.0m的障碍物,可以不做处理直接跳出中断服务程序;对于距离小于或等于1.0m.又做另外一种处理等。
使用 CX20106A 作为超声波接收处理的典型电路。当 CX20106A 接收到40KHz的信号时,会在第7脚产生一个低电平下降脉冲,这个信号可以接到单片机的外部中断引脚作为中断信号输入。
使用CX20106A集成电路对接收探头受到的信号进行放大、滤波。其总放大增益80db。
以下是CX20106A的引脚注释
1脚:超声信号输入端,该脚的输入阻抗约为40kΩ。
2脚:该脚与地之间连接RC串联网络,它们是负反馈串联网络的一个组成部分,改变它们的数值能改变前置放大器的增益和频率特性。增大电阻R1或减小C1,将使负反馈量增大,放大倍数下降,反之则放大倍数增大。但C1的改变会影响到频率特性,一般在实际使用中不必改动,推荐选用参数为R1=4.7Ω,C1=3.3μF。
3脚:该脚与地之间连接检波电容,电容量大为平均值检波,瞬间相应灵敏度低;若容量小,则为峰值检波,瞬间相应灵敏度高,但检波输出的脉冲宽度变动大,易造成误动作,推荐参数为3.3μf。
4脚:接地端。
5脚:该脚与电源间接入一个电阻,用以设置带通滤波器的中心频率f0,阻值越大,中心频率越低。例如,取R=200kΩ时,f0≈42kHz,若取R=220kΩ,则中心频率f0≈38kHz。
6脚:该脚与地之间接一个积分电容,标准值为330pF,如果该电容取得太大,会使探测距离变短。
7脚:遥控命令输出端,它是集电极开路输出方式,因此该引脚必须接上一个上拉电阻到电源端,推荐阻值为10kΩ,没有接受信号是该端输出为高电平,有信号时则产生下降。
8脚:电源正极,4.5~5V。
接收部分电路如图所示
超声雷达系统设计_第10张图片
报警部分原理图
蜂鸣器与家用电器上的喇叭在用法上也有相似的地方,通常工作电流比较大,工作时电路上通过的电流基本上驱动不了蜂鸣器,需要增加一个电流放大的电路才可以,即由于一个管脚很难驱动蜂鸣器发出声音,所以增加了一个三极管来增加通过蜂鸣器的电流。
通过将蜂鸣器连接到三极管的集电极,一旦有被检测物体进入,单片机P1.1口为0,三极管导通,这样蜂鸣器的电流形成回路,发出声音。实现报警。当P1.1管脚为高时,三极管截至,蜂鸣器不发出声音。蜂鸣器报警电路如下如图所示:
超声雷达系统设计_第11张图片
十段发光条与通常的LED灯有相似之处,使用时可以看做是十个LED灯封装在一起使用,由于要控制发光条亮暗的个数来显示超声波探测的距离,所以需要单片机编程控制,于是将十段发光条接到单片机的I/O口上,最好选择相近的I/O口,不至于混淆,注意在接到单片机上之前要通过电阻限流防止发光条被烧毁,电阻阻值可在1 kΩ到10 kΩ之间选择,因为使用的是十段管,故可以使用排阻。发光条报警电路如下图超声雷达系统设计_第12张图片
温度补偿电路的设计
温度补偿电路通过使用温度传感器DS18B20实现温度采集,将温度传给单片机,再通过温度与声速的关系,即可将声速调整到一个较为准确的数值,从而实现减小测距误差的目的
温度与声速关系如下图所示
这里写图片描述
结果测算,空气中声速与温度的关系式可表示为
V=331.4+0.6T(m/s)
DS18B20的用法太简单,就三个管脚,不讲了,网上一堆资料,就贴下电路图
超声雷达系统设计_第13张图片
总体电路设计图如下图
超声雷达系统设计_第14张图片
成品长啥样?
超声雷达系统设计_第15张图片
超声雷达系统设计_第16张图片
醉醉重点的,代码呢?
距离的计算公式为:
d=s/2=(c×t)/2 (2-2)
其中d为被测物与测距器的距离,s为声波的来回的路程,c为声速,t为声波来回所用的时间。
距离计算程序如下:

void csbcj() //超声波测距 
{ 
        if(cl==1)           //1秒计时时间到
        { 
                   TR1=0;   //关闭定时器1
                TH0=0x00;   //定时器0赋初值
                TL0=0x00; 
                i=csbs;     //赋值发射的脉冲数
                while(i--)  //只要i不减到0就一直减,每次减,控制csbout取反
                { 
                        csbout=!csbout;    //取反,输出脉冲
                } 
                TR0=1;                    //打开定时器0     
                   i=mqs; //盲区 
                while(i--)                //控制延时
                {} 
                i=0; 
                while(csbint)             //超声波输入等于1
                { 
                        i++;              //i加
                        if(i>=4000)                        //等待时间过长 
                        csbint=0;                          //清零,退出while循环
                } 
                TR0=0;                 //停止计时
                TH1=0x9E; 
                TL1=0x57;              //T1重新赋初值,准备计时1s,重新测距
                t=TH0;                 //T0的高八位赋值到t
                t=t*256+TL0;           //高位乘以256就是左移8位,然后加上低八位,组成一个16位的数据
                t=t-29;        
                sudu1=get_temp();
                sudu1=sudu1*0.06*0.0001;        
                s=t*(ss+sudu1)/2; //时间乘以超声波的速度,然后除以2得到实际距离
                TR1=1;                 //打开定时器T1
                cl=0; 
                csbint=1;              //置一,准备下次测距

}

2.3.2 主程序设计
主程序首先是对系统环境初始化,设置定时器T0工作模式为16位定时计数器模式,置位总中断允许位EA并给显示端口P0和P2清零。然后调用超声波发生子程序送出一个超声波脉冲,为了避免超声渡从发射器直接传送到接收器引起的直射波触发,需要延时约0. l ms(这也就是超声波测距器会有一个最小可测距离的原因)后,才打开外中断0接收返回的超声波信号。由于采用的是12MHz的晶振,计数器每计一个数就是1us,当主程序检测到接收成功的标志位后,将计数器T0中的数(即超声波来回所用的时间)结合温度声速关系按声速计算公式计算,即可得被测物体与测距器之间的距离,其中TO为计数器T0的计数值。测出距离后结果将以十进制BCD码方式送往LED显示约0.5 s,然后再发超声波脉冲重复测量过程。为了有利于程序结构化和容易计算出距离,主程序采用c语言编写。下图为主程序流程图
超声雷达系统设计_第17张图片
主程序如下:

void main()                      //主函数 
{ 
        EA=1;                    //开中断 
        TMOD=0x11;               //设定时器0为计数,设定时器1定时 
        ET0=1;                                         //定时器0中断允许 
        ET1=1;                                         //定时器1中断允许
        ET2=1;                                          
        TH0=0x00; 
        TL0=0x          //T0初值用于距离计算
        TH1=0x9E; 
        TL1=0x57;       //赋初值25ms用于定时1秒采集一次距离数据
        TH2=0xd8; 
        TL2=0xf0;       //赋初值10ms定时
        T2CON=0;        
        csbds=0;        //超声波定时清零 
        csbout=1;       //超声波输出置位 
        cl=0;           //测量标识清零 
        csbs=8;         //默认脉冲数
        sj1=35;         //分段测距
        sj2=200;        //小于50和大于580都是盲区,不测距
        sj3=580;        //中间200分界计算方式略不同,测距更准确
        k4cl();         //计算当前盲区
        TR1=1;          //打开计时开关
        TR2=1;
        while(1)    
          { 
                  csbcj();                //调用超声波测距程序 
                  baojing();  
                  tempchange();           //温度转换函数
                  dis_temp(get_temp());   //温度指示                      
        } 
}

2.3.3 报警子程序设计
显示报警设备是用单片机控制脉冲,通过单片机内部程序进行计算,由LED发光条进行距离显示,并在一定的距离内让蜂鸣器接通,以不同频率发声来作为报警信号,提示具体位置。报警子程序如下,由于报警程序分为十段原理相同的条件判断,此处摘录一段,其余与此类同

void baojing()
{
    for(k=0;k<8;k++)
                {
                  if((s>50)&&(s<=55))
                  {
                    d1=0;
                    d2=1;
                    d3=1;
                    d4=1;
                    d5=1;
                    d6=1;
                    d7=1;
                    d8=1;
                    d9=1;
                    d10=1;
                    bj=0;   
                    delay2(55);
                    bj=1;
                    delay2(55);
                  }
                }

2.3.4 显示子程序设计
由于电路使用数码管来显示探测距离,所以程序驱动数码管示数,数码管的显示原理较为简单,本次选用四位共阴数管,共有12个管脚,分为4个段选和8个位选,段选用于选择当前选中哪一位数码管,当选中其中一位数码管后,位选给管脚赋值则让数码管按要求显示正确的数字,程序如下:

void scanLED()                             //显示功能模块 
{ 
        LED=buffer[0]; 
        LED3=0; 
        delay(200); 
        LED3=1; 
        LED=buffer[1]; 
        LED2=0; 
        delay(200); 
        LED2=1;   
        LED=buffer[2]; 
        LED1=0; 
        delay(200); 
        LED1=1; 
} 
void timeToBuffer()                    //转换段码功能模块 
{ 
        xm0=s/100;         
        xm1=(s-100*xm0)/10; 
        xm2=s-100*xm0-10*xm1; 
        buffer[2]=convert[xm2];         
        buffer[1]=convert[xm1]; 
        buffer[0]=convert[xm0]; 
}

2.3.5 温度补偿子程序设计
温度补偿是使用DS18B20温度传感器,只要按照此传感器时序图要求编程即采集到温度数据,首先对传感器进行初始化,然后依时序按位读取数据,调用时先进行温度转换,然后读取即可,程序如下:

void dsreset(void)    //DS18B20复位,初始化函数
{
    uint i;
    ds=0;
    i=103;
    while(i>0)
        i--;
    ds=1;
    i=4;
    while(i>0)
        i--;
}
bit tempreadbit(void)     //读一位数据函数
{
    uint i;
    bit dat;
    ds=0;i++;
    ds=1;i++;i++;
    dat=ds;
    i=8;while(i>0)i--;
    return(dat);
}

uchar tempread(void)        //读一个字节数据函数
{
    uchar i,j,dat;
    dat=0;
    for(i=1;i<=8;i++)
    {
        j=tempreadbit();
        dat=(j<<7)|(dat>>1);
    }
    return(dat);
}
void tempwritebyte(uchar dat)      //向DS18B20写一个字节数据函数
{
    uint i;
    uchar j;
    bit testb;
    for(j=1;j<=8;j++)
    {
        testb=dat&0x01;
        dat=dat>>1;
        if(testb)
        {
            ds=0;
            i++;i++;
            ds=1;
            i=8;while(i>0)i--;
        }
        else
        {
            ds=0;
            i=8;while(i>0)i--;
            ds=1;
            i++;i++;
        }
    }
}
void tempchange(void)          //DS18B20开始获取温度并转换
{
    dsreset();
    delay(110);
    tempwritebyte(0xcc);      //跳过读ROM指令
    tempwritebyte(0x44);      //写温度转换指令
}
uint get_temp()              //读取寄存器中存储的温度数据
{
    uchar a,b;
    dsreset();
    delay(110);
    tempwritebyte(0xcc);
    tempwritebyte(0xbe);
    a=tempread();         //读低八位
    b=tempread();         //读高八位
    temp=b;               
    temp<<=8;             //两个字节组合为一个字
    temp=temp|a;
    if(temp<0x800)flag=0;      //判断正负温度
        else if(temp>=0x800)
        {
            flag=1;
            temp=~temp+1;
        }
    f_temp=temp*0.0625;    //温度在寄存器中为12位,分辨率为0.0625°
    temp=f_temp*10+0.5; //乘以10表示小数点后取一位,加0.5是四舍五入
    f_temp=f_temp+0.05;
    return temp;           //temp是整型
}

调试注意:
超声波发射和接收采用超声波换能器74ls04(T发射)和CX20106A(R接收),中心频率为40kHz,安装时应保持两换能器中心轴线平行并相距4~8cm
这可是会对测距精度有不小的影响哦!
最最后,完整版代码;

#include  //头文件
sbit csbout=P1^0;                         //超声波发送 
sbit csbint=P3^2;                         //超声波接收 
#define LED P0 //数码管显示形  
sbit LED1=P2^4; //LED控制 
sbit LED2=P2^5; //LED控制 
sbit LED3=P2^6; //LED控制 
sbit bj=P2^0;//报警
#define ss 0.0347     //声音的速度
#define uchar unsigned char
#define uint unsigned int
sbit d1 = P3^6;
sbit d2 = P3^5;
sbit d3 = P3^4;
sbit d4 = P1^7;
sbit d5 = P1^6;
sbit d6 = P1^5;
sbit d7 = P1^4;
sbit d8 = P1^3;
sbit d9 = P1^2;
sbit d10 = P1^1;
sbit ds=P2^2;
sbit zsd=P2^1;
uint temp;               //定义整形的温度数据
float f_temp,sudu1;          //定义浮点型的温度数据
unsigned char cl,mqzd,csbs,csbds,buffer[3],xm1,xm2,xm0,timer2str;//显示标识  
unsigned char convert[10]={0x18,0x7b,0x2c,0x29,0x4b,0x89,0x88,0x3b,0x08,0x09};//0~9段码 
unsigned int s,t,i,xx,j,sj1,sj2,sj3,mqs,sx1,k,flag; 
unsigned int aa,bb,cc,dd,ee,ff;
void csbcj(); 
void delay(j);          //延时函数 
void scanLED();         //显示函数 
void timeToBuffer();    //显示转换函数 
void k1cl(); 
void k2cl(); 
void k3cl(); 
void k4cl();
void baojing(); 

void dsreset(void)    //DS18B20复位,初始化函数
{
    uint i;
    ds=0;
    i=103;
    while(i>0)
        i--;
    ds=1;
    i=4;
    while(i>0)
        i--;
}
bit tempreadbit(void)     //读一位数据函数
{
    uint i;
    bit dat;
    ds=0;i++;
    ds=1;i++;i++;
    dat=ds;
    i=8;while(i>0)i--;
    return(dat);
}

uchar tempread(void)        //读一个字节数据函数
{
    uchar i,j,dat;
    dat=0;
    for(i=1;i<=8;i++)
    {
        j=tempreadbit();
        dat=(j<<7)|(dat>>1);
    }
    return(dat);
}
void tempwritebyte(uchar dat)      //向DS18B20写一个字节数据函数
{
    uint i;
    uchar j;
    bit testb;
    for(j=1;j<=8;j++)
    {
        testb=dat&0x01;
        dat=dat>>1;
        if(testb)
        {
            ds=0;
            i++;i++;
            ds=1;
            i=8;while(i>0)i--;
        }
        else
        {
            ds=0;
            i=8;while(i>0)i--;
            ds=1;
            i++;i++;
        }
    }
}
void tempchange(void)          //DS18B20开始获取温度并转换
{
    dsreset();
    delay(110);
    tempwritebyte(0xcc);      //跳过读ROM指令
    tempwritebyte(0x44);      //写温度转换指令
}

uint get_temp()              //读取寄存器中存储的温度数据
{
    uchar a,b;
    dsreset();
    delay(110);
    tempwritebyte(0xcc);
    tempwritebyte(0xbe);
    a=tempread();         //读低八位
    b=tempread();         //读高八位
    temp=b;               
    temp<<=8;             //两个字节组合为一个字
    temp=temp|a;
    if(temp<0x800)flag=0;      //判断正负温度
        else if(temp>=0x800)
        {
            flag=1;
            temp=~temp+1;
        }
    f_temp=temp*0.0625;    //温度在寄存器中为12位,分辨率为0.0625°
    temp=f_temp*10+0.5; //乘以10表示小数点后取一位,加0.5是四舍五入
    f_temp=f_temp+0.05;
    return temp;           //temp是整型

}
void dis_temp(int t)       //显示温度数值函数,t传递的是整型的温度值
{
    if(t>300)
        zsd=0;
    else if(t<=300)
        zsd=1;


}



void delay2(unsigned int z)///delay延时一毫秒
{
    unsigned int x,y;
    for(x=z;x>0;x--)
    {
    if(flag==1)
                {
                    TR2=0;
                timeToBuffer();         
                  scanLED();
                  flag=0;
                  TH2=0xd8; 
                  TL2=0xf0;//            赋初值,定时10ms
                  TR2=1;    
                }
        for(y=110;y>0;y--);
    }
}

void main()                                        //主函数 
{ 
        EA=1;                                           //开中断 
        TMOD=0x11;                                   //设定时器0为计数,设定时器1定时 
        ET0=1;                                         //定时器0中断允许 
        ET1=1;                                         //定时器1中断允许
        ET2=1;                                          
        TH0=0x00; 
        TL0=0x00;                  //T0初值用于距离计算
        TH1=0x9E; 
        TL1=0x57;       //赋初值25ms用于定时1秒采集一次距离数据
        TH2=0xd8; 
        TL2=0xf0;       //赋初值10ms定时
        T2CON=0;
    //  T2MOD=0;

        csbds=0;        //超声波定时清零 
        csbout=1;       //超声波输出置位 
        cl=0;           //测量标识清零 
        csbs=8;         //默认脉冲数
        sj1=35;         //分段测距
        sj2=200;        //小于50和大于580都是盲区,不测距
        sj3=580;        //中间200分界计算方式略不同,测距更准确
        k4cl();         //计算当前盲区
        TR1=1;          //打开计时开关
        TR2=1;
        while(1)    
          { 
                        csbcj();                //调用超声波测距程序 
                        if(s>sj3)                //大于时显示“CCC” 
                        { 
                                buffer[2]=0xC6;         
                                buffer[1]=0xC6;         
                                buffer[0]=0xC6;         
                        } 
                        else if(s//小于时显示“- - -” 
                        { 
                                buffer[2]=0xBF;         
                                buffer[1]=0xBF;         
                                buffer[0]=0xBF; 
                        } 

                  baojing();  
                  tempchange();//温度转换函数
                  dis_temp(get_temp());  //温度指示                      
        } 
} 

void scanLED()                             //显示功能模块 
{ 
        LED=buffer[0]; 
        LED3=0; 
        delay(200); 
        LED3=1; 

        LED=buffer[1]; 
        LED2=0; 
        delay(200); 
        LED2=1; 

        LED=buffer[2]; 
        LED1=0; 
        delay(200); 
        LED1=1; 
} 

void timeToBuffer()                    //转换段码功能模块 
{ 
        xm0=s/100;         
        xm1=(s-100*xm0)/10; 
        xm2=s-100*xm0-10*xm1; 
        buffer[2]=convert[xm2];         
        buffer[1]=convert[xm1]; 
        buffer[0]=convert[xm0]; 
} 

void delay(i)                                         
{ 
    while(--i); 
} 

void timer1int (void)  interrupt 3  using 2 
{ 
        TH1=0x9E; 
        TL1=0x57;       //初值25ms
        csbds++; 
        if(csbds>=40)    //计数40次就是1s
        //if(csbds>=20)
        { 
                csbds=0; 
                cl=1;   //一秒采集一次
        }                 
} 
void timer2() interrupt 5
{
    TF2=0;
    TH2=0xd8; 
    TL2=0xf0;
    timer2str++;
    if(timer2str>=2)
    {
        timer2str=0;
        flag=1;

    }

}

void csbcj() //超声波测距 
{ 
        if(cl==1)           //1秒计时时间到
        { 
                   TR1=0;   //关闭定时器1
                TH0=0x00;   //定时器0赋初值
                TL0=0x00; 
                i=csbs;     //赋值发射的脉冲数
                while(i--)  //只要i不减到0就一直减,每次减,控制csbout取反
                { 
                        csbout=!csbout;    //取反,输出脉冲
                } 
                TR0=1;                    //打开定时器0     
                   i=mqs; //盲区 
                while(i--)                //控制延时
                {} 
                i=0; 
                while(csbint)             //超声波输入等于1
                { 
                        i++;              //i加
                        if(i>=4000)                        //等待时间过长 
                        csbint=0;                          //清零,退出while循环
                } 
                TR0=0;                 //停止计时
                TH1=0x9E; 
                TL1=0x57;              //T1重新赋初值,准备计时1s,重新测距
                t=TH0;                 //T0的高八位赋值到t
                t=t*256+TL0;           //高位乘以256就是左移8位,然后加上低八位,组成一个16位的数据
                t=t-29;        

                sudu1=get_temp();
                sudu1=sudu1*0.06*0.0001;        
                //s=t*ss/2;            //时间乘以超声波的速度,然后除以2得到实际距离
                s=t*(ss+sudu1)/2;
                TR1=1;                 //打开定时器T1
                cl=0; 
                csbint=1;              //置一,准备下次测距

                if(s//检测到当前距离小于50
                { 
                        if(csbs>6)             //脉冲数大于6
                        { 
                                csbs=csbs-2;   //脉冲数减2
                                sj1=40;        //sj1改成40
                        } 
                        sj1=sj1+2;             //sj1加2
                        k4cl();                //进入盲区,测试不出距离
                } 
                else if(s>=sj3)                //大于最大值,初始是580
                { 
                        if(csbs<32)            //脉冲数小于32
                        { 
                                csbs=csbs+2;   //脉冲数加2
                                sj1=sj1+10;    //加10
                                k4cl();        //进入盲区,测试不出距离
                        } 
                } 
        } 
} 
void k4cl()     //测试距离在哪个范围
{ 
        sx1=sj1-1; 
        sx1=sx1/ss; 
        mqs=sx1/4.5; 
}
void baojing()
{
    for(k=0;k<8;k++)
                {


                  if(s<=50) //如果距离小于80cm报警
                    {

                    d1=1;
                    d2=1;
                    d3=1;
                    d4=1;
                    d5=1;
                    d6=1;
                    d7=1;
                    d8=1;
                    d9=1;
                    d10=1;
                    timeToBuffer();         
                  scanLED();
                    bj=0;
                    }
                   if(s>100)  //如果距离大于80cm不报警
                    {

                    d1=0;
                    d2=0;
                    d3=0;
                    d4=0;
                    d5=0;
                    d6=0;
                    d7=0;
                    d8=0;
                    d9=0;
                    d10=0;
                    timeToBuffer();         
                  scanLED();
                    bj=1;
                    }
                  if((s>50)&&(s<=55))
                  {
                    d1=0;
                    d2=1;
                    d3=1;
                    d4=1;
                    d5=1;
                    d6=1;
                    d7=1;
                    d8=1;
                    d9=1;
                    d10=1;

                    bj=0;   
                    delay2(55);

                    bj=1;
                    delay2(55);

                  }
                  if((s>55)&&(s<=60))
                  {
                    d1=0;
                    d2=0;
                    d3=1;
                    d4=1;
                    d5=1;
                    d6=1;
                    d7=1;
                    d8=1;
                    d9=1;
                    d10=1;

                    bj=0;
                    delay2(63);

                    bj=1;
                    delay2(63);
                  }
                  if((s>60)&&(s<=65))
                  {
                    d1=0;
                    d2=0;
                    d3=0;
                    d4=1;
                    d5=1;
                    d6=1;
                    d7=1;
                    d8=1;
                    d9=1;
                    d10=1;

                    bj=0;
                    delay2(71);

                    bj=1;
                    delay2(71);

                  }
                  if((s>65)&&(s<=70))
                  {
                    d1=0;
                    d2=0;
                    d3=0;
                    d4=0;
                    d5=1;
                    d6=1;
                    d7=1;
                    d8=1;
                    d9=1;
                    d10=1;

                    bj=0;   
                    delay2(84);

                    bj=1;
                    delay2(84);

                  }
                  if((s>70)&&(s<=75))
                  {
                    d1=0;
                    d2=0;
                    d3=0;
                    d4=0;
                    d5=0;
                    d6=1;
                    d7=1;
                    d8=1;
                    d9=1;
                    d10=1;

                    bj=0;   
                    delay2(100);

                    bj=1;
                    delay2(100);

                  }
                  if((s>75)&&(s<=80))
                  {
                    d1=0;
                    d2=0;
                    d3=0;
                    d4=0;
                    d5=0;
                    d6=0;
                    d7=1;
                    d8=1;
                    d9=1;
                    d10=1;

                    bj=0;

                    delay2(125);

                    bj=1;
                    delay2(125);

                  }
                  if((s>80)&&(s<=85))
                  {
                    d1=0;
                    d2=0;
                    d3=0;
                    d4=0;
                    d5=0;
                    d6=0;
                    d7=0;
                    d8=1;
                    d9=1;
                    d10=1;

                    bj=0;   
                    delay2(167);

                    bj=1;
                    delay2(167);

                  }
                  if((s>85)&&(s<=90))
                  {
                    d1=0;
                    d2=0;
                    d3=0;
                    d4=0;
                    d5=0;
                    d6=0;
                    d7=0;
                    d8=0;
                    d9=1;
                    d10=1;

                    bj=0;
                    delay2(200);

                    bj=1;
                    delay2(200);

                  }
                  if((s>90)&&(s<=100    ))
                  {
                    d1=0;
                    d2=0;
                    d3=0;
                    d4=0;
                    d5=0;
                    d6=0;
                    d7=0;
                    d8=0;
                    d9=0;
                    d10=1;
                    bj=0;
                    delay2(250);    
                    bj=1;
                    delay2(250);
                  }

                }   
}

你可能感兴趣的:(单片机)