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

STM32 智能垃圾桶项目笔记(一):超声波模块(HC-SR04)原理与驱动实现

本系列笔记是笔者学习 B 站 up 主 “技术探索者” STM32 系列视频所作的记录,有不明白的地方推荐观看视频

目录

  • 一、前言
  • 二、超声波模块(HC-SR04)原理
    • 2.1 模块引脚与核心特性
    • 2.2 工作原理与测距逻辑
    • 2.3 时序图与中断触发方案
  • 三、CubeMX 工程配置
    • 3.1 基础配置(芯片 / 时钟 / Debug)
    • 3.2 TIM3 配置(1μs 高精度延时)
    • 3.3 引脚与中断配置(Trig/Echo)
    • 3.4 串口配置(数据传输与验证)
  • 四、核心代码实现
    • 4.1 1μs 延时函数(基于 TIM3)
    • 4.2 串口重定向(printf 输出)
    • 4.3 超声波驱动函数(触发 / 中断回调)
    • 4.4 驱动头文件(driver_sr04.h)
  • 五、总结与预告

一、前言

本系列笔记将记录笔者运用 STM32 知识完成 “智能垃圾桶” 入门级项目的全过程。若想跟做该项目,需提前准备以下耗材:

  • 蓝牙模块:JDY-31
  • 语音合成模块:SYN6288
  • 超声波模块:HC-SR04(本次核心讲解模块)
    智能垃圾桶的核心功能是 “检测物体靠近后自动开盖”,而超声波模块的作用就是精准测量物体与桶的距离 —— 本次笔记将从模块原理、CubeMX 配置、代码实现三方面,完成超声波模块的基础驱动开发。

二、超声波模块(HC-SR04)原理

2.1 模块引脚与核心特性

HC-SR04 超声波模块共引出 4 个引脚,功能与接线要求如下:

引脚功能描述接线建议
VCC电源正极接 5V(模块工作电压为 5V)
Trig触发信号输入(外部控制)接 STM32 普通 GPIO 输出引脚
Echo回响信号输出(反馈距离)接 STM32 带中断的 GPIO 引脚
GND电源负极接 STM32 GND(需共地)

模块核心特性(无需深入研究参数细节,重点关注以下 3 点):

  • 测距范围:2cm ~ 400cm(满足垃圾桶开盖检测需求)
  • 测量精度:0.3cm(精度足够)
  • 工作频率:40kHz(超声波标准频率,无额外干扰)

2.2 工作原理与测距逻辑

HC-SR04 的工作流程由 “触发信号” 启动,通过 “回响信号” 反馈距离,具体步骤如下:

  1. 触发测距:STM32 向 Trig 引脚输出至少 10μs 的高电平信号(需高精度延时,笔者在定时器笔记中已实现,可回顾);
  2. 模块自动发送 / 接收超声波:Trig 接收到触发信号后,模块会自动发送 8 个 40kHz 的方波,同时开始检测是否有超声波反射回来;
  3. 回响信号反馈:若超声波反射回来,模块会通过 Echo 引脚输出高电平 —— 高电平的持续时间 = 超声波从 “发射到返回” 的总时间;
  4. 距离计算:根据 “时间 - 距离” 公式推导,最终距离 = (Echo 高电平持续时间 × 声速) / 2
    (注:声速取 340m/s,除以 2 是因为超声波需 “发射→反射→返回”,走了两倍距离)。

2.3 时序图与中断触发方案

超声波模块的 Echo 引脚电平变化时序图如下:
请添加图片描述

从时序图可观察到:

  • Echo 引脚从低电平变高电平时,产生上升沿(标志着超声波开始返回);
  • Echo 引脚从高电平变低电平时,产生下降沿(标志着超声波返回结束);
  • 上升沿到下降沿的时间差,就是 Echo 高电平持续时间(即超声波往返时间)。
    因此,我们需要用双边沿触发中断来捕获这两个时刻:
  1. 上升沿触发中断:记录当前时间 t1(开启定时器计数);
  2. 下降沿触发中断:记录当前时间 t2(停止定时器计数);
  3. 计算时间差 t = t2 - t1,代入距离公式即可得到测量结果。

三、CubeMX 工程配置

笔者使用的是 STM32F103C8T6 最小系统板,以下配置步骤均基于该芯片,按步骤操作即可完成基础工程搭建。

3.1 基础配置(芯片 / 时钟 / Debug)

  1. 芯片选择:打开 CubeMX,搜索并选择 STM32F103C8T6,如下图:
    请添加图片描述

  2. Debug 配置:进入 System Core → SYS,Debug 选择 Serial Wire(SWD 调试模式,常用且稳定);

  3. 时钟配置

    • 进入 System Core → RCC,High Speed Clock(HSE)选择 Crystal/Ceramic Resonator(外部晶振);
    • 进入 Clock Configuration,将 HCLK 配置为 72MHz(STM32F103 常用最高主频),配置如下:
      请添加图片描述
  4. 工程生成配置

    • 进入 Project Manager → Code Generator,勾选 Generate peripheral initialization as a pair of .c/.h files per peripheral(外设初始化文件分开,便于管理);
    • 进入 Project Manager → Project,Toolchain/IDE 选择 MDK-ARM(Keil 编译器),填写工程名并选择保存路径;
    • 点击 Generate Code 生成工程,编译确保无错误。

3.2 TIM3 配置(1μs 高精度延时)

超声波触发需要 10μs 高电平,需用 TIM3 实现 1μs 级延时,配置步骤如下:

  1. 进入 Timers → TIM3,模式选择 Internal Clock(内部时钟);
  2. 使能中断:勾选 NVIC Settings → TIM3 global interrupt(后续延时函数无需中断,但需开启定时器计数);
  3. 参数计算与配置
    • 预分频系数(Prescaler):72 - 1(72MHz 时钟 / 72 = 1MHz,即 1 次计数 = 1μs);
    • 自动重载值(Counter Period):65535(16 位定时器最大计数,避免频繁溢出);
  4. 配置如下图:
    请添加图片描述

3.3 引脚与中断配置(Trig/Echo)

笔者选择的引脚:Trig→PA9(输出)、Echo→PA8(中断输入),配置如下:

  1. Trig 引脚(PA9)

    • 进入 GPIO → PA9,模式设为 GPIO_Output(推挽输出),无需中断;
  2. Echo 引脚(PA8)

    • 进入 GPIO → PA8,模式设为 GPIO_EXTI8(外部中断模式);
    • 触发方式:Trigger Selection → Rising/Falling edge(双边沿触发);
    • 上拉电阻:Pull-up/Pull-down → Pull-up(避免引脚悬空误触发);
    • 配置如下图:
      请添加图片描述
  3. 使能 Echo 中断

    • 进入 NVIC → NVIC Settings,勾选 EXTI line[9:5] interrupts(PA8 对应 EXTI8,属于 line [9:5] 组)。

3.4 串口配置(数据传输与验证)

需通过串口输出测量结果,配置 USART1 如下:

  1. 进入 Connectivity → USART1,模式选择 Asynchronous(异步通信);

  2. 基本参数:波特率 115200,数据位 8,停止位 1,校验位 None

  3. 使能串口中断:勾选 NVIC Settings → USART1 global interrupt(可选,本次仅用发送,不强制);

  4. 配置如下图:
    请添加图片描述

  5. 硬件接线:STM32 的 PB6(USART1_TX)接 TTL-USB 转换器的 RX,PB7(USART1_RX)接转换器的 TX,转换器与开发板共地。

四、核心代码实现

生成工程后,新建 driver 文件夹,创建 driver_sr04.cdriver_sr04.h(驱动文件),并将 driver 文件夹添加到 Keil 工程路径(Options for Target → C/C++ → Include Paths)。

4.1 1μs 延时函数(基于 TIM3)

该函数与之前定时器笔记的实现略有不同,通过 “设置计数起始值” 实现精准延时,代码如下:

#include "driver_sr04.h"
#include "stm32f1xx_hal.h"// 声明 TIM3 句柄(CubeMX 自动生成在 tim.c 中)
extern TIM_HandleTypeDef htim3;/*** @brief  1μs 级高精度延时函数* @param  us:目标延时时间(单位:μs,最大 65530μs,避免溢出)* @retval 无*/
void Delay_us(uint16_t us)
{uint16_t differ = 0xffff - us - 5;  // 计算计数起始值(-5 为代码执行补偿)__HAL_TIM_SET_COUNTER(&htim3, differ);  // 设置 TIM3 计数起始值HAL_TIM_Base_Start(&htim3);  // 启动 TIM3 计数// 等待计数到接近 0xffff(避免溢出)while(differ < 0xffff - 5){differ = __HAL_TIM_GET_COUNTER(&htim3);  // 实时读取计数值}HAL_TIM_Base_Stop(&htim3);  // 停止 TIM3 计数
}

逻辑说明

  • 定时器从 differ 向上计数到 0xffff,计数次数 = 0xffff - differ ≈ us(补偿值 -5 抵消函数调用耗时);
  • 1MHz 时钟下,1 次计数 = 1μs,因此总延时 ≈ 目标 us 值。

4.2 串口重定向(printf 输出)

需实现 fputc 函数,让 printf 通过 USART1 输出,代码添加在 usart.c 中:

#include <stdio.h>  // 包含 printf 所需头文件// 声明 USART1 句柄
UART_HandleTypeDef huart1;/*** @brief  串口重定向函数,printf 输出到 USART1* @param  ch:要输出的字符* @param  f:文件指针(标准输出,无需关注)* @retval 输出的字符*/
int fputc(int ch, FILE *f)
{HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 1000);  // 发送 1 个字符,超时 1000msreturn ch;
}

Keil 配置

  • 打开工程 Options for Target → Target,勾选 Use MicroLIB(启用微库,支持 printf);
  • 进入 Debug → Settings → Flash Download,勾选 Reset and Run(下载后自动运行)。

4.3 超声波驱动函数(触发 / 中断回调)

4.3.1 触发函数(SR04_Trigger)

向 Trig 引脚输出 10μs 高电平,启动模块测距:

/*** @brief  超声波模块触发函数(启动测距)* @param  无* @retval 无*/
void SR04_Trigger(void)
{Trig_ON;    // PA9 拉高(触发开始)Delay_us(10);  // 保持 10μs 高电平Trig_OFF;   // PA9 拉低(触发结束)
}
4.3.2 中断回调函数(捕获 Echo 电平)

需额外配置 TIM4(用于计数 Echo 高电平时间),步骤如下:

  1. CubeMX 中配置 TIM4:Internal Clock,预分频 72-1,自动重载 65535,无需使能中断;
  2. driver_sr04.c 中实现 GPIO 中断回调,捕获 Echo 上升沿 / 下降沿:
// 声明 TIM4 句柄(CubeMX 自动生成)
extern TIM_HandleTypeDef htim4;
uint32_t distance_cm = 0;  // 测量距离(单位:cm)/*** @brief  GPIO 中断回调函数(处理 Echo 引脚电平变化)* @param  GPIO_Pin:触发中断的引脚* @retval 无*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{static uint32_t count = 0;  // 定时器计数值(暂存)if(GPIO_Pin == GPIO_PIN_8)  // 确认是 Echo 引脚(PA8){if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8) == 1)  // Echo 上升沿(开始返回){HAL_TIM_Base_Start(&htim4);  // 启动 TIM4 计数__HAL_TIM_SetCounter(&htim4, 0);  // 清零计数值}else  // Echo 下降沿(返回结束){HAL_TIM_Base_Stop(&htim4);  // 停止 TIM4 计数count = __HAL_TIM_GetCounter(&htim4);  // 读取计数值(1 计数 = 1μs)// 距离计算:count(μs) × 340(m/s) / 2 → 转换为 cmdistance_cm = count * 340 / 2 * 0.000001 * 100;count = 0;  // 清零计数值,准备下次测量}}
}

4.4 驱动头文件(driver_sr04.h)

声明函数与宏定义,供外部调用:

#ifndef __DRIVER_SR04_H
#define __DRIVER_SR04_H#include "main.h"
#include <stdio.h>// 宏定义:Trig 引脚(PA9)电平控制
#define Trig_ON    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_SET)
#define Trig_OFF   HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET)// 函数声明
void Delay_us(uint16_t us);        // 1μs 延时函数
void SR04_Trigger(void);           // 超声波触发函数// 外部变量声明(可选,供 main.c 读取距离)
extern uint32_t distance_cm;#endif

五、总结与预告

本次笔记完成了超声波模块(HC-SR04)的核心开发:

  1. 理解了模块的 “触发→测距→反馈” 工作流程,以及基于双边沿中断的时间捕获方案;
  2. 完成 CubeMX 配置(基础时钟、TIM3/TIM4 定时器、引脚中断、串口);
  3. 实现了 1μs 延时、触发函数、中断回调函数,为后续距离测量做好准备。
    下一篇笔记将结合本次驱动文件,实现完整逻辑。请关注 Hello_Embed,我们一起逐步完成智能垃圾桶项目!
http://www.dtcms.com/a/409802.html

相关文章:

  • 全文 -- Vortex: Extending the RISC-V ISA for GPGPU and 3D-Graphics Research
  • 设计网站推荐理由公司网站备案电话
  • 事件驱动与CDS:基于FHIR R5 Subscriptions与Bulk Data的再考察(下)
  • Tigshop开源商城系统 Java v5.2.2 / PHP v5.1.6版本正式发布(ES搜索上新)
  • 仙游县住房和城乡建设局网站1元涨1000粉丝网站
  • 【Linux】进程概念(六):进程地址空间深度解析:虚拟地址与内存管理的奥秘
  • 网站怎么做微信登录界面wordpress restful
  • Linux下写一个简陋的shell程序
  • OpenSource - 异构数据库数据与结构同步工具dbswitch
  • 首次披露潮玩成长性,量子之歌敲响新财年重估的钟声
  • jdk21 list中筛选出符合条件的list
  • Session共享问题
  • 3. Ollama 安装,流式输出,多模态,思考模型
  • Go基础:常用数学函数处理(主要是math包rand包的处理)
  • 做彩票网站被捉将受到什么惩罚北京网站建设公司制作网站
  • 沈阳小程序建设兰州seo优化
  • 低疲劳高响应!硬件软件协同:明基 RD280U 赋能创作开发,解锁新工位高效工作氛围
  • Apache Log4j2 lookup JNDI 注入漏洞(CVE-2021-44228)
  • wpf之 Popup
  • @xyflow/react:构建交互式节点流程图的完整指南
  • LinuxC++项目开发日志——基于正倒排索引的boost搜索引擎(5——通过cpp-httplib库建立网页模块)
  • 消息队列Apache Kafka教程
  • Hadess入门到实战(3) - 如何管理Npm制品
  • 【AI算法工程师的一些子路】音频大模型从入门到精通:算法工程师的成长之路
  • 透明的多级并发(行) 方式
  • 音乐网站还可以做做seo网站的公司哪家好
  • 【python3】Streamlit快速构建前端页面
  • ​FAQ: 如何在 WPF 项目中强制指定统一输出目录并确保 VS 调试正常?
  • mysql数据库学习之数据查询进阶操作(三)
  • 虚拟机下 Ubuntu 20.04 + Kubernetes 安装步骤