当前位置: 首页 > news >正文

STM32-HAL库 HC-SR04超声波测距 -- 2024.10.26

一、驱动简介

        此驱动基于STM32 HAL库开发,可移植到任何HAL工程里,适配任何型号的STM32单片机。本驱动不需要使用单片机的通用定时器,且测量精度很高(毫米级精度),这样做的优点是不需要占用定时器资源,工程配置简单,且驱动的可移植性更高。

        本驱动在 2024.11.10 以前免费,有需求的朋友请帮忙点个关注、点个赞。若在移植的过程中遇到无法解决的困难,请在评论区留言。

        若还需要其他类型的传感器驱动,可在评论区留言,或者添加微姓:able078

二、HC-SR04简介

(一)概述

        HC-SR04 是一种流行的超声波距离传感器,广泛应用于各种电子项目,如机器人、测距设备等。它通过发射和接收超声波信号来测量与障碍物之间的距离。HC-SR04 具有成本低、易于使用和高精度等优点。

(二)引脚说明

HC-SR04 通常有 4 个引脚,功能如下:

  • VCC:供电引脚,通常接 5V 电源。
  • Trig(触发引脚):输入引脚,发送高电平信号来触发传感器发射超声波。
  • Echo(回声引脚):输出引脚,传递接收到的回波持续时间,以计算距离。
  • GND:接地引脚。

(三)工作原理

  1. 触发信号:通过将 Trig 引脚拉高至少 10 微秒,传感器开始发射超声波信号。
  2. 发射超声波:传感器内的发射器会发出 8 个 40 kHz 的超声波脉冲。
  3. 接收回波:超声波遇到障碍物反射回传感器,接收器感知到这个回波信号。
  4. 持续时间测量:Echo 引脚输出高电平,时间与超声波从传感器发出到返回所用时间成正比。时间越长,距离越远。
  5. 距离计算:利用公式计算距离:Distance = (Time*343) / 2 

三、CubeMX生成基础工程

1、芯片选型:这里选择STM32f103c8t6

2、配置Debug:SW模式

3、配置外部时钟

4、配置TRIG引脚:引脚可根据实际情况任意选择,但必须重命名为:TRIG

5、配置ECHO引脚:引脚可根据实际情况任意选择,但必须重命名为:ECHO 

6、配置串口,输出数据

7、输出基础工程文件 

  四、Keil5编写工程

(一)hcsr04.c 

      新建 hcsr04.c 文件,将下面代码块中的代码全部复制到  hcsr04.c 文件中

/* 这个代码块为 hcsr04.c 中的文件 */#include "hcsr04.h"/*************************************************** @brief  获取系统时钟(us级时钟)***************************************************/
uint64_t GetTime_us(void)
{uint32_t time_ms;uint32_t time_us;uint64_t time;time_ms=HAL_GetTick();time_us=( ( (SysTick->LOAD+1-SysTick->VAL) * 1.0) /(SysTick->LOAD+1) )* 1000;time=time_us+time_ms*1000;return time;
}	/*** 微妙延时函数* 全系列通用,只需要将宏定义CPU_FREQUENCY_MHZ根据时钟主频修改即可。* 系统滴答定时器是HAL库初始化的,且必须有HAL库初始化。*/
#define CPU_FREQUENCY_MHZ   (int)(HAL_RCC_GetHCLKFreq()/1000000)		// 自动获取STM32时钟主频
void delay_us(__IO uint32_t delay)  
{int last, curr, val;int temp;while (delay != 0){temp = delay > 900 ? 900 : delay;last = SysTick->VAL;curr = last - CPU_FREQUENCY_MHZ * temp;if (curr >= 0){do{val = SysTick->VAL;}while ((val < last) && (val >= curr));}else{curr += CPU_FREQUENCY_MHZ * 1000;do{val = SysTick->VAL;}while ((val <= last) || (val > curr));}delay -= temp;}
}void SR04_GPIO_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};/* GPIO Ports Clock Enable */__HAL_RCC_GPIOA_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_RESET);/*Configure GPIO pin : PtPin */GPIO_InitStruct.Pin = TRIG_Pin;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(TRIG_GPIO_Port, &GPIO_InitStruct);/*Configure GPIO pin : PtPin */GPIO_InitStruct.Pin = ECHO_Pin;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(ECHO_GPIO_Port, &GPIO_InitStruct);}float SR04_Get_Distance(void) {SR04_GPIO_Init();float total_distance = 0; // 用于存储总距离const int measurements = 5; // 测量次数for (int i = 0; i < measurements; i++) {uint64_t startTime = 0;uint32_t travelTime = 0;// 发送 10 us 的高电平信号到 TRIG 引脚HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_SET);delay_us(20); // 确保 TRIG 信号维持至少 10 usHAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_RESET);// 等待 ECHO 引脚变为高电平,开始计时while (HAL_GPIO_ReadPin(ECHO_GPIO_Port, ECHO_Pin) == GPIO_PIN_RESET) {// 等待 Echo 引脚高电平开始}startTime = GetTime_us(); // 记录开始时间// 等待 ECHO 引脚变为低电平,计时结束while (HAL_GPIO_ReadPin(ECHO_GPIO_Port, ECHO_Pin) == GPIO_PIN_SET) {// 等待 Echo 引脚低电平结束}travelTime = GetTime_us() - startTime; // 计算往返时间// 计算距离,Speed of Sound ~ 343 m/s => Distance (cm) = (Time (us) * 343) / 2float distance = ((travelTime * 343.0) / 2.0) / 10000; // 返回距离(厘米)total_distance += distance; // 累加当前测量的距离if(measurements > 1) HAL_Delay(10);}// 返回 5 次测量的平均值return total_distance / measurements;
}

      将该.c文件保存到:工程路径>Core>Src  

(二)hcsr04.h 

      新建 hcsr04.h 文件,将下面代码块中的代码全部复制到  hcsr04.h 文件中

/* 这里的代码复制到hcsr04.h中 */#ifndef __SR04_H
#define __SR04_H#include "main.h"void  SR04_GPIO_Init(void);
float SR04_Get_Distance(void);#endif 

        并将该.h文件保存到:工程路径>Core>Inc  

(三) 添加源文件

 (四)调用驱动

注意:

  1. 在使用该驱动的地方,需要在合适的位置写:#include "hcsr04.h" 
  2. 该驱动不需要初始化,在需要测距的地方直接调用函数即可。
  3. 使用之前需要一个浮点型的变量来缓存距离数据。
  4. 该传感器的最快调用频率不可超过100Hz,也就是每次调用间隔至少10ms。

下面是我在 main.c 中调用驱动函数的程序,读者可参考使用。

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "hcsr04.h"
#include <string.h>
#include "stdio.h"
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
float SR04_Distance = 0.0;
char  Tx_Buff[20] ;
/* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 *//* USER CODE END 0 *//*** @brief  The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 *//* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){SR04_Distance = SR04_Get_Distance();sprintf(Tx_Buff,"距离:%0.1f\r\n",SR04_Distance);HAL_UART_Transmit(&huart1,(uint8_t*)Tx_Buff,strlen(Tx_Buff),100);HAL_Delay(500);/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

五、效果展示

        因为录屏原因,不好记录传感器的移动过程,所以只录了串口调试助手的数据。但可以保证测量精度非常高,放在一个地方不动传感器,数据几乎没有波动。


http://www.mrgr.cn/news/59212.html

相关文章:

  • 87.【C语言】数据结构之链表的头插和尾插
  • ASP.NET Core 8.0 中使用 Hangfire 调度 API
  • 代码随想录刷题学习日记
  • 【大数据分析与挖掘模型】matlab实现——非线性回归预测模型
  • 论文笔记:通用世界模型WorldDreamer
  • 铜业机器人剥片 - SNK施努卡
  • C++基础:三个字符串也能搞大小?
  • 谈谈你对AQS的理解
  • 百度智能云推出11.11活动,各大云厂商香港服务器优惠活动汇总
  • Spark 基础操作
  • 线程安全-同步与互斥/死锁
  • 读取文件内容,并按数学成绩排名,之后输出显示
  • linux学习笔记 Ubuntu下的守护进程supervisor安装与多项目部署
  • 2024系统架构师---真题考试知识点
  • python如何通过json以及pickle读写保存数据
  • es实现自动补全
  • python 轮子是什么
  • 【Python】Whoosh:全流程自建搜索引擎
  • Linux之远程连接服务器
  • 【机器学习】股票数据爬取与展示分析(有代码链接)
  • 解析三相220V与三相380V变频器的关键差异
  • 初识Linux · 动静态库(incomplete)
  • 《 C++ 修炼全景指南:十七 》彻底攻克图论!轻松解锁最短路径、生成树与高效图算法
  • OCR应用之集装箱箱号自动识别技术,原理与应用
  • 3.1.1 平衡二叉树中改变区块属性,并分裂区块保持属性一致:MmSplitRegion()
  • RHCE笔记