一、HC-SR04工作原理
1)采用IO触发测距,给至少10us的高电平信号。
2)模块自动发送8个40KHz的方波,自动检测是否有信号返回。
3)有信号返回,通过IO输出一高电平,高电平持续时间就是超声波从发射到返回的时间声波从发
射到返回的时间。
4)HC-SR04超声波测距模块提供2cm~400cm的测距功能,精度达3mm。
二、实物介绍
以下图片截取自深圳市捷深科技有限公司的《HC-SR04超声波测距模块说明书》:
VCC 3.3-5V供电(推荐5V供电)
GND 接地
Trig 外部触发信号输入,输入一个高于10μs的高电平即可触发模块测距
Echo 回响信号输出,测距结束时此管脚输出一个低电平,电平宽度反映超声波往返时间之和
三、工作说明
1、触发信号Trig直接通过IO输出和延时给一个大于10us的高电平即可触发。
2、Echo引脚需要接收并记录高电平的持续时间。
3、在发送触发信号后,Echo响应后(上升沿)触发外部中断,开启定时器计时直到Echo变为低电
平,关闭定时器记录下计时时间。
4、实际应用,如果需要精确距离值,必需要考虑温度影响,做温度补偿。
distance = time * 0.017
距离=T*C/2(C 为声速)
声速温度公式:c=(330.45+0.61t/℃)m/s-1 (其中330.45是在0℃)
0℃声速:330.45m/s 20℃声速:342. 62m/s 40℃声速:354.85M/S
四、标准库工作代码
我一般使用标准库较少,使用代码时请注意检查
使用OLED显示,OLED使用可以看:
uint32_t distance;
while(1)
{
distance = 0;
for(int i=0;i<10;++i)
{ //每次取10次测距数据,取平均值减少误差
GPIO_SetBits(GPIOA,GPIO_Pin_6);
Delay_us(15); //需要提供至少10us的高电平
GPIO_ResetBits(GPIOA,GPIO_Pin_6);
Delay_ms(70); //每个周期至少需要等待60ms
distance+=(times/5.8); //获取单位为mm的距离
}
distance/=10;
OLED_ShowNum(2,1,distance,4); //使用OLED显示
}
//定时器中断函数
//72MHz/72/100=1000,每秒定时器计数1000个,因此每个计数为100us
void TIM2_IRQHandler(void)
{
if(SET==TIM_GetITStatus(TIM2,TIM_FLAG_Update))
{
number++; //每次中断将次数++
TIM_ClearITPendingBit(TIM2,TIM_FLAG_Update);
}
}
//外部中断函数,利用外部中断检测高低电平变化来控制定时器开关
void EXTI9_5_IRQHandler(void)
{
if(SET==EXTI_GetITStatus(EXTI_Line7))
{
if(flag==0)
{
//上升沿即回响电平开始,打开计数器
number=0;flag=1;
TIM_SetCounter(TIM2,0);
TIM_Cmd(TIM2,ENABLE);
}
else
{
//下降沿即回响电平结束,统计高电平持续时长
TIM_Cmd(TIM2,DISABLE);
flag=0;
times=number*100+TIM_GetCounter(TIM2); //得到回响的高电平持续的us
}
EXTI_ClearITPendingBit(EXTI_Line7);
}
}
五(1)、HAL--CubeMX配置
GPIO配置(Trig端口):设置PA1为触发端(可更改为其他GPIO口)。单击芯片的PA1引脚会跳
出选择项,选择GPIO_Output,即为GPIO输出。
定时器配置(Echo端口):为方便计算定时器的分频系数和定时周期,将APB1设置为50MHz。
先设置TIM2的通道1位直接模式输入捕获,在参数设置中设置预分频为71,通过计算分频器输出的
时钟信号频率为1000kHz,通过换算得到1us,极性为上升沿触发。设置完成后自动引出PA0引
脚,即为接收端引脚Echo,使能NVIC中断。
USART1配置:串口输出显示结果,设置为异步模式,波特率为115200Bits/s,
RX--PA10//TX--PA9
五(2)、HAL库工作代码
1、HCSR04.h
#ifndef __HCSR04_H
#define __HCSR04_H
#include "main.h"
//#include "tim.h"
#include "stdio.h"
#define TRIG_H HAL_GPIO_WritePin(Trig_GPIO_Port,Trig_Pin,GPIO_PIN_SET)
#define TRIG_L HAL_GPIO_WritePin(Trig_GPIO_Port,Trig_Pin,GPIO_PIN_RESET)
void delay_us(uint32_t us);
void HCSR04_GetData(void);
#endif
2、HCSR04.c
#include "HCSR04.h"
float distance; //测量距离
uint32_t Buf[3] = {0}; //存放定时器计数值的数组
uint8_t Cnt = 0; //状态标志位
uint32_t high_time; //超声波模块返回的高电平时间
//读取距离
void HCSR04_GetData(void)
{
switch(Cnt)
{
case 0:
TRIG_H; //发送信号
delay_us(30);
TRIG_L;
Cnt++; //标志位为1
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1); //开启TIM2
//启动输入捕获或者:__HAL_TIM_ENABLE(&htim5);
break;
case 3:
high_time = Buf[1]- Buf[0]; //计算高电平时间
printf("\r\n----高电平时间-%d-us----\r\n",high_time); //串口打印时间
distance=(high_time*0.034)/2; //计算距离单位cm
printf("\r\n-检测距离为-%.2f-cm-\r\n",distance); //串口打印距离
Cnt = 0; //清空标志位
TIM2->CNT=0; //清空计时器计数
break;
}
}
//中断回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(TIM2 == htim->Instance)// 判断触发的中断的定时器为TIM2
{
switch(Cnt)
{
case 1:
//获取当前的捕获值
Buf[0] = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);
//设置为下降沿捕获!!!
__HAL_TIM_SET_CAPTUREPOLARITY(&htim2,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);
Cnt++;
break;
case 2:
//获取当前的捕获值
Buf[1] = HAL_TIM_ReadCapturedValue(&htim2,TIM_CHANNEL_1);
HAL_TIM_IC_Stop_IT(&htim2,TIM_CHANNEL_1);
//停止捕获或者: __HAL_TIM_DISABLE(&htim5);
Cnt++; //此时标志位为3
break;
}
}
}