一、简介
HC-SR04 工作参数:
• 探测距离:2~600cm
• 探测精度:0.1cm±1%
• 感应角度:<15°
• 输出方式:GPIO
• 工作电压:DC 3~5.5V
• 工作电流:5.3mA
• 工作温度:-40~85℃
- 怎么让它发送波 Trig?
给Trig端口至少10us的高电平
- 怎么知道它开始发了波 Echo引脚?
由低电平跳转到高电平,表示开始发送波
- 怎么知道接收了返回波 Echo?
由高电平跳转回低电平,表示波回来了
- 怎么算时间 ?
Echo引脚维持高电平的时间,波发出去的那一下,开始启动定时器 波回来的那一下,我们开始停止定时器,计算出中间经过多少时间
- 怎么算距离?
距离 = 速度(343m/s) * 时间 / 2
二、实验前期准备
因为想把测出来的距离打印在串口上,所以复制项目文件19-串口打印功能,重命名25-超声波传感器,新建文件夹hc-sr04
打开工程文件
加载文件
引脚接线
三、代码:
main.c
cpp
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "hcsr04.h"
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
led_init();//初始化led灯
hcsr04_init();
uart1_init(115200);
while(1)
{
printf("距离是:%.2f\r\n",hcsr04_get_lenght());
delay_ms(1000);
}
}
hcsr04.c
cpp
#include "hcsr04.h"
#include "delay.h"
TIM_HandleTypeDef tim2_handle = {0};//定义结构体
//定时器初始化函数
void timer_init()//把ARR和PSC当作参数传进来
{
tim2_handle.Instance = TIM2; //选择使用的定时器
tim2_handle.Init.Prescaler = 72-1; //PSC:使其读一个数用1us
tim2_handle.Init.Period = 65536-1; //ARR
tim2_handle.Init.CounterMode = TIM_COUNTERMODE_UP;//配置成向上的,默认向上的
tim2_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; //自动重装载,默认自动重装载
HAL_TIM_Base_Init(&tim2_handle);
// HAL_TIM_Base_Start_IT(&tim2_handle);//设置使能更新中断,和启动计数器
}
//msp函数
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
if(htim->Instance == TIM2)
{
__HAL_RCC_TIM2_CLK_ENABLE();
// HAL_NVIC_SetPriority(TIM2_IRQn,2,2);//设置优先级
// HAL_NVIC_EnableIRQ(TIM2_IRQn);//设置使能中断
}
}
//定时器启动的函数
void tim2_start(void)
{
HAL_TIM_Base_Start(&tim2_handle);
}
//定时器关闭的函数
void tim2_stop(void)
{
HAL_TIM_Base_Stop(&tim2_handle);
}
//读CNT计数器的值
uint16_t tim2_get_cnt(void)
{
return __HAL_TIM_GetCounter(&tim2_handle);
}
//将CNT计数器的值传递进来
void tim2_set_cnt(uint16_t val)
{
__HAL_TIM_SetCounter(&tim2_handle,val);
}
//初始化gpio口引脚
void hcsr04_gpio_init(void)
{
GPIO_InitTypeDef gpio_initstruct;//定义一个结构体gpio_initstruct
//打开trig和echo时钟
TRIG_GPIO_CLK_ENABLE();
ECHO_GPIO_CLK_ENABLE();
//调用TRIG的GPIO初始化函数
gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;//推挽输出
gpio_initstruct.Pin = TRIG_PIN;//trig对应的引脚
gpio_initstruct.Pull = GPIO_NOPULL;//引脚不拉
gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;//高速
HAL_GPIO_Init(TRIG_PORT,&gpio_initstruct);
//调用echo的GPIO初始化函数
gpio_initstruct.Mode = GPIO_MODE_INPUT;//作为输入引脚
gpio_initstruct.Pin = ECHO_PIN;//echo对应的引脚
HAL_GPIO_Init(ECHO_PORT,&gpio_initstruct);
}
//初始化超声波
void hcsr04_init(void)
{
timer_init();//初始化定时器
hcsr04_gpio_init();//初始化GPIO引脚
}
//读取超声波测出来的距离
float hcsr04_get_lenght(void)
{
uint16_t total_time = 0; //定义一个变量用于接收CNT的值
float distance = 0;
//1、Trig,给Trig端口至少10us的高电平
TRIG_HIGH();
delay_us(15);
TRIG_LOW();
//2、Echo引脚,由低电平跳转到高电平,表示开始发送波
//波发出去的那一下,开始启动定时器
while(ECHO_STATUS() == GPIO_PIN_RESET);//用echo引脚是否从低电平变成高电平来决定波是否发出去了
tim2_start(); //启动定时器2
tim2_set_cnt(0);//将定时器初始值置0
//3、Echo,由高电平跳转回低电平,表示波回来了
//波回来的那一下,我们开始停止定时器
while(ECHO_STATUS() == GPIO_PIN_SET);//用echo引脚是否从高电平变成低电平来决定波是否接到
tim2_stop();//关掉定时器
//4、Echo引脚维持高电平的时间=计算出中间经过多少时间
total_time = tim2_get_cnt();//用total_time接收CNT定时器里面的值
//距离 = 速度(343m/s) * 时间 / 2
//343m/s = 34300cm/s,因为距离是一个来回,所以要/2(这里速度除2下面路程就不用除2了)
// = 34300/2 = 17150cm/s = 0.017150cm/us
distance = total_time * 0.01715;
return distance;
}
hcsr04.h
cpp
#ifndef __HCSR04_H__
#define __HCSR04_H__
#include "sys.h"
#define TRIG_PORT GPIOB //trig对应gpio的哪一组
#define TRIG_PIN GPIO_PIN_6 //trig对应gpio的哪个引脚
#define TRIG_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() //gpio口时钟打开
#define TRIG_HIGH() HAL_GPIO_WritePin(TRIG_PORT,TRIG_PIN,GPIO_PIN_SET)//trig对应的引脚拉高
#define TRIG_LOW() HAL_GPIO_WritePin(TRIG_PORT,TRIG_PIN,GPIO_PIN_RESET)//trig对应的引脚拉低
#define ECHO_PORT GPIOB //echo对应gpio的哪一组
#define ECHO_PIN GPIO_PIN_7 //echo对应gpio的哪个引脚
#define ECHO_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE() //gpio口时钟打开
#define ECHO_STATUS() HAL_GPIO_ReadPin(ECHO_PORT,ECHO_PIN) //读取echo对应的引脚电平
void hcsr04_init(void);
float hcsr04_get_lenght(void);
#endif
打开串口助手,每一秒超声波都在测距