一、基本介绍
HC-SR04超声波测距模块可提供 2cm-400cm的非接触式距离感测功能,测距精度可达高到 3mm;模块包括超声波发射器、接收器与控制电路。(模块手册)
电气参数
电路图
两个压电陶瓷超声传感器,一个用于发出超声波信号,一个用于接收反射回来的超声波信号。由于发出信号和接收信号都比较微弱,所以需要通过外围信号放大器提高发出信号的功率,和将反射回来信号进行放大,以能更稳定地将信号传输给单片机。
二、工作原理
- 采用IO口TRIG触发测距,给最少10us的高电平信呈;
- 模块自动发送8个40khz的方波,自动检测是否有信号返回;
- 有信号返回,通过IO口ECHO输出一个高电平,高电平持续的时间就是超声波从发射到返回的时间。
测试距离=(高电平时间*声速(340M/S))/2;
时序图
一点小Tips
1、Echo引脚0—>1启动定时器计时;1—>0结束定时器计时。
2、公式:uS/58=厘米或者uS/148=英寸;或距离=高电平时间*声速(340M/S)/2;
3、建议测量周期为60ms 以上,以防止发射信号对回响信号的影响。
三、代码段
hcsr04.c
#include "hcsr04.h"
extern char value[]; //存储转换后的值
extern int Length;
int Val=0;
void hcsr04Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB2PeriphClockCmd(HCSR04_CLK,ENABLE);
RCC_APB1PeriphClockCmd(HCSR04_TIM_CLK,ENABLE);
GPIO_InitStructure.GPIO_Pin=HCSR04_TRIG;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //推挽输出
GPIO_Init(HCSR04_PORT,&GPIO_InitStructure);
GPIO_ResetBits(HCSR04_PORT, HCSR04_TRIG);
GPIO_InitStructure.GPIO_Pin=HCSR04_ECHO;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(HCSR04_PORT, &GPIO_InitStructure);
TIM_DeInit(TIM4);
TIM_TimeBaseStructure.TIM_Period = 999;
TIM_TimeBaseStructure.TIM_Prescaler =71;
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;//不分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //初始化
TIM_ClearFlag(TIM4, TIM_FLAG_Update); //清除更新中断,免得一打开中断立即产生中断
TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE); //打开定时器更新中断
TIM_Cmd(TIM4,DISABLE);
}
float UltraSonic_valuetance(void) //测量超声波距离
{
float length=0;
GPIO_SetBits(HCSR04_PORT, HCSR04_TRIG); //拉高电平信号
DelayUs(20); //高电平至少10uS
GPIO_ResetBits(HCSR04_PORT, HCSR04_TRIG); //拉低电平信号
/*等待回响信号*/
while(GPIO_ReadInputDataBit(HCSR04_PORT,HCSR04_ECHO)==0); //接收到信号ECHO为高电平
TIM_Cmd(TIM4,ENABLE); //使能TIM4定时器
while(GPIO_ReadInputDataBit(HCSR04_PORT,HCSR04_ECHO)==1); //直到回响信号消失
TIM_Cmd(TIM4,DISABLE); //失能TIM4定时器
length=TIM_GetCounter(TIM4)/58;
if(length<=0){
length=0;
}
TIM_SetCounter(TIM4,0); //取出TIM4的counter寄存器里的值
DelayMs(200);
return length;
}
hcsr04.h
#ifndef __HCSR04_H
#define __HCSR04_H
#include "stm32f10x.h"
#include "delay.h"
#define HCSR04_PORT GPIOB
#define HCSR04_CLK RCC_APB2Periph_GPIOB
#define HCSR04_TIM_CLK RCC_APB1Periph_TIM4
#define HCSR04_TRIG GPIO_Pin_7
#define HCSR04_ECHO GPIO_Pin_6
void hcsr04Init(void);
float UltraSonic_valuetance(void);
#endif /*__HCSR04_H */
还有TIM4的中断
void TIM4_IRQHandler(void)
{
if(TIM_GetITStatus(TIM4,TIM_IT_Update)!=RESET)
{
TIM_ClearITPendingBit(TIM4,TIM_IT_Update);
}
}
余震处理
以上代码确实可以测到距离,但是总有时数据会跟实际偏差很大。这是因为超声波测量一次的时间很短,测量一次有可能出错。
关于余震原因
- 探头的余震。发射头发射完还会震一会,这种震动信号也会向外传播。如果发射完立刻切换为接收状态,检测会被这余震波干扰到。
- 壳体的余震。发射头发射完壳体余震会传导到接收头,造成检测时的干扰。
- 电路串扰。超声波发射时的瞬间电流很大,会对电源有一定影响,并干扰接收电路。
我们稍微修改一下代码,通过多测几次求平均值来进行消抖。
float UltraSonic_valuetance(void) //测量超声波距离
{
float length=0,sum=0;
int i=0;uint16_t time;
while(i!=5){
GPIO_SetBits(HCSR04_PORT, HCSR04_TRIG); //拉高电平信号
DelayUs(20); //高电平至少10uS
GPIO_ResetBits(HCSR04_PORT, HCSR04_TRIG); //拉低电平信号
/*等待回响信号*/
while(GPIO_ReadInputDataBit(HCSR04_PORT,HCSR04_ECHO)==0); //接收到信号ECHO为高电平
TIM_Cmd(TIM4,ENABLE); //使能TIM4定时器
i+=1;
while(GPIO_ReadInputDataBit(HCSR04_PORT,HCSR04_ECHO)==1); //直到回响信号消失
TIM_Cmd(TIM4,DISABLE); //失能TIM4定时器
time=TIM_GetCounter(TIM4);
length=(time+count*1000)/58.0;
if(length<=0){
length=0;
}
sum+=length;
DelayMs(10);
TIM4->CNT=0;
count=0;
}
length=sum/5.0;
return length;
}
关于测量问题应该是本人代码缺陷。如能更好的实现还请多多指教。
参考自:
1、STM32与HC-SR04超声波测距
2、基于STM32的超声波HC-SR04历程