基于STM32的HC-SR04超声波测距模块实验

2021-08-16 16:07:17 浏览数 (1)

硬件环境

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,加好友进群一起交流呀!

io

0 人点赞