当前位置:网站首页>19.[STM32]HC_SR04超声波测距_定时器方式(OLED显示)

19.[STM32]HC_SR04超声波测距_定时器方式(OLED显示)

2022-07-05 15:18:00 依点_DW


作者简介:大家好啊,我叫DW,每天分享一些我新学到的知识,期待和大家一起进步
   
 
 系列专栏:STM32
   
 

 小实验目标:在OLED上显示HC_SR04测距的值
 如有写得不好的地方欢迎大家指正

 开发板:STM32F103ret6
创作时间:2022年6月11日

目录

HCSR_04特点

超声波测距原理 

实物图连接图

HC_SR04程序编写 

配置IO口

 超声波测距函数


HCSR_04特点

        HC_SR04 超声波测距模块可提供 2cm~400cm的非接触式距离感测功能,测距精度可达到3mm;模块包括超声波发射器、接收器与控制电路。

超声波测距原理 

        超声波测距原理是在超声波发射装置发出超声波,它的根据是接收器接到超声波时的时间差,与雷达测距原理相似。 超声波发射器向某一方向发射超声波,在发射时刻的同时开始计时,超声波在空气中传播,途中碰到障碍物就立即返回来,超声波接收器收到反射波就立即停止计时

超声波在空气中的传播速度为340m/s,根据计时器记录的时间t(秒),就可以计算出发射点距障碍物的距离(s),即:s=340t/2。

实物图连接图

VCC 供 5V电源

GND 为地线

Trig 触 发 控 制 信 号 输入,与STM32单片机的接PA6相连接

Echo() 回响信号,与STM32单片机的接PA7相连接

HC_SR04程序编写 

配置IO口

初始化Trig和Echo两个引脚,并配置定时器中断。 

u32 msCount = 0;

void HC_SR04_UserConfig(void){

	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef TIM_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//使能USART1,GPIOA时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);		//使能定时器6时钟
	


	GPIO_InitStructure.GPIO_Pin = Trig; //触发测距引脚
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	//推挽输出
	GPIO_Init(HC_PROT, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = Echo; //信号回响引脚
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;	//下拉
	GPIO_Init(HC_PROT, &GPIO_InitStructure);
	
	TIM_DeInit(TIM6);
	TIM_InitStructure.TIM_Period = 1000-1;//1MS
	TIM_InitStructure.TIM_Prescaler = 72-1;//预分配系数
	TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//不分频
	TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
	TIM_InitStructure.TIM_RepetitionCounter = DISABLE;//不开启重复计数
	TIM_TimeBaseInit(TIM6,&TIM_InitStructure);//定时器初始化
	
	TIM_ClearFlag(TIM6,TIM_FLAG_Update);
	TIM_ITConfig(TIM6,TIM_IT_Update|TIM_IT_Trigger,ENABLE);//使能中断源和中断触发
	TIM_Cmd(TIM6,DISABLE);//关闭定时器
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
	NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;//选择TIM6中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//子占优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//中断使能
	NVIC_Init(&NVIC_InitStructure);//初始化中断
	

}
void TIM6_IRQHandler(void){

	if(TIM_GetITStatus(TIM6,TIM_IT_Update) != RESET){//判断中断是否产生  1MS
	
		TIM_ClearITPendingBit(TIM6,TIM_IT_Update);//清空中断标志位
		msCount++;
	}
}

 为什么配置Echo引脚为下拉模式呢?因为由时序图可以看出,没有检测到回响信号时,Echo一直处于低电平状态,如果模式设置为浮空的话是不稳定的。

        当检测到信号时引脚拉高,当没有检测到信号时引脚自动拉低,所以配置为下拉模式。

        以上时序图表明你只需要提供一个 10uS 以上脉冲触发信号,该模块内部将发出 8 个 40kHz 周期电平并检测回波。一旦检测到有回波信号则输出回响信号回响信号的脉冲宽度与所测的距离成正比由此通过发射信号时的时间和接收到回响信号时的时间的间隔,就可以计算得到距离

        公式uS/58=厘米或者 uS/148=英寸;或是:距离= 高电平时间*声速(340M/S)/2;建议测量周期为 60ms 以上,以防止发射信号对回响信号的影响。 

 超声波测距函数

1. data1为通过厘米换算的值,data2为通过声速换算的值。

2. 由超声波时序图可以知道,当产生10us以上的触发脉冲时,Echo处于信号回响状态,当一开始时我们不确定此时输出回响信号Echo是否处在低电平状态,所以首先要判断Echo引脚的电平状态,以此用来查看上次有没有完成数据转换,之后再去触发信号Trig

	while(GPIO_ReadInputDataBit(HC_PROT,Echo) == 1);//!1,则执行下一步
	
	Trig_High;
	delay_us(20);
	Trig_Low;

3.  如果有触发信号Trig,模块内部会自动产生8 个 40kHz 周期电平,之后再判断Echo是否有高电平输出;

	while(GPIO_ReadInputDataBit(HC_PROT,Echo) == 0);//!=0
	TIM_SetCounter(TIM6,0);//清空计数器
	msCount = 0;//清空中断计数器值
	TIM_Cmd(TIM6,ENABLE);//开启TIM6中断

 4. 当Echo不为高电平时,则我们记录下一个回响电平,我们此时关闭TIM6.

	while(GPIO_ReadInputDataBit(HC_PROT,Echo) == 1);//!1
	TIM_Cmd(TIM6,DISABLE);

 5. 获取高电平时间,并进行距离换算。

	Count = msCount*1000;//us = ms * 1000
	Count = Count + TIM_GetCounter(TIM6);//高电平时间
	
	*data1 = Count/58;// us/58
	*data2 = Count*0.017;// 340 00/1000 000=0.034  0.034/2=0.017
    //有来回两段距离,故需要/2
	delay_ms(100);

完整函数代码如下

void HC_SR04_Ranging(u16 *data1,u16 *data2){
	
	u32 Count = 0;

	while(GPIO_ReadInputDataBit(HC_PROT,Echo) == 1);//!1,则执行下一步
	
	Trig_High;
	delay_us(20);
	Trig_Low;
	
	while(GPIO_ReadInputDataBit(HC_PROT,Echo) == 0);//!=0
	TIM_SetCounter(TIM6,0);//清空计数器
	msCount = 0;//清空中断计数器值
	TIM_Cmd(TIM6,ENABLE);//开启TIM6中断
	
	while(GPIO_ReadInputDataBit(HC_PROT,Echo) == 1);//!1
	TIM_Cmd(TIM6,DISABLE);//关闭定时器
	
	Count = msCount*1000;//us = ms * 1000
	Count = Count + TIM_GetCounter(TIM6);//高电平时间
	
	*data1 = Count/58;// us/58
	*data2 = Count*0.017;// 340 00/1000 000=0.034  0.034/2=0.017
	delay_ms(100);
}

340m/s等于 ? cm/us

1s=1000 000 us
340 00/1000 000=0.034
340m/s=0.034cm/us
 

6. 为了使获得的数据更加准确,我们需要多次测量获取平均值。

void HC_SR04_Debolan(u8 mode){

	u16 data1 = 0,data2 = 0; u32 data = 0;
	HC_SR04_Ranging(&data1,&data2);
	
	if(mode){  //厘米换算
	
		for(u8 i=0;i<5;i++){
		
			data = data + data1;
		}
		OLED_Write_Number(0,40,data/5);
	}
	else{	//声速换算
	
		for(u8 i=0;i<5;i++){
		
			data = data + data2;
		}
		OLED_Write_Number(4,40,data/5);
	}
}

我们配置了两种模式,模式1为厘米换算的值,模式0为声速换算的值。

 7主函数

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "oled.h"
#include "HC_SR04.h"


 int main(void)
 {		
	  delay_init();
	  OLED_UserConfig();
	  OLED_Init();
	  OLED_Display_On();
	  HC_SR04_UserConfig();
	 
	  //OLED_Display_Off();
 	while(1){
	
		    //OLED_Write_Number(2,40,131);
			HC_SR04_Debolan(1);//厘米换算
	}
 }
 

        全部的源代码已经介绍完毕,我们在测距模块3cm出放置障碍物,可以看到液晶屏幕上显示数字3,在模式1和模式0下都能准确的测量出距离。

为了方便下次查找,记得点点关注哦。

本章结束,我们下一章见


参考资料:

1.STM32固件库手册

2.正点原子STM32不完全手册_库函数版本

3.参考视频

资料已上传,需要自取

原网站

版权声明
本文为[依点_DW]所创,转载请带上原文链接,感谢
https://blog.csdn.net/qq_48796593/article/details/125215851