微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > MCU和单片机设计讨论 > 带温度补偿的超声波测距程序

带温度补偿的超声波测距程序

时间:10-02 整理:3721RD 点击:
程序名:带温度补偿的超声波测距程序
编写人:曾文豪杰
编写日期:2012年11月11日
程序设计思路:1.利用DS18B20将环境的温度测量出来。2.根据测量出来的环境温度计算出
该温度下声音的速度。3.记录该速度。4.启动超声波模块,让其发出超声波。5.利用定时器测量出超声波信号遇到障碍物后返回所需要的时间。6.利用前面测出的声速和定时器计算的时间算出超声波模块到障碍物的距离,并把距离显示在数码管显示。7.重复以上步骤。
硬件环境:单片机采用STC89C52。12M晶振,两块74HC573的锁存器,一块控制数码管的段选,锁存端为P2.6.一块控制数码管的位选,锁存端为P2.7.两块锁存器的信号段均接单片机的P0口。数码管采用四位一体八段共阴型。超声波模块采用HR-04四脚型。Echo接P1.0,Trig接1.1.DS18B20接P2.2.
*/

#include <reg52.h>         //STC89C52头文件
#define uchar unsigned char   
#define uint unsigned int
unsigned int  time=0;
unsigned int  timer=0;
unsigned long S=0;         //距离变量
bit  flag =0;                    //超声波模块量程溢出标志(>5米时置1)
sbit echo=P1^0;             //超声波模块的发射端
sbit trig=P1^1;               //超声波模块的接收端
sbit ds=P2^2;                //DS18B20的信号线
sbit duan=P2^6;            //数码管段选信号锁存端
sbit wei=P2^7;              //数码管位选信号锁存端
int temp;   
//八位共阴数码管编码
unsigned char code shuzu[]={0x3f,0x06,0x5b,0x4f,                //0-3
                                            0x66,0x6d,0x7d,0x07,               //4-7
                                            0x7f,0x6f                                 //8-9
};
/*********************************************************/
//毫秒级延时
void delayms(unsigned char z)  
{
       unsigned char a,b;
       for(a=z; a>0; a--)
                for(b=110; b>0; b--);
}
/*********************************************************/
/*********************************************************/
//微秒级延时
void delayus(unsigned char z)  
{
       while(z)
         z--;
}
/*********************************************************/
//DS18B20初始化
void ds18b20init()
{
           ds=0;
           delayus(80);                //延时480-960us
           ds=1;
           delayus(4);                 //等待应答
}
/*********************************************************/
//DS18B20读命令子程序(读一字节)
uchar dushuju()
{
           uchar i,dat,m;
           for(i=8;i>0;i--)
           {
                    ds=0;
                    delayus(1);
                    ds=1;
                    delayus(2);
                    m=ds;
                    dat=(m<<7)|(dat>>1);   //读出的数据最低位在最前面,刚好一个字节在dat里
                    delayus(8);
              }
       return dat;
}
/*********************************************************/
//DS18B20写命令子程序(写一字节)
void xiemingling(uint shuju)
{
       uint i;
       bit m;
       for(i=8;i>0;i--)
       {
                m=shuju&0x01;
                shuju=shuju>>1;
                if(m)                           //写1
                {
                         ds=0;
                         delayus(2);
                         ds=1;
                         delayus(8);
                }
                else                     //写0
                {
                         ds=0;
                         delayus(8);
                         ds=1;
                         delayus(2);
                }
       }
}
/*********************************************************/  
//DS18B20开始获取温度并转换
void zhuanhuan()
{
           ds18b20init();
           delayms(1);
           xiemingling(0xcc);        //写跳过读ROM指令
           xiemingling(0x44);       //写温度转换命令
}
/*********************************************************/
//DS18B20读寄存器中存储的温度数据
int duwendu()
{
           uint a,b;
           ds18b20init();
           delayms(1);
           xiemingling(0xcc);                     //跳过ROM,忽略64位ROM地址
           xiemingling(0xbe);                    //读内部RAM中的9字节的温度数据
           a=dushuju();                            //读低8位
           b=dushuju();                           //读高8位
           b=b<<8;                                //高8位左移8位
           temp=b|a;                             // 高8位和低8位组合为1个字
           temp=temp*0.0625;              //温度在寄存器中位12位,分辨率为0.0625度
           return temp;
}
/*********************************************************/
//显示子程序
void xianshi(unsigned long num)
{
           unsigned char bai,shi,ge;
           bai=num/100;                        //分离三位距离数据
           shi=num%100/10;                  //
           ge=num%10;                         //
           duan=1;                                //显示第一位
           P0=shuzu[bai]|0x80;
           duan=0;
           P0=0xfe;
           wei=1;
           wei=0;
           delayms(1);
           duan=1;                                  //显示第二位
           P0=shuzu[shi];
           duan=0;
            P0=0xfd;
           wei=1;
            wei=0;
           delayms(1);
           duan=1;                                 //显示第三位
           P0=shuzu[ge];
           duan=0;
           P0=0xfb;
           wei=1;
           wei=0;
           delayms(1);
}
/*********************************************************/
//计算距离子程序
void Conut()
{
        float a;
        time=TH0*256+TL0;             //这是最后计算到的时间,但应该再乘以12/11.092
                                                   //时间应该是time*12/11.0592
        TH0=0;                                   //定时器0的初始值位0           
        TL0=0;
        a=(331.5+0.607*temp);    //声速与温度的函数关系:声速=331.5+0.607*温度
       S=(time*a/200)/100;        //算出来是cm     

        if (S>=500)                     //最大距离为5m,即500cm
        S=888;
        if (flag==1)                     //判断是否溢出
        {
                S=888;
                flag=0;
                TH0=0;
                TL0=0;
       }
}
/********************************************************/
//初始化定时器0和定时器1
void T0_init()
{
          TMOD=0x11;   
           TH0=0;            
           TL0=0;         
           TH1=0xf8;        //定时器1赋初值,应该是2ms
           TL1=0x30;
           ET0=1;            
           ET1=1;     
           TR1=1;      
           EA=1;
}
void  main(   )
{  
           unsigned int i;
           T0_init();   
           while(1)
           {
                    duwendu();                               //获取温度后计算相应声速,从而计算距离
                     while(!echo);                            //当echo为0时等待
                     TR0=1;                                    //开启定时器0
                     while(echo);                            //当echo为1计数并等待
                     TR0=0;                                   //关闭定时器0
                     Conut();                                  //计算距离
                     for(i=150;i>0;i--)              
                     {
                              xianshi(S);                      //数码管显示
                     }
           }
}
/********************************************************/
void zd0() interrupt 1   
{
          flag=1;                                            //中断溢出标志
}                       
/********************************************************/
void  zd3()  interrupt 3   
{                                
         TH1=0xf8;                    
         TL1=0x30;
         timer++;
         if(timer>=100)                                //每隔800ms启动超声波模块
         {
               timer=0;
               xianshi(S);
               trig=1;            
               delayms(30);                             //一次超声波信号时长30ms
               trig=0;
         }
}
/*********************************************************/

不错哦 拿下啦

鼓励分享,好好学习天天向上

小编好人,东西也好,学习了。

不知道小编测试过这个程序吗?能不能检测啊?

亲自测试过一切正常。

支持实实在在在做事情的人。

好好学习,天天向上

很好。

支持实实在在在做事情的人。

不错,继续========

貌似开头定义的注释,echo是接收端, trig是发射端(控制端),是不是大神写反了,还是我弄错了?

小编这个程序是否写对,要注明哦!

谢谢小编分享

谢谢小编分享

很详细,谢谢小编分享,辛苦了

很详细,谢谢小编分享,辛苦了

很详细,谢谢小编分享,辛苦了

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top