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

🍌🍌
作者简介:大家好啊,我叫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.参考视频

资料已上传,需要自取

  • 11
    点赞
  • 104
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
以下是使用HAL库完成SR-04超声波传感器距离测量的步骤: 1. 配置STM32CUBEMX: - 将超声波传感器的Trig引脚连接到STM32的GPIO输出引脚。 - 将超声波传感器的Echo引脚连接到STM32的GPIO输入引脚。 - 在STM32CUBEMX中配置GPIO引脚的模式为输出和输入。 - 在STM32CUBEMX中配置TIM定时器,用于计算超声波的回声时间。 2. 编写HAL库程序: - 初始化GPIO引脚和TIM定时器。 - 发送一个10微秒的高电平脉冲到Trig引脚,触发超声波传感器。 - 等待Echo引脚变为高电平,并开始计时。 - 等待Echo引脚变为低电平,并停止计时。 - 根据计时器的值计算距离,并将其显示在LCD屏幕上。 下面是一个使用HAL库完成SR-04超声波传感器距离测量的示例代码: ```c #include "main.h" #include "stm32f1xx_hal.h" #define TRIG_PIN GPIO_PIN_0 #define TRIG_PORT GPIOA #define ECHO_PIN GPIO_PIN_1 #define ECHO_PORT GPIOA TIM_HandleTypeDef htim2; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_TIM2_Init(void); int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_TIM2_Init(); while (1) { HAL_GPIO_WritePin(TRIG_PORT, TRIG_PIN, GPIO_PIN_RESET); HAL_Delay(2); HAL_GPIO_WritePin(TRIG_PORT, TRIG_PIN, GPIO_PIN_SET); HAL_Delay(10); HAL_GPIO_WritePin(TRIG_PORT, TRIG_PIN, GPIO_PIN_RESET); uint32_t start_time = 0; uint32_t end_time = 0; while (HAL_GPIO_ReadPin(ECHO_PORT, ECHO_PIN) == GPIO_PIN_RESET) { start_time = HAL_GetTick(); } while (HAL_GPIO_ReadPin(ECHO_PORT, ECHO_PIN) == GPIO_PIN_SET) { end_time = HAL_GetTick(); } uint32_t pulse_duration = end_time - start_time; float distance = pulse_duration * 0.034 / 2; // 将距离显示在LCD屏幕上 // ... HAL_Delay(100); } } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } } static void MX_TIM2_Init(void) { TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; htim2.Instance = TIM2; htim2.Init.Prescaler = 72 - 1; htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 0xFFFFFFFF; htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; if (HAL_TIM_Base_Init(&htim2) != HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) { Error_Handler(); } } static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = TRIG_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(TRIG_PORT, &GPIO_InitStruct); GPIO_InitStruct.Pin = ECHO_PIN; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(ECHO_PORT, &GPIO_InitStruct); } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

依点_DW

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值