硬件环境
STM32F407探索板(其他开发板皆可以)
HC-SR04超声波模块
软件环境
KEIL5
CUBEMX
串口调试助手(sscom或其他)
实验目标
- 了解HC-SR04超声波模块工作原理
- 实现超声波模块测距
1、超声波模块介绍
1.1 超声波测距原理及系统组成
超声波测距是借助于超声脉冲回波渡越时间法来实现的。设超声波脉冲由传感器发出到接收所经历的时间为t,超声波在空气中的传播速度为c,则从传感器到目标物体的距离D可用下式求出:D = ct/2,图 2是相应的系统框图。
基本原理:经发射器发射出长约 6mm,频率为 40KHZ 的超声波信号。此信号被物 体反射回来由接收头接收,接收头实质上是一种压电效应的换能器。它接收到信号后产 生 mV 级的微弱电压信号。
1.2 HC-SR04模块原理
HC-SR04超声波测距模块可提供2cm-400cm的非接触式距离感测功能,测 距精度可达高到3mm,模块包括超声波发射器、接收器与控制电路。
基本工作原理:(1)采用 IO 口 TRIG 触发测距,给最少 10us 的高电平信呈。(2)模块自动发送 8 个 40khz 的方波,自动检测是否有信号返回;(3)有信号返回,通过 IO 口 ECHO 输出一个高电平,高电平持续的时间就是超声 波从发射到返回的时间。测试距离=(高电平时间*声速(340M/S))/2,下面是实物图。
如上图接线,VCC供5V电源,GND为地线,TRIG触发控制信号输入,ECHO 回响信号输出等四个接口端。
1.3 超声波时序图
以上时序图表明你只需要提供一个10uS以上脉冲触发信号,该模块内部将发出8个40kHz周期电平并检测回波。一旦检测到有回波信号则输出回响信号。回响信号的脉冲宽度与所测的距离成正比。由此通过发射信号到收到的回响信号时间间隔可以计算得到距离。公式:uS/58=厘米或者uS/148=英寸;或是:距离=高电平时间*声速(340M/S)/2;建议测量周期为60ms以上,以防止发射信号对回响信号的影响。
注:1、此模块不宜带电连接,若要带电连接,则先让模块的GND端先连接,否则会影响 模块的正常工作。
2、测距时,被测物体的面积不少于0.5平方米且平面尽量要求平整,否则影响测量的 结果。
1.4 电气参数
电气参数 | HC-SR04模块 |
---|---|
工作电压 | DC5V |
工作电流 | 15mA |
工作频率 | 40KHZ |
最远射程 | 4M |
最近射程 | 2CM |
测量角度 | 15度 |
输入触发信号 | 10uS 的 TTL 脉冲 |
输出回响信号 | 输出 TTL 电平信号,与射程成比例 |
规格尺寸 | 45*20*15mm |
2、软件实现
对程设计最重要的就是模块的时序图了,一切皆时序,看明白了时序,那么驱动自然也就不难写了,分析上面时序,首先模块需要触发信号,触发信号是不低于10us的TTL电平,也是就需要控制IO输出不低于10us的高电平脉冲,模块接收到此脉冲信号后,内部会输出8个40KHZ脉冲,然后模块会输出与检测距离相应时间的高电平作为回响信号,作为我们检测的依据。
2.1 硬件连接
单片机 | HC-SR04模块 |
---|---|
5V | VCC |
Trig | PB14 |
Echo | PB15 |
GND | GND |
2.2 cubemx配置
结合上面我们的分析,需要用到us延时,定时器计算超声波返回高电平时间,us延时在上一篇文章做了很详细的介绍,小伙伴们可以动动可爱的小手哈,上篇文章链接在这:Embeded。
时钟配置上篇文章也有介绍到,这里也贴出来,也可以使用内部RC高速时钟,本次主要介绍使用外部高速时钟,上图:
我板子上焊接的是8M的晶体,如果小伙伴们的板子上不是8M,根据自己的晶振频率配置即可,左侧圈1中,可以根据自己的晶体频率,输入相应的频率,经过分频、倍频后,系统时钟频率设置为最大,168MHZ,APB1的时钟频率为 84MHZ,也是后面用到的 TIM2 挂载的时钟源的频率。
TIM2 基础配置,这个就比较简单了,分频系数 83,计数单位为 84MHZ/84 = 1uS,向上计数方式,周期 65535,由于没有使用到中断,不需要开启中断。
配置串口1作为我们调试输出串口,配置如下图
接下来,配置超声波模块用到的IO,PB14作为Trig引脚,配置为输出模式,PB15作为Echo引脚,配置为输入模式
此时IO的状态有个默认值,可能不是我们上电初始化希望保持的状态,比如Trig引脚是需要输出不低于10us的高电平脉冲,那么Trig初始引脚配置为低电平使我们希望的,为实现这个目的,需要再配置一下
至此,我们的cubemx配置就完成了,下面进行软件逻辑的实现。
2.3 软件代码实现
首先将我们用到的两个IO进行宏定义,方便调用,代码如下:
代码语言:javascript复制#define HCSR_TRIG_HIGH() HAL_GPIO_WritePin(HC_SR04_Trig_GPIO_Port,HC_SR04_Trig_Pin,GPIO_PIN_SET)
#define HCSR_TRIG_LOW() HAL_GPIO_WritePin(HC_SR04_Trig_GPIO_Port,HC_SR04_Trig_Pin,GPIO_PIN_RESET)
#define HCSR_ECHO() HAL_GPIO_ReadPin(HC_SR04_ECHO_GPIO_Port,HC_SR04_ECHO_Pin)
根据上面的协议,先实现触发脉冲信号,不低于10us的TTL高电平脉冲信号,我延时了20us,也是上一张测试过的20us延时函数,如果小伙伴不知道怎么实现us延时,麻烦翻看上一张哈,代码如下,顺便用逻辑分析仪截了一下TRIG引脚信号,还是熟悉的20us:
代码语言:javascript复制void HCSR04StartTrigStart(void)
{
HCSR_TRIG_HIGH();
for_delay_us(20);
HCSR_TRIG_LOW();
}
接下来是TIM2的配置函数,代码如下:
代码语言:javascript复制/* TIM2 init function */
void MX_TIM2_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 84-1;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 65535;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
}
定时器开启与关闭函数体如下面,由于没用中断,屏蔽了定时器中断部分:
代码语言:javascript复制//mode=1-->open timer
//mode=0-->close timer
void HCSR04_TimerFunc(uint8_t mode)
{
if(mode)
{
__HAL_TIM_SetCounter(&htim2,0);
HAL_TIM_Base_Start(&htim2);
//HAL_TIM_Base_Start_IT(&htim2);
msHcCount = 0;
}
else
{
HAL_TIM_Base_Stop(&htim2);
//HAL_TIM_Base_Stop_IT(&htim2);
}
}
接下来就是我们的核心时间采集及距离换算部分了,代码如下,设计两个函数,一个是单次获取距离,另一个是对采集结果做了均值滤波处理,减少误差:
代码语言:javascript复制//单次获取测量距离
float HCSR04_Get_Distant(void)
{
HCSR04StartTrigStart();
while(!HCSR_ECHO());
HCSR04_TimerFunc(1);//start timer
while(HCSR_ECHO());
HCSR04_TimerFunc(0);//stop timer
return (__HAL_TIM_GetCounter(&htim2))/58.0;
}
//均值滤波减小测量误差
float Distance(uint8_t cnt)
{
float sum = 0;
for(int i =0;i<cnt;i )
{
sum =HCSR04_Get_Distant();
}
return sum/cnt;
}
主函数部分没什么,每隔100ms读取一次,并通过串口打印出来:
代码语言:javascript复制 distant = Distance(5);
t ;
if(t%5==0)
{
t=0;
printf("rnrn---------------start--------------------rnrn");
printf("The Mesure Distant is:%.2f cmrn",distant);
printf("rnrn----------------stop--------------------rnrn");
HAL_GPIO_TogglePin(led_run_GPIO_Port,led_run_Pin);
}
HAL_Delay(100);
最终测试效果,手机支架高度,大概16CM,测量效果还是可以的:
本次要分享的内容就要结束啦,希望对能帮助到正在想使用HC-SR04超声波模块却不知道如何下手的小伙伴。
如果你觉得对自己有帮助的话,给个赞,点个关注,点个在看,感谢前进的道路上有你的陪伴!图片欢迎大家关注Embeded小飞哥,让我快点遇到优秀的你,然后一起变得更加优秀,加油!!!小飞哥微信号:w974762670,加好友进群一起交流呀!