码迷,mamicode.com
首页 > 其他好文 > 详细

超声测距

时间:2018-01-20 20:31:56      阅读:214      评论:0      收藏:0      [点我收藏+]

标签:当前时间   相加   注意   主循环   .com   速度   lap   ima   脉冲   

超声测距模块 HC-SR04P。工作电压3-5V,有效距离2-400cm,分辨率1mm。注意型号末尾的“P”:有另一个外观、接口、工作方式一样的型号 HC-SR04,但工作电压为5V。我这个模块 PCB正面印刷的是HC-SR04,反面印刷 HC-SR04P:

技术分享图片

有4个引脚,VCC/GND供电,TRIG触发测距,ECHO接收测量结果。向TRIG给一个10us以上(规格书建议40-50us)的正脉冲触发信号,模块开始工作,发射超声波并接收回声。从发射到接收到回声的时间,以回响电平的形式从ECHO输出;电平持续时间等于声波往返模块到障碍物的时间:

技术分享图片

 温下,声音在空气中的传播速度约343m/s = 3.43mm/10us = .8575mm/2.5us。初步想法是,启动一个Timer作为时间基,计数频率 2.5us = 400kHz,以满足10us触发信号延时和1mm测量分辨率的需求。接口方式,触发信号用GPIO output,回响信号用GPIO外部中断。如下图,回响信号接PC7(Arduino兼容Pin D9),其EXTI line编号为7:

技术分享图片

使用基本Timer TIM6,时钟源为PCLK1 x 2=72MHz。设PSC=179,得计数频率 CK_CNT = 72MHz / (1+179) = 400kHz。设 ARR = 63999,则 UEV 频率为 400kHz /(1+63999) = 6.25Hz = 160ms。

计时及有关工具函数实现如下。全局变量 _App_timestamp 记录时间戳,在TIM6 UEV 中断回调函数中更新,因此其精度为160ms。获取当前时间戳时,将_App_timestamp 与 TIM6 CNT寄存器值相加,可达到 2.5us 精度:

typedef struct {
    uint32_t milli;
    uint16_t micro;
} _App_Timestamp;

volatile _App_Timestamp _App_timestamp = { 0, 0 };

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
    if (&htim6 == htim) {
        _App_timestamp.milli += 160; // 160 ms/tick
    }
}

#define _App_GetDuration(from, to)  (                   1000 * ((to).milli - (from).milli)            + (to).micro - (from).micro                   )

void _App_GetTimestamp(_App_Timestamp *ts) {
    *ts = _App_timestamp;
    uint32_t micro = 5 * htim6.Instance->CNT / 2;
    ts->milli += (micro / 1000);
    ts->micro += (micro % 1000);
}

void _App_DelayMicro(uint32_t micro) {
    _App_Timestamp t1, t2;
    _App_GetTimestamp(&t1);
    for (;;) {
        _App_GetTimestamp(&t2);
        if (_App_GetDuration(t1, t2) >= micro) {
            break;
        }
    }
}

ECHO Pin启用外部中断,在中断回调函数内记录上升沿和下降沿的时间戳:

typedef struct {
    uint8_t state;
    uint32_t duration; // in us
    _App_Timestamp _risingTs;
} _App_Measure;

volatile _App_Measure _App_measure = { 0 };

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
    if (D9_ECHO_Pin == GPIO_Pin) {
        if (GPIO_PIN_SET == HAL_GPIO_ReadPin(D9_ECHO_GPIO_Port, D9_ECHO_Pin)) {
            // Rising edge
            _App_Timestamp now;
            _App_GetTimestamp(&now);
            _App_measure._risingTs = now;
            _App_measure.state = 0;
        } else {
            // Falling edge
            _App_Timestamp now;
            _App_GetTimestamp(&now);
            _App_measure.duration = _App_GetDuration(_App_measure._risingTs,
                    now);
            _App_measure.state = 1;
        }
    }
}

 

主循环如下。首先发送TRIG脉冲,时间设为20us。距离的计算注意将声波往返距离除以 2 才是到障碍物的距离:

void App_Loop() {

    _App_Trig(20);

    HAL_Delay(500);

    if (_App_measure.state) {
        uint32_t dur = _App_measure.duration;
        uint32_t dist = (uint32_t) (.343f * dur / 2);

        if (dist > 25 && dist < 5000) {
            char msg[80];
            sprintf(msg, "%d mm\n", (int) dist);
            HAL_UART_Transmit(&huart2, (uint8_t *) msg, strlen(msg),
            HAL_MAX_DELAY);
        }
    }
}

void _App_Trig(uint32_t micro) {
    HAL_GPIO_WritePin(D8_TRIG_GPIO_Port, D8_TRIG_Pin, GPIO_PIN_SET);
    _App_DelayMicro(micro);
    HAL_GPIO_WritePin(D8_TRIG_GPIO_Port, D8_TRIG_Pin, GPIO_PIN_RESET);
}

测得的距离从串口 USART2 输出,单位为mm:

技术分享图片  

超声测距

标签:当前时间   相加   注意   主循环   .com   速度   lap   ima   脉冲   

原文地址:https://www.cnblogs.com/vinccc/p/8318586.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!