- 作者:老汪软件技巧
- 发表时间:2024-12-06 10:02
- 浏览量:
· 靠自媒体连续年入百万,靠自己买房买车。
我本科及硕士都是学机械,通过自学成功进入世界500强外企。我已经将自己的学习经验写成了一本电子书,超千人通过此书学习并转行成功。现在将这本电子书免费分享给大家,希望对你们有帮助:
电子书链接:
2. HC-SR04介绍
超声波传感器有很多的信号:HC-SR04、UC-025、UC-026、UC-015、US-100等等,它们之间大同小异,无非是工作参数有点不一样,像是工作的电压或温度、探测距离或精度有点差别,引脚是一样的,都是4个引脚(US-100 多一个 GND 引脚),引脚顺序和功能也是一样的。
大家在学习和工作中可以自行选择合适的型号,这里我为大家介绍最常见的 HC-SR04 这个型号。
2.1 HC-SR04型号介绍
现在市面上的 HC- SR04 有新版和旧版,我们介绍的是新版。新版性能比老版的精度更高,测距范围更远,可达6米,高于一般超声波测距模块。采用 CS-100A 超声波测距 SOC 芯片,高性能,工业级,宽电压,价格在4块钱左右。
2.2 HC-SR04工作参数及引脚介绍
HC-SR04 工作参数:
接线如下:
HC-SR04STM32备注
VCC
3.3/5V
外接直流电源
Trig
任意一个GPIO口
输入端
Echo
任意一个GPIO口
输出端
GND
GND
接地
3. HC-SR04工作原理3.1 原理简述
超声波测距的工作原理其实很简单,传感器发送超声波,超声波碰到障碍物反弹回来,被传感器接收到。芯片算出发送和接收的时间间隔,再利用公式:s = v × t,看下面示意图,所以实际距离 = 测量距离 / 2 = 速度 × 时间 / 2。
顺便一提,超声波在空气中的传播速度大概是 343m/s,传播速度受到环境条件的影响,如温度、湿度和气压等。
超声波模块上的两个超声波探头,一个是发送端,负责发送超声波;一个是接收端,负责接收超声波。
3.2 原理详述
接下来我们详细的介绍下超声波模块的工作时序,明白了时序以后才知道怎么写代码。
单片机给超声波模块发送大于 10us 的高电平的触发信号;超声波模块收到触发信号后 Trig 端发送 8个40kHz 的超声波脉冲;Echo 端由低电平转为高电平,同时开始发送超声波;超声波模块检测到返回信号,Echo 端由高电平转为低电平;Echo 端高电平宽度即为超声波传播时间。
如果觉得太生涩了,我给大家准备了趣味描述:
当测量距离超过 HC-SR04 的测量范围时,Echo 任会输出高电平,宽度约为66ms,后转为低电平。
4. 编程实战4.1 硬件接线
本教程使用的硬件如下:
HC-SR04STM32USB 转 TTL
VCC
3.3/5V
Trig
B6
Echo
B7
GND
A10
TX
A9
RX
GND
烧录的时候接线如下表,如果不会烧录的话可以看我之前的文章【STM32下载程序的五种方法:…
ST-Link V2STM32
SWCLK
SWCLK
SWDIO
SWDIO
GND
GND
3.3V
3V3
接好如下图:
4.2 初始化引脚
我们将 Trig 引脚设置为推挽式输出,Echo 引脚设置为浮空输入。为什么这样设置呢?大家可以对照下表的 GPIO 的八种工作模式看看。
模式名称性质特征
浮空输入
数字输入
可读取引脚电平,若引脚悬空,则电平不确定
上拉输入
数字输入
可读取引脚电平,内部连接上拉电阻,悬空时默认高电平
下拉输入
数字输入
可读取引脚电平,内部连接下拉电阻,悬空时默认低电平
模拟输入
模拟输入
GPIO 无效,引脚直接接入内部 ADC
开漏输出
数字输入
可输出引脚电平,高电平为高阻态,低电平接 VSS
推挽输出
数字输入
可输出引脚电平,高电平接 VDD,低电平接 VSS
复用开漏输出
数字输入
由片上外设控制,高电平为高阻态,低电平接VSS
复用推挽输出
数字输入
由片上外设控制,高电平接VDD,低电平接VSS
引脚初始化代码如下:
void HCSR04_GPIO_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
Trig_GPIO_CLK_ENABLE(); /* Trig引脚使能 */
Echo_GPIO_CLK_ENABLE(); /* Echo引脚使能 */
/* Trig低电平 */
HAL_GPIO_WritePin(Trig_GPIO_PORT, Trig_GPIO_PIN, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = Trig_GPIO_PIN; /* Trig引脚 */
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出 */
GPIO_InitStruct.Pull = GPIO_NOPULL; /* 浮空 */
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; /* 低速 */
HAL_GPIO_Init(Trig_GPIO_PORT, &GPIO_InitStruct); /* 初始化Trig引脚 */
GPIO_InitStruct.Pin = Echo_GPIO_PIN; /* Echo引脚 */
GPIO_InitStruct.Mode = GPIO_MODE_INPUT; /* 输入 */
GPIO_InitStruct.Pull = GPIO_NOPULL; /* 浮空 */
HAL_GPIO_Init(Echo_GPIO_PORT, &GPIO_InitStruct); /* 初始化Echo引脚 */
}
4.3 初始化定时器
需要初始化一个定时器,用于测量 Echo 高电平宽度,这里我们初始化了通用定时器2。
void TIM2_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = {0}; /* 定时器设置结构体 */
TIM_MasterConfigTypeDef sMasterConfig = {0};
htim2.Instance = TIM2; /* 通用定时器2 */
htim2.Init.Prescaler = 71; /* 预分频系数 */
htim2.Init.CounterMode = TIM_COUNTERMODE_UP; /* 递增计数模式 */
htim2.Init.Period = 65535; /* 自动装载值 */
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
HAL_TIM_Base_Init(&htim2);
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig);
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig);
}
4.4 测量距离
按照超声波的工作时序,
单片机给超声波模块发送大于 10us 的高电平的触发信号;Trig 的 8个40kHz 的超声波脉冲,不用管,我们不需要;Echo 端由低电平转为高电平,开启定时器;超声波模块检测到返回信号,Echo 端由高电平转为低电平,关闭定时器;得到超声波来回的总距离,进行计算,得到实际测量距离。
void HCSR04_Get_Length (void)
{
int total_time=0; //超声波来回的总时间
float distance=0; //实际测量距离
HCSR04_GPIO_init();
HAL_GPIO_WritePin(Trig_GPIO_PORT,Trig_GPIO_PIN,GPIO_PIN_SET); //拉高
__HAL_TIM_SetCounter(&htim2, 0); //定时器归零
delay_us(15);
HAL_GPIO_WritePin(Trig_GPIO_PORT,Trig_GPIO_PIN,GPIO_PIN_RESET); //拉低
while(HAL_GPIO_ReadPin(Echo_GPIO_PORT,Echo_GPIO_PIN)==GPIO_PIN_RESET); //Echo转到高电平
HAL_TIM_Base_Start(&htim2); //启动定时器
while(HAL_GPIO_ReadPin(Echo_GPIO_PORT,Echo_GPIO_PIN)==GPIO_PIN_SET); //Echo转回低电平
HAL_TIM_Base_Stop(&htim2); //停止定时器
total_time = __HAL_TIM_GetCounter(&htim2); //得到高电平持续时间
distance = total_time * 0.01715; // //算出测量距离(343*0.000001*100/2 = 0.01715)
printf("dis : %.2f cm\r\n",distance);
}
有的同学可能会好奇,这个“ * 0.01715 ”是什么,因为
实际距离 = 测量距离 / 2
= 速度 × 总时间 / 2。
= 343(m/s) * total_time(us)/ 2
= 343(m/s) * total_time(us) * 0.000001(1s=1000000) * 100(1m=100cm)/2
= 343 * 0.000001 * 100 / 2
= 0.01715
所以我们就直接写 0.01715 啦,减轻一点计算负担,虽然本身也没多少。
.h文件内容如下:
#ifndef __HCSR04_H__
#define __HCSR04_H__
#include "stdio.h"
#include "stm32f1xx.h"
/* 引脚定义 */
#define Trig_GPIO_PORT GPIOB
#define Trig_GPIO_PIN GPIO_PIN_6
#define Trig_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0) /* PB口时钟使能 */
#define Echo_GPIO_PORT GPIOB
#define Echo_GPIO_PIN GPIO_PIN_7
#define Echo_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0) /* PB口时钟使能 */
void HCSR04_GPIO_init(void);
void TIM2_Init(void);
void HCSR04_Get_Length (void);
#endif
4.5 最终效果
串口输出如下,这是我用本子在超声波前来回移动的数据。记得给板子上电哦,光 STLink 供电可不够。
5. 小结通过本文的学习与实践,相信大家已经了解并掌握 HC-SR04 的特性和使用,能够更好地应用于嵌入式开发。希望 HC-SR04 可以成为您的得力助手,让我们一起玩转 HC-SR04,peace and love!
另外,想进大厂的同学,一定要好好学算法,这是面试必备的。这里准备了一份 BAT 大佬总结的 LeetCode 刷题宝典,很多人靠它们进了大厂。
刷题 | LeetCode算法刷题神器,看完 BAT 随你挑!
有收获?希望老铁们来个三连击,给更多的人看到这篇文章