文章目录
- 一、HC-SR04
- HC-SR04是什么?
- HC-SR04测距的原理
- 二、使用步骤
- 1.硬件
- 最远探测距离调节
- 硬件连接
- 2.软件
- 1.初始化配置代码如下(示例):
- 引脚初始化
- 定时器初始化
- 2.引脚输入输出配置代码如下(示例):
- 3.定时器中断处理代码如下(示例):
- 4.HCSR04测距函数代码如下(示例):
- 5.显示函数代码如下(示例):
- 6.变量定义如下(示例):
- 7.显示结果如下(示例):
- 图片
- 串口打印
- 三、总结
一、HC-SR04
HC-SR04是什么?
HC-SR04是一种常见的超声波测距模块,它可以用于测量物体与传感器之间的距离,在机器人导航、智能家居和安防系统等领域得到了广泛的应用。
HC-SR04超声波测距模块包含一个发射器和一个接收器,它们通过超声波信号实现测距。当发射器发出超声波信号后,它会被目标物体反射回来,并被接收器接收。根据超声波从发射到接收的时间差,就可以计算出物体与传感器之间的距离。
正面:
背面:
HC-SR04测距的原理
工作原理:
HC-SR04超声波测距模块由发射器和接收器组成。它通过发射超声波信号并接收反射回来的信号,利用信号的往返时间差来计算距离。
(1)采用 IO 触发测距,给至少 10us 的高电平信号;
(2)模块自动发送 8 个 40khz 的方波,自动检测是否有信号返回;
(3)有信号返回,通过 IO 输出一高电平,高电平持续的时间就是超声波从发射到返回的时间.测试距离=(高电平时间*声速(340M/S))/2;
模块使用注意事项:
1:此模块不宜带电连接,如果要带电连接,则先让模块的 Gnd 端先连接。否则会影响
模块工作。
2:测距时,被测物体的面积不少于 0.5 平方米且要尽量平整。否则会影响测试结果。
二、使用步骤
1.硬件
最远探测距离调节
上图标志电阻即 R3,可以调节最大探测距离。R3 电阻为 392,探测距离最大 4.5M 左右,探测角度小于 15 度;R3 电阻为 472,探测距离最大 7M 左右,探测角度小于 30 度;出厂默认 392,即最大探测距离 4.5M 左右。R3 电阻大,接收部分增益高,检测距离大,但检测角度会相应变大,容易检测到前方旁边的物体。当然,在不要求很高的测试距离的条件下,
可以改小 R3 来减小探测角度,这时最大测距会减小。
硬件连接
VCC | 电源5V | 接5V |
---|---|---|
Trig | 控制端 | 接PB12 |
Echo | 接收端 | 接PB13 |
GND | 电源地 | 接GND |
/* Defines ------------------------------------------------------------------*/
#define HCSR04_GPIO_RCC RCC_APB2Periph_GPIOB
#define HCSR04_GPIO_Port GPIOB
#define Trig_Pin GPIO_Pin_12
#define Echo_Pin GPIO_Pin_13//根据实际的引脚修改
2.软件
1.初始化配置代码如下(示例):
/*******************************************************************************
* 函数名:User_HCSR04_Init
* 描述 :HCSR04初始化
* 输入 :void
* 输出 :void
* 调用 :初始化
* 备注 :
*******************************************************************************/
void User_HCSR04_Init(void)
{
User_TIM1_Init();
HCSR04_GPIO_Init();
}
引脚初始化
/*******************************************************************************
* 函数名:HCSR04_GPIO_Init
* 描述 :HCSR04引脚初始化
* 输入 :void
* 输出 :void
* 调用 :初始化
* 备注 :
*******************************************************************************/
void HCSR04_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = Trig_Pin;//控制脚 Trig
GPIO_Init(HCSR04_GPIO_Port, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;//下拉输入
GPIO_InitStructure.GPIO_Pin = Echo_Pin;//接收脚 Echo
GPIO_Init(HCSR04_GPIO_Port, &GPIO_InitStructure);
}
定时器初始化
/*******************************************************************************
* 函数名:User_TIM1_Init
* 描述 :定时器1初始化
* 输入 :void
* 输出 :void
* 调用 :初始化
* 备注 :
*******************************************************************************/
void User_TIM1_Init(void)
{
RCC_APB2PeriphClockCmd(HCSR04_TIM_CLK_ENABLE, ENABLE); // 启用TIM1时钟
TIM_InternalClockConfig(HCSR04_TIM);// 设置TIM1使用内部时钟
TIM_TimeBaseInitTypeDef TIM1_TimeBaseInitStructure;// 定义结构体,配置定时器
TIM1_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 设置1分频(不分频)
TIM1_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;// 设置计数模式为向上计数
TIM1_TimeBaseInitStructure.TIM_Period = PERIOD_COUNT - 1; // 设置最大计数值,达到最大值触发更新事件
TIM1_TimeBaseInitStructure.TIM_Prescaler = PRESCALER_COUNT - 1; // 设置时钟预分频
TIM1_TimeBaseInitStructure.TIM_RepetitionCounter = 0; // 重复计数器
TIM_TimeBaseInit(HCSR04_TIM, &TIM1_TimeBaseInitStructure); // 初始化TIM1定时器
TIM_ClearFlag(HCSR04_TIM, TIM_FLAG_Update); // 清除更新中断标志位
TIM_ITConfig(HCSR04_TIM, TIM_IT_Update, ENABLE); // 开启更新中断
TIM1_NVIC_Init();
TIM_Cmd(HCSR04_TIM, ENABLE); // 开启定时器
}
/*******************************************************************************
* 函数名:TIM1_NVIC_Init
* 描述 :定时器1中断配置初始化
* 输入 :void
* 输出 :void
* 调用 :初始化
* 备注 :
*******************************************************************************/
void TIM1_NVIC_Init(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 设置中断优先级分组
NVIC_InitTypeDef NVIC_InitStructure; // 定义结构体,配置中断优先级
NVIC_InitStructure.NVIC_IRQChannel = HCSR04_TIM_IRQn; // 指定中断通道
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 中断使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 设置抢占优先级为最高
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 设置响应优先级为最高
NVIC_Init(&NVIC_InitStructure);
}
2.引脚输入输出配置代码如下(示例):
/*******************************************************************************
* 函数名:Trig_out_High
* 描述 :Trig输出高电平
* 输入 :void
* 输出 :void
* 调用 :内部调用
* 备注 :
*******************************************************************************/
void Trig_Out_High(void)
{
GPIO_SetBits(HCSR04_GPIO_Port,Trig_Pin);//Trig= 1
}
/*******************************************************************************
* 函数名:Trig_Out_Low
* 描述 :Trig输出低电平
* 输入 :void
* 输出 :void
* 调用 :内部调用
* 备注 :
*******************************************************************************/
void Trig_Out_Low(void)
{
GPIO_ResetBits(HCSR04_GPIO_Port,Trig_Pin);//Trig= 0
}
/*******************************************************************************
* 函数名:Read_Echo_Level
* 描述 :读取Echo引脚电平
* 输入 :void
* 输出 :void
* 调用 :内部调用
* 备注 :
*******************************************************************************/
uint8_t Read_Echo_Level(void)
{
return GPIO_ReadInputDataBit(HCSR04_GPIO_Port,Echo_Pin);
}
3.定时器中断处理代码如下(示例):
/*******************************************************************************
* 函数名:HCSR04_TIM_IRQHandler
* 描述 :定时器1中断服务程序
* 输入 :void
* 输出 :void
* 调用 :初始化
* 备注 :
*******************************************************************************/
void HCSR04_TIM_IRQHandler(void)
{
if(TIM_GetITStatus(HCSR04_TIM, TIM_IT_Update) != RESET)
{
if(ditance_flag)
{
ditance_count++;
}
TIM_ClearITPendingBit(HCSR04_TIM, TIM_IT_Update); //清除中断挂起位
}
}
4.HCSR04测距函数代码如下(示例):
/*******************************************************************************
* 函数名:Measurement_function
* 描述 :HCSR04测距函数
* 输入 :void
* 输出 :void
* 调用 :内部调用
* 备注 :
*******************************************************************************/
void Measurement_function(void)
{
Trig_Out_High();
Delay_20us();
Trig_Out_Low();
while(Read_Echo_Level()==0);//等待低电平结束
ditance_count = 0;
while(Read_Echo_Level()==1);//等待高电平结束
ditance_flag = 1;
if(ditance_count < Overtime)//小于超时时间 38ms
{
MM_ditance = ((ditance_count * 340)/2)/100;//单位毫米MM
}
}
5.显示函数代码如下(示例):
对OLED有疑问的可以参考我的另外一篇博客0.96寸OLED(IIC接口)显示屏的图像显示应用
/*******************************************************************************
* 函数名:OLED_Rfresh
* 描述 :OLED实时显示数据刷新
* 输入 :void
* 输出 :void
* 调用 :1s
* 备注 :
*******************************************************************************/
void OLED_Rfresh(void)
{
OLED_ShowString(1, 1, "Distance:"); //1行1列显示字符串Distance:
OLED_Part_Clear(2,1,16);
if(MM_ditance < 10)
{
OLED_ShowNum(2,10,MM_ditance,1);
OLED_ShowString(2, 12, "MM"); //2行12列显示单位MM
}
else if(MM_ditance < 100)
{
OLED_ShowNum(2,10,MM_ditance,2);
OLED_ShowString(2, 13, "MM"); //2行13列显示单位MM
}
else if(MM_ditance < 1000)
{
OLED_ShowNum(2,10,MM_ditance,3);
OLED_ShowString(2, 14, "MM"); //2行14列显示单位MM
}
}
6.变量定义如下(示例):
/* Defines ------------------------------------------------------------------*/
#define HCSR04_GPIO_RCC RCC_APB2Periph_GPIOB
#define HCSR04_GPIO_Port GPIOB
#define Trig_Pin GPIO_Pin_12
#define Echo_Pin GPIO_Pin_13//根据实际的引脚修改
#define HCSR04_TIM TIM1
#define HCSR04_TIM_CLK_ENABLE RCC_APB2Periph_TIM1
#define PERIOD_COUNT 10
#define PRESCALER_COUNT 72
#define HCSR04_TIM_IRQn TIM1_UP_IRQn
#define HCSR04_TIM_IRQHandler TIM1_UP_IRQHandler
#define Overtime 3800//38ms
uint8_t ditance_flag = 0;//开始测量标志
uint32_t ditance_count = 0;//测量计数 10us/次
uint16_t MM_ditance = 0;//输出测量距离 单位毫米
7.显示结果如下(示例):
图片
本来想录像的,但是一直录不好,有兴趣的自己测试下把。
串口打印
截取部分,测试内容:我是拿一个黑色本子立起来从近距离到远距离。
三、总结
超声波测距模块使用起来比较简单,但是发现环境条件对测量结果也存在一定影响,温度湿度我也没考虑进去,多次测量取平均值我也没用,还是存在诸多问题的,后面有时间在改进下,感谢你的观看,谢谢!