1、工作原理
常用的HC-SR04模块如下所示:
引脚说明:
引脚 | 说明 |
---|---|
VCC | 电源,常用5v |
Trig | 控制端 |
Echo | 接收端 |
GND | 地 |
使用说明:
控制端发送一个10us的高电平脉冲,之后再接收口等待高电平输出,一有高电平输出就开始计时,直到低电平到来就可以结束计时,速度X时间,就是我们测量到的距离了。
时序图说明
其他说明:
- 调节测距长短
图中标志的电阻可以调节最大探测距离。R3电阻为392,探测距离最大4.5M左右,探测角度小于15度;R3电阻为472,探测距离最大7M左右,探测角度小于30度;出厂默认392,即最大探测距离4.5M左右。R3电阻大,接收部分增益高,检测距离大,但检测角度会相应变大,容易检测到前方旁边的物体。 - 提高测距有效性:
测距时,被测物体的面积不少于0.5平方米且要尽量平整。否则会影响测试结果。
2、读取数据方式
说白了就是发脉冲然后计数,所以关键问题在于计数的方式上,可以选的方式如下:
- 延时函数
- 定时器计数
- 输入捕获
这里用延时函数的方法肯定是会打断整个系统的进程的,虽然时间很短,但是也会有一定影响,使用定时器输入捕获应该是要配合中断来使用,缺点是要废掉一个定时器,采用输入捕获应该是最高精度的方法了,但是同样的也要废掉一个定时器!!!
关于定时器的使用可以看我之前的一篇文章,较全面的总结了定时器的使用方法:stm32外设总结-定时器使用
3、驱动记录
这里还是采用输入捕获的方法来测试,其他两个方法都比较直白,只是编写下逻辑函数就行的,就不做演示了
用的就是PWM输入的方式
CH1上升沿,CH2下降沿
打开中断
配置控制引脚
之后就可以生成代码了
编写测量函数
源代码:
#include "HC-SR04.h"
#include "tim.h"
#define fac_us 72 //时钟频率,单位MHZ
/*微秒级延时函数*/
void delay_us(uint32_t nus)
{
uint32_t ticks;
uint32_t told,tnow,tcnt=0;
uint32_t reload=SysTick->LOAD; //LOAD的值
ticks=nus*fac_us; //需要的节拍数
told=SysTick->VAL; //刚进入时的计数器值
while(1)
{
tnow=SysTick->VAL;
if(tnow!=told)
{
if(tnow<told)tcnt+=told-tnow; //这里注意一下SYSTICK是一个递减的计数器就可以了.
else tcnt+=reload-tnow+told;
told=tnow;
if(tcnt>=ticks)break; //时间超过/等于要延迟的时间,则退出.
}
}
}
static void HC_SR04_Start()
{
HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_SET);
delay_us(10);
HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_RESET);
}
static uint16_t HCSR04_get_measure()
{
HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_2);
measure_flag = 1;
HC_SR04_Start();
while(measure_flag);
return pulse_time;
}
float HCSR04_get_distance_cm()
{
float distance_cm;
distance_cm = HCSR04_get_measure() / 58.0f;
return distance_cm;
}
中断的数据处理函数
源代码
float dis = 0;
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim == &htim1)
{
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
IC_RisingEdge = __HAL_TIM_GET_COMPARE(&htim1, TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_1);
}
else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
pulse_time = __HAL_TIM_GET_COMPARE(&htim1, TIM_CHANNEL_2) - IC_RisingEdge;
measure_flag = 0;
HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_2);
}
}
}
之后读数据就OK了
将程序下载到开发板,调试查看数据效果如下,基本OK 的