STM32CubeMX-H7-14-HAL库使用超声波测距模块
这个是我从产品说明书中获取的简介。
2025年5月11日更新:新增标准库代码,添加初始化修改引脚直接可以使用
2025年6月7日第二次更新:新增定时器方案,获取距离不再堵塞,不用卡程序,用定时器状态机的方式(推荐)(旧的不删,新的是在原来的基础上弄出来的,看懂原来的才好看懂新的)
前言
在51单片机和32的标准库的时候使用过这个模块,但是到后面的时候,太久不用忘记怎末使用了
然后超声波模块测距的原理,好像也没有那么简单理解,为什么高脉冲的持续时间,就是从发送到接收的时间呢?
然后在HAL库又怎末使用呢?
本篇文章提供.c. h代码,只需要修改.h文件的TR和HC引脚,以及配置的10us的定时器中断TIM编号,就可以使用了
然后不用外部中断,只需要一个定时器中断就可以实现超声波测距的功能了
超声波测距模块简介
这个是我从产品说明书中获取的简介



超声波测距模块驱动过程
1.初始化
#define HC_TR_TRIG_PIN GPIO_PIN_0
#define HC_TR_TRIG_PORT GPIOA
#define HC_TR_ECHO_PIN GPIO_PIN_1
#define HC_TR_ECHO_PORT GPIOA
#define HC_TR_TIME htim2


只需要在Cubemx配置定时器中断,时间为10us就欧克
记得开启定时器中断,我这里是以主频为80Hz,PA0为TR,PA1为HC为例
2.脉冲发射
给TR口一个至少10us的高电平,就会开始发射8个40Hz的脉冲
因为是HAL库,HAL_Delay()是以1ms为单位的,直接给1ms就好
void TR_SEND()
{
HAL_GPIO_WritePin(HC_TR_TRIG_PORT, HC_TR_TRIG_PIN, GPIO_PIN_SET);
HAL_Delay(1);
HAL_GPIO_WritePin(HC_TR_TRIG_PORT, HC_TR_TRIG_PIN, GPIO_PIN_RESET);
GetEchoTime(2);
}
3.脉冲接收过程

根据这张图可以发现,发送完后HC还是低电平,所以我们要等到高电平
然后高电平的持续时间,就是从发送到接收的时长,我也想不明白,为什么会是这个时间
可能是发送芯片发送完后
要给接收芯片一个已发送收完的信号
接收芯片在收到发送完的信号后,才开始设置为高电平
直到接收到8个40KHz的脉冲后,才变成低电平
所以单片机在发送完后的一小段时间里面,HC还是低电平的,然后才变高,最后变低
高电平持续时间,就是发送和接收的时长
代码就在下面
其中计算的公式是
float distance = (float)GetEchoTime(0)/100000*340/2*100;
因为我定时器的时间为10us
假设期间经过了x个10us,那么就是
Time=x*10 us
=10x us
=10x /1000 ms
=10x /1000 000 s
=x/ 100 000s
然后路程等于速度乘时间
x=s*t= 340m/s * x/100 000s (m)
因为路程是距离的两倍
所以
实际测距得的距离为
L=x/2 = 340m/s * x/100 000s /2(m)
转化成cm,厘米为单位,那么就是乘100
L=x/2 = 340m/s * x/100 000s /2 *100(cm)
所以简化就是
L=x*170/1000(cm)
L=x*0.17 (cm)
如果发现数值错乱,那就是供电不稳的原因
历程源码-直接复制改.h文件引脚就可以使用了
记得要调用初始化函数
HC_TR.c
#include "HC_TR.h"
#include "tim.h"
#include "gpio.h"
#include "usart.h"
#include "stdio.h"
#include "string.h"
void TR_SE_init()
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
/*Configure GPIO pin : PA0 */
GPIO_InitStruct.Pin = HC_TR_TRIG_PIN ;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init( HC_TR_TRIG_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = HC_TR_ECHO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(HC_TR_ECHO_PORT, &GPIO_InitStruct);
HAL_TIM_Base_Start_IT(&HC_TR_TIME);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
}
void TR_SEND()
{
HAL_GPIO_WritePin(HC_TR_TRIG_PORT, HC_TR_TRIG_PIN, GPIO_PIN_SET);
HAL_Delay(1);
HAL_GPIO_WritePin(HC_TR_TRIG_PORT, HC_TR_TRIG_PIN, GPIO_PIN_RESET);
GetEchoTime(2);
}
uint32_t GetEchoTime(uint8_t cmd)
{
static uint32_t echo_time = 0;
switch (cmd)
{
case 0:
return echo_time;
case 1:
echo_time ++;
break;
case 2:
echo_time = 0;
break;
}
}
// 获取距离函数
float HC_TR_GetDistance(void)
{
// 发送触发信号
TR_SEND();
GetEchoTime(2);
while(HAL_GPIO_ReadPin(HC_TR_ECHO_PORT, HC_TR_ECHO_PIN)==0)
{
if(GetEchoTime(0) > 1000)
{
printf("wate time \r\n");
break;
}
}
//超时检测
GetEchoTime(2);
while (HAL_GPIO_ReadPin(HC_TR_ECHO_PORT, HC_TR_ECHO_PIN))
{
if(GetEchoTime(0) > 1000)
{
printf("one time \r\n");
break;
}
}
//超时检测
//float distance = (float)GetEchoTime(0)/100000*340/2*100;
float distance = (float)GetEchoTime(0)*0.17;
// printf("distance= %.1fcm\r\n",distance);
return distance;
}
// 定时器2中断处理函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim==&HC_TR_TIME)
{
GetEchoTime(1);
}
}
HC_TR.h
#ifndef HC_TR_H
#define HC_TR_H
#include "main.h"
// 定义超声波传感器的引脚
#define HC_TR_TRIG_PIN GPIO_PIN_0
#define HC_TR_TRIG_PORT GPIOA
#define HC_TR_ECHO_PIN GPIO_PIN_1
#define HC_TR_ECHO_PORT GPIOA
#define HC_TR_TIME htim2
void TR_SE_init();
float HC_TR_GetDistance(void);
void TR_SEND();
uint32_t GetEchoTime(uint8_t cmd);
#endif /* HC_TR_H */

2025年5月11日更新内容
标准库
HC_TR.c
#include "stm32f10x.h" // Device header
#include "HC_TR.h"
#include "Delay.h"
void Timer_Init(void)//要修改成自己对应的引脚
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;
TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(TIM2, ENABLE);
}
void TR_SE_init()
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_Initstructure;
GPIO_Initstructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Initstructure.GPIO_Pin = HC_TR_TRIG_PIN;
GPIO_Initstructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(HC_TR_TRIG_PORT,&GPIO_Initstructure);
GPIO_Initstructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Initstructure.GPIO_Pin = HC_TR_ECHO_PIN;
GPIO_Initstructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(HC_TR_ECHO_PORT,&GPIO_Initstructure);
Timer_Init();
}
void TR_SEND()
{
GPIO_WriteBit(HC_TR_TRIG_PORT, HC_TR_TRIG_PIN, 1);
Delay_us(100);
GPIO_WriteBit(HC_TR_TRIG_PORT, HC_TR_TRIG_PIN, 0);
GetEchoTime(2);
}
uint32_t GetEchoTime(uint8_t cmd)
{
static uint32_t echo_time = 0;
switch (cmd)
{
case 0:
return echo_time;
case 1:
echo_time ++;
break;
case 2:
echo_time = 0;
break;
}
}
// 获取距离函数
float HC_TR_GetDistance(void)
{
// 发送触发信号
TR_SEND();
GetEchoTime(2);
while(GPIO_ReadInputDataBit(HC_TR_ECHO_PORT, HC_TR_ECHO_PIN)==0)
{
if(GetEchoTime(0) > 1000)
{
break;
}
}
//超时检测
GetEchoTime(2);
while (GPIO_ReadInputDataBit(HC_TR_ECHO_PORT, HC_TR_ECHO_PIN))
{
if(GetEchoTime(0) > 1000)
{
break;
}
}
//超时检测
//float distance = (float)GetEchoTime(0)/100000*340/2*100;
float distance = (float)GetEchoTime(0)*0.17;
// printf("distance= %.1fcm\r\n",distance);
return distance;
}
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
GetEchoTime(1);
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
}
HC_TR.h
#ifndef HC_TR_H
#define HC_TR_H
#include "stm32f10x.h"
#define HC_TR_TRIG_PIN 1<<0
#define HC_TR_TRIG_PORT GPIOA //我这里是PA0
#define HC_TR_ECHO_PIN 1<<1
#define HC_TR_ECHO_PORT GPIOA //PA1
void Timer_Init(void);
void TR_SE_init();
float HC_TR_GetDistance(void);
void TR_SEND();
uint32_t GetEchoTime(uint8_t cmd);
#endif
2025年6月7日第二次更新
用法一样,都是初始化然后直接调用
不过函数有些小变化,下面讲用法
修改引脚编号和定时器编号

核心就是创建一个10us的定时器中断,然后把这个函数放到中断

然后初始化,直接调用就可以了

如图,其实可以返回小数,因为是浮点型

hc_tr.c
#include "HC_TR.h"
#include "tim.h"
#include "gpio.h"
#include <stdint.h>
void TR_SE_init()
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOE_CLK_ENABLE();
GPIO_InitStruct.Pin = HC_TR_TRIG_PIN ;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init( HC_TR_TRIG_PORT, &GPIO_InitStruct);
GPIO_InitStruct.Pin = HC_TR_ECHO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(HC_TR_ECHO_PORT, &GPIO_InitStruct);
TR_station(0);
HAL_TIM_Base_Start_IT(HC_TR_TIM);
}
uint32_t GetEchoTime(uint8_t cmd)
{
static uint32_t echo_time = 0;
switch (cmd)
{
case 0:
return echo_time;
case 1:
echo_time ++;
break;
case 2:
echo_time = 0;
break;
}
}
float distance_change(uint8_t cmd,float distance)
{
static float distance1=0;
if(cmd==0)
{
return distance1;
}
else if(cmd==1)
{
distance1=distance*0.17;
}
}
float distance_return()
{
float distance = distance_change(0,0);
}
void HC_TR_TIME()
{
static uint32_t time=0;
static uint8_t flag=0;
switch (flag)
{
case 0:
{
GetEchoTime(2);
TR_station(1);
flag=1;
break;
}
case 1:
{
if(GetEchoTime(0)>50)
flag=2;
break;
}
case 2:
{
GetEchoTime(2);
TR_station(0);
flag=3;
break;
}
case 3:
{
if(EC_station_read())
{
GetEchoTime(2);
flag=4;
}
if(GetEchoTime(0)>10000)
{
flag=0;
}
break;
}
case 4:
{
if(!EC_station_read())
{
flag=5;
}
if(GetEchoTime(0)>10000)
{
flag=0;
}
break;
}
case 5:
{
distance_change(1,GetEchoTime(0));
flag=0;
break;
}
}
GetEchoTime(1);
}
hc_tr.h
#ifndef HC_TR_H
#define HC_TR_H
#include "main.h"
// 定义超声波传感器的引脚
#define HC_TR_TRIG_PIN 1<<2
#define HC_TR_TRIG_PORT GPIOE
#define HC_TR_ECHO_PIN 1<<3
#define HC_TR_ECHO_PORT GPIOE
#define HC_TR_TIM &htim2
#define TR_station(x) HAL_GPIO_WritePin(HC_TR_TRIG_PORT, HC_TR_TRIG_PIN, x)
#define EC_station_read() HAL_GPIO_ReadPin(HC_TR_ECHO_PORT, HC_TR_ECHO_PIN)
void TR_SE_init();
float distance_return();
uint32_t GetEchoTime(uint8_t cmd);
void HC_TR_TIME();
float distance_change(uint8_t cmd,float distance);
#endif /* HC_TR_H */
更多推荐



所有评论(0)