• 关于HC04超声波模块测距的思考(51版)


    之前写过一篇HC04的使用文章,当时是使用stm32来实现的,原文链接

    后来又多次使用51来驱动这个模块,有时候有测距需要,使用了几次,总是感觉我上次那个程序不是很好,

    所以这次对它进行了改进。虽然上一次也使用了多次测量取平均值,但是内有排除中间会有错误数据的情况。

    之前的程序是这样的(测距部分) :

    u32 t = 0;  
    int i = 0;  
    float lengthTemp = 0;  
    float sum = 0;  
    while(i!=5)  
    {  
    TRIG_Send = 1;      //发送口高电平输出  
    Delay_Us(20);  
    TRIG_Send = 0;  
    while(ECHO_Reci == 0);      //等待接收口高电平输出  
        OpenTimerForHc();        //打开定时器  
        i = i + 1;  
        while(ECHO_Reci == 1);  
        CloseTimerForHc();        //关闭定时器  
        t = GetEchoTimer();        //获取时间,分辨率为1US  
        lengthTemp = ((float)t/58.0);//cm  
        sum = lengthTemp + sum ;  
    }   
    lengthTemp = sum/5.0;  
    return lengthTemp;  

    就是当超出测量范围的时候(3.4米),数据肯定是不准确的。还有就是当因为某些原因模块没有接收到返回的超声波,也会导致错误的数据,

    就算是取平均值,如果中间有一个很大的数据的话,计算的结果也是不精确的。

    利用51再次使用这个模块的程序如下:

    /* 
    获取当前距离 
    2018.3.5  误差在1cm以内  
    */  
    float get_distence()  
    {  
        unsigned long int time_buf = 0;     //总耗时  
        float distence = 0;     //计算一次距离  
        float sum = 0;          //多次计算的总距离  
        uchar i = 0;  
      
        while(i < NUM)  
        {  
            time_flag = 0;  //先清除标志  
            sr04_start();   //开始测距  
            while(!ECHO);   //等待发出40khz脉冲,触发信号之后,echo会变成高电平  
            time_0_start(); //当把trig拉高10us之后,模块即开始发出8个40khz的脉冲,与此同时,echo变为高电平时,打开定时器。  
            while(ECHO);    //等待回响信号,收到回响信号,echo会变低电平  
            TR0 = 0;        //关闭定时器  
      
            if(time_flag != 0)  //超出测量范围  
                continue;       //不进行计算,放弃这次测量,从新测量  
      
            else                //time_flag = 0,没有超出测量范围  
            {  
                time_buf = (TH0 * 256) + TL0;  
                distence = time_buf * 0.0168;//(单位:cm)虽然声速340m/s,发现使用0.0168更精确,可能和温度有关  
                sum+= distence;  
                i++;  
            }       
        }     
        return (sum/NUM) ;  //取NUM次平均值  
    }   

    其实就是在进行计算前先判断一下定时器是否产生中断,如果产生中断,就放弃本次数据,再次测量。这样测出的数据算是很精确了,唯一的误差就是声速的计算上面,导致会有1-2cm的误差。

    16位的定时器,12M的晶振,定时器模式1,从0开始计数,最大到65535,一次溢出需要的时间是0.065s,声速为340m/s。那么溢出时的距离为22.1m,已经远远超过了超声波模块的测量范围(0-5m),所以只要产生一次溢出,就可以认为是超出测量范围.。

    所以在定时器中断函数中 :

    void TIME0() interrupt 1  
    {  
    //  TF0 = 0;       //模式1硬件自动清零  
        TH0 = 0;  
        TL0 = 0;  
        time_flag++;  
    }  

    其中对一些操作进行了简单的封装。开始测距函数,就是按照要求拉高TRIG引脚

    /*start*/  
    void  sr04_start()  
    {  
         TRIG = 1;    
         delay_10us(5); //拉高50us  
         TRIG = 0;  
    }  

    还有就是定时器开始函数,在这个函数里面需要把计数清零:

    /*开启定时器0,打开之前先清除之前的计数,不然会累计计数*/  
    void time_0_start()  
    {     
        TH0 = 0;       //打开前计数清零  
        TL0 = 0;  
        TR0 = 1;       //打开定时器  
    }  

    然后就是模块的 初始化函数了,在初始化的时候其实就是对定时器的初始化,顺便把TRIG和ECHO引脚置0;

    void sr04_init()  
    {     
        TRIG = 0;  
        ECHO = 0;  
      
        TMOD |= 0X01;   //定时器0模式设置1  
        TH0 = 0;    //从0开始计数  
        TL0 = 0;  
        TR0 = 0;    //关闭定时器  
        EA = 1;     //开总中断  
        ET0 = 1;    //允许定时器0中断  
    }  

  • 相关阅读:
    SpringMVC学习笔记----常用注解
    python常用模块学习1
    python基础模块,包
    python-验证功能的装饰器示例
    python闭包及装饰器
    关于windows服务器配置
    python高阶函数
    python-生成器和迭代器
    linux--基础知识5
    python基础-文件操作的其他方法
  • 原文地址:https://www.cnblogs.com/qsyll0916/p/8524857.html
Copyright © 2020-2023  润新知