超聲波傳感器模塊

歡迎來到?破曉的歷程的 博客

??不負時光,不負己??

文章目錄

    • 1.`HC-SR04`介紹
    • 2.`HC-SR04`原理介紹
      • 2.1原理概述
        • 3.2原理詳解
    • 4驅動代碼編寫
      • 4.1寫前思考
      • 4.2硬件連線
    • 5.總結
      • hcsr04.h
      • hcsr04.c

1.HC-SR04介紹

超聲波傳感器有很多種類的型號:HC-SR04、UC-025、UC-026、UC-015、US-100等等,但是他們都大同小異。他們的主要區別是工作參數有點不一樣,像是工作的電壓或者溫度,探測距離或精度有點差別。引腳是一樣的,都是4個引腳(us-100多了一個GND引腳),引腳的工作和作用也是一樣的。

image-20250513180231393

其中我們最常用的為

image-20250513180319082

接線如下:

HC-SR04STM32備注
VCC3.3V/5V外接直流電源
Trig任意一個GPIO輸入端
ECHO任意一個GPIO輸出端
GNDGND接地

2.HC-SR04原理介紹

2.1原理概述

超聲波測距的工作原理其實很簡單,傳感器發送超聲波,超聲波碰到障礙物反彈回來,被傳感器接收到。芯片算出發送和接收的時間間隔,再利用公式:s=vxt,看下面示意圖,所以實際距離=測量距離/2= 速度 x時間/2。
順便一提,超聲波在空氣中的傳播速度大概是 343m/,傳播速度受到環境條件的影響,如溫度、濕度和氣壓等

image-20250513182145684

超聲波模塊有兩個超聲波探頭,一個是發送端,負責發送超聲波,一個是接受端,負責接收超聲波。

3.2原理詳解

接下來我們用時序圖的方式來介紹超聲波發送和接收的過程以及如何計算距離的。

  • 正常測距時的時序:
image-20250513182520277
  1. 單片機會給超聲波模塊發送大于10us的高電平的觸發信號;
  2. 超聲波模塊接收到觸發信號后 Trig端發送8個40KHz的超聲波脈沖。
  3. Echo端由低電平轉為高電平,并同時開始發送超聲波。
  4. 超聲波模塊接收到返回信號后,Echo端由高電平轉為低電平。
  5. Echo的高電平寬度即為超聲波發出的時間。

4驅動代碼編寫

明白了超聲波測距的原理,我們知道了超聲波測距的重點是測量超聲波在空氣中的時間。接下來我們來寫超聲波傳感器的驅動代碼。

4.1寫前思考

我們計算差超聲波往返所需時間,然后乘于超聲波的速度,計算出距離,所以我們需要一個類似于秒表的東西,來測我們的時間。

所以我們可以先用定時器來做一個以微妙為單位的計時。為了方便使用,我們再封裝若干個使用函數以便于我們使用這個定時器。

程序如下:

// TIM2 初始化句柄
TIM_HandleTypeDef tim2_handle;/*** @brief TIM2 定時器初始化函數*        設置定時器基本參數,并調用 HAL 庫進行初始化*/
void tim2_init(void)
{// 指定定時器實例為 TIM2(即使用 TIM2 作為定時器)tim2_handle.Instance = TIM2;// 設置分頻器:72-1 = 71// 如果主頻為 72MHz,那么定時器時鐘頻率為 72MHz / 72 = 1MHz// 即定時器每計數一次所需時間為 1 微秒tim2_handle.Init.Prescaler = 72 - 1;// 設置自動重裝載值(ARR):65536-1 = 65535// 當定時器計數到 65535 后溢出,重新從 0 開始// 若計數頻率為 1MHz,則溢出周期為 65536 微秒(即 65.536 毫秒)tim2_handle.Init.Period = 65536 - 1;// 向上計數模式(從0計數到ARR)tim2_handle.Init.CounterMode = TIM_COUNTERMODE_UP;// 關閉自動重裝載寄存器的預裝載功能tim2_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;// 調用 HAL 庫函數初始化定時器 TIM2HAL_TIM_Base_Init(&tim2_handle);
}/*** @brief TIM2 的 MSP(MCU Support Package)初始化函數*        一般用于配置定時器的時鐘及中斷* @param htim TIM句柄指針*/
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{// 判斷當前初始化的是不是 TIM2if(htim->Instance == TIM2){// 使能 TIM2 定時器時鐘__HAL_RCC_TIM2_CLK_ENABLE();}
}/*** @brief 啟動 TIM2 定時器*/
void tim2_start(void)
{// 啟動基礎定時器,不帶中斷HAL_TIM_Base_Start(&tim2_handle);
}/*** @brief 停止 TIM2 定時器*/
void tim2_stop(void)
{// 停止基礎定時器HAL_TIM_Base_Stop(&tim2_handle);
}/*** @brief 獲取當前 TIM2 定時器計數器的值* @return 當前計數器的值(0~65535)*/
uint16_t tim2_get_cnt(void)
{// 使用 HAL 宏獲取定時器當前計數器值return __HAL_TIM_GetCounter(&tim2_handle);
}/*** @brief 設置 TIM2 定時器計數器的值* @param val 要設置的計數器值*/
void tim2_set_cnt(uint16_t val)
{// 使用 HAL 宏設置定時器的當前計數器值__HAL_TIM_SetCounter(&tim2_handle, val);
}

4.2硬件連線

HC-SR04C8T6
VCCVCC
GNDGND
TrigPB6
echoPB7

因為我們涉及到對個別引腳的使用,所以我們需要對引腳進行一些簡單的配置(為了方便對引腳進行修改,我們對引腳進行了一些簡單的宏定義):

hcsrc04.h:

#define TRIG_PORT  GPIOB
#define TRIG_PIN   GPIO_PIN_6 
#define TRIG_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOB_CLK_ENABLE()
#define TRIG_HIGH()         HAL_GPIO_WritePin(TRIG_PORT,TRIG_PIN,GPIO_PIN_SET)
#define TRIG_LOW()          HAL_GPIO_WritePin(TRIG_PORT,TRIG_PIN,GPIO_PIN_RESET)#define ECHO_PORT GPIOB
#define ECHO_PIN  GPIO_PIN_7
#define ECHO_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
#define ECHO_STATUS()     HAL_GPIO_ReadPin(ECHO_PORT,ECHO_PIN)

hcsrc04.c

/*** @brief 初始化 HC-SR04 超聲波模塊所使用的 GPIO 引腳*        Trig 為輸出模式,用于發出超聲波脈沖*        Echo 為輸入模式,用于接收返回的超聲波信號*/
void hcsr04_gpio_init(void)
{// 定義 GPIO 初始化結構體,用于配置引腳屬性GPIO_InitTypeDef gpio_initstruct;// 使能 Trig 引腳所在 GPIO 端口的時鐘TRIG_GPIO_CLK_ENABLE();// 使能 Echo 引腳所在 GPIO 端口的時鐘ECHO_GPIO_CLK_ENABLE();/*************** 配置 Trig 引腳 ***************/// 設置 Trig 引腳號(例如 GPIO_PIN_1)gpio_initstruct.Pin = TRIG_PIN;// 設置為推挽輸出模式(用于產生控制信號)gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;// 上拉電阻(防止懸空引起不穩定)gpio_initstruct.Pull = GPIO_PULLUP;// 設置 IO 速度為中速(可根據需要選擇低、中、高)gpio_initstruct.Speed = GPIO_SPEED_MEDIUM;// 初始化 Trig 引腳所在端口HAL_GPIO_Init(TRIG_PORT, &gpio_initstruct);/*************** 配置 Echo 引腳 ***************/// 設置 Echo 引腳號(例如 GPIO_PIN_2)gpio_initstruct.Pin = ECHO_PIN;// 設置為輸入模式(用于接收超聲波返回信號)gpio_initstruct.Mode = GPIO_MODE_INPUT;// Echo 通常不需要特別配置上拉/下拉,默認即可(如需設置可加上)// gpio_initstruct.Pull = GPIO_NOPULL;// 初始化 Echo 引腳所在端口HAL_GPIO_Init(ECHO_PORT, &gpio_initstruct);
}

為了方便我們使用,我們也需要封裝一個函數,這個函數名我們定義為:hcsr04_get_length,相信大家通過這個函數名就可以知道這個函數的作用,在前文中,我們介紹了超聲波是如何發出的,四個 引腳的作用有什么不同。簡單梳理一下:

  1. 單片機給Trig引腳至少10us長的一個高電平。
  2. ECHO引腳從低電平到高電平,表示開始發送波;波發出的那一刻,開啟軟件定時器(開始計時)。
  3. ECHO引腳,由高電平轉為低電平,表示波回來了,此時我們停止計時器,計算經過時長。
  4. 獲取經過的時間,并根據計算公式算出距離。

基于此,我們寫出:

/*** @brief 獲取 HC-SR04 超聲波測距模塊測得的距離(單位:厘米)* @return 距離值(cm)*/
float hcsr04_get_length(void)
{// 用于保存 Echo 信號持續的時間(單位:微秒)uint16_t totol_time = 0;// 用于保存最終計算出的距離值(單位:厘米)float distance = 0;/*************** 第1步:發送Trig脈沖 ***************/// 給 Trig 引腳發送一個 10 微秒以上的高電平脈沖,觸發超聲波發射TRIG_HIGH();       // 設置 Trig 引腳為高電平delay_us(15);      // 延遲至少 10us,這里用 15us 更加保險TRIG_LOW();        // 設置 Trig 引腳為低電平,發送完成/*************** 第2步:等待 Echo 信號拉高(開始接收) ***************/// 當 Echo 引腳由低電平變為高電平時,表示超聲波已經發射出去// 此時開始計時while(ECHO_STATUS() == GPIO_PIN_RESET);  // 等待 Echo 變為高電平tim2_start();        // 啟動定時器tim2_set_cnt(0);     // 將定時器計數清零/*************** 第3步:等待 Echo 信號拉低(接收到回波) ***************/// 當 Echo 引腳由高電平變為低電平時,表示回波已經接收完成// 此時停止計時while(ECHO_STATUS() == GPIO_PIN_SET);    // 等待 Echo 變為低電平tim2_stop();         // 停止定時器/*************** 第4步:獲取 Echo 高電平持續時間 ***************/// 獲取定時器計數值(單位是 us,取決于定時器配置)totol_time = tim2_get_cnt();/*************** 第5步:根據聲速計算距離 ***************/// 聲速約為 34300 cm/s,即 0.0343 cm/us// 因為往返距離,所以除以 2// distance = (totol_time × 0.0343) / 2 ≈ totol_time * 0.01715distance = totol_time * 0.01715f;// 返回測得的距離(單位:cm)return distance;
}

5.總結

本文章中,我們介紹了超聲波傳感器的原理,并以其中較為經典的 HC-SR04為例,給出了驅動代碼。現將完整代碼粘貼如下:

hcsr04.h

#ifndef __HCSR04_H__#define __HCSR04_H__#define TRIG_PORT  GPIOB
#define TRIG_PIN   GPIO_PIN_6 
#define TRIG_GPIO_CLK_ENABLE()  __HAL_RCC_GPIOB_CLK_ENABLE()
#define TRIG_HIGH()         HAL_GPIO_WritePin(TRIG_PORT,TRIG_PIN,GPIO_PIN_SET)
#define TRIG_LOW()          HAL_GPIO_WritePin(TRIG_PORT,TRIG_PIN,GPIO_PIN_RESET)#define ECHO_PORT GPIOB
#define ECHO_PIN  GPIO_PIN_7
#define ECHO_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
#define ECHO_STATUS()     HAL_GPIO_ReadPin(ECHO_PORT,ECHO_PIN)
void hcsr04_init(void);
float hcsr04_get_length(void);
#endif 

hcsr04.c

#include "hcsr04.h"
#include "sys.h"
#include "delay.h"
TIM_HandleTypeDef tim2_handle = {0};//定時器初始化函數
void tim2_init(void)
{tim2_handle.Instance = TIM2;tim2_handle.Init.Prescaler = 72-1;tim2_handle.Init.Period = 65536-1;tim2_handle.Init.CounterMode = TIM_COUNTERMODE_UP;tim2_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;HAL_TIM_Base_Init(&tim2_handle);}//msp函數
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM2){__HAL_RCC_TIM2_CLK_ENABLE();}
}void tim2_start(void)
{HAL_TIM_Base_Start(&tim2_handle);
}
void tim2_stop(void)
{HAL_TIM_Base_Stop(&tim2_handle);
}
uint16_t tim2_get_cnt(void)
{return __HAL_TIM_GetCounter(&tim2_handle);
}
void tim2_set_cnt(uint16_t val)
{__HAL_TIM_SetCounter(&tim2_handle,val); 
}/******************************************************** */
/*初始化超聲波傳感器*/
void hcsr04_gpio_init(void)
{GPIO_InitTypeDef gpio_initstruct;//打開時鐘TRIG_GPIO_CLK_ENABLE();ECHO_GPIO_CLK_ENABLE();gpio_initstruct.Pin=TRIG_PIN;gpio_initstruct.Mode=GPIO_MODE_OUTPUT_PP;gpio_initstruct.Pull=GPIO_PULLUP;gpio_initstruct.Speed=GPIO_SPEED_MEDIUM;HAL_GPIO_Init(TRIG_PORT,&gpio_initstruct);gpio_initstruct.Pin=ECHO_PIN;gpio_initstruct.Mode=GPIO_MODE_INPUT;HAL_GPIO_Init(ECHO_PORT,&gpio_initstruct);
}
void hcsr04_init(void)
{tim2_init();hcsr04_gpio_init();}
float hcsr04_get_length(void)
{uint16_t totol_time=0;float distance=0;//1Trig引腳,給Trig引腳至少10us的高電平TRIG_HIGH();delay_us(15);TRIG_LOW();//2ECHO引腳,由低電平跳轉到高電平,表示開始發送波,波發出去的那一下,開啟定時器while(ECHO_STATUS()==GPIO_PIN_RESET);tim2_start();tim2_set_cnt(0);//3ECHO,由高電平條轉低電平,表示波回來了,波回來的那一下,我們開始停止定時器,計算出中間經過//多長時間while(ECHO_STATUS()==GPIO_PIN_SET);tim2_stop();//4.計算出中間經過的時間totol_time=tim2_get_cnt();//5.距離=速度(343m/s)*時間/2;distance=totol_time*0.01715;return distance;}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/80646.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/80646.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/80646.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

《Effective Python》第2章 字符串和切片操作——深入理解Python 中的字符數據類型(bytes 與 str)的差異

引言 本篇博客基于學習《Effective Python》第三版 Chapter 2: Strings and Slicing 中的 Item 10: Know the Differences Between bytes and str 的總結與延伸。在 Python 編程中,字符串處理是幾乎每個開發者都會頻繁接觸的基礎操作。然而,Python 中的…

py7zr解壓文件時報錯CrcError(crc32, f.crc32, f.filename)

報錯信息 Traceback (most recent call last):File "/home/hp/project/test/file_util.py", line 130, in extract_archive_7zarchive.extract(targets[fixed_file], pathoutput_dir, recursiveTrue)File "/home/hp/miniconda3/envs/celery/lib/python3.10/sit…

物理:由基本粒子組成的個體能否提煉和重組?

個體差異源于基本粒子組合的復雜性與隨機性,這一假設若成立,確實可能為生物醫學帶來革命性突破——但需要突破技術、理論與系統層級的多重壁壘。以下從科學邏輯與技術路徑展開分析: 一、隨機組合中的共性與穩定結構 1. 自然界的自組織規律 涌現性(Emergence):盡管粒子組…

動態路由EIGRP的配置

動態路由EIGRP的配置 動態路由EIGRP:增強內部網關協議 為何收斂快、不成環? 路由計算的無環路和路由的收斂速度是路由計算的重要指標。EIGRP協議由于使用了DUAL算法,使得EIGRP協議在路由計算中不可能有環路路由產生,同時路由計…

組合問題(多條件)

39. 組合總和 - 力扣&#xff08;LeetCode&#xff09; class Solution { private:vector<vector<int>>result;vector<int>path;void backtracking(vector<int>& candidates, int target,int sum,int startIndex){if(sum>target){return;}if(…

SimScape物理建模實例2--帶控制的單質量彈簧阻尼系統

模型下載&#xff1a; 基于simscape&#xff0c;單質量系統帶位置控制資源-CSDN文庫 在實例1中&#xff0c;我們搭建了不帶控制的單質量彈簧阻尼系統&#xff0c;該系統沒有外界力量介入&#xff0c;只有彈簧的初始彈力&#xff0c;帶著彈簧使勁彈來彈去。 SimScape物理建模實…

OpenAI Text 模型與 Chat 模型調用實戰指南:從基礎配置到創意花店命名

在 AI 應用開發的浪潮中&#xff0c;OpenAI 的大語言模型成為開發者實現創新功能的得力工具。其中&#xff0c;Text 模型和 Chat 模型作為核心接口&#xff0c;被廣泛應用于文本生成、對話交互等場景。本文將以 “為花店起名” 為實際需求&#xff0c;手把手教你如何安全調用這…

網頁常見水印實現方式

文章目錄 1 明水印技術實現1.1 DOM覆蓋方案1.2 Canvas動態渲染1.3 CSS偽元素方案2 暗水印技術解析2.1 空域LSB算法2.2 頻域傅里葉變換3 防篡改機制設計3.1 MutationObserver防護3.2 Canvas指紋追蹤4 前后端實現對比5 攻防博弈深度分析5.1 常見破解手段5.2 進階防御策略6 選型近…

現代化QML組件開發教程

現代化QML組件開發教程 目錄 QML基礎介紹QML項目結構基本組件詳解自定義組件開發狀態與過渡高級主題最佳實踐 QML基礎介紹 什么是QML QML (Qt Meta Language) 是一種聲明式語言&#xff0c;專為用戶界面設計而創建。它是Qt框架的一部分&#xff0c;讓開發者能夠創建流暢、…

C/C++ 程序執行的主要過程

預處理&#xff08;Preprocessing&#xff09; 任務&#xff1a; 處理源代碼中以 # 開頭的預處理指令&#xff0c;包括&#xff1a; 頭文件包含&#xff08;#include&#xff09;&#xff1a;將頭文件&#xff08;如 stdio.h&#xff09;的內容直接插入到源文件中。宏替換&…

時間序列預測建模的完整流程以及數據分析【學習記錄】

文章目錄 1.時間序列建模的完整流程2. 模型選取的和數據集2.1.ARIMA模型2.2.數據集介紹 3.時間序列建模3.1.數據獲取3.2.處理數據中的異常值3.2.1.Nan值3.2.2.異常值的檢測和處理&#xff08;Z-Score方法&#xff09; 3.3.離散度3.4.Z-Score3.4.1.概述3.4.2.公式3.4.3.Z-Score與…

ValueError: Caught ValueError in DataLoader worker process 0.

參考鏈接&#xff1a; https://stackoverflow.com/questions/1841565/valueerror-invalid-literal-for-int-with-base-10 它提示我有個地方值錯誤空字符 果然因為格式處理沒有傳進去東西&#xff0c;找下原因&#xff0c;讓它正常處理 原來是相對路徑的.影響了程序運行 將v…

JavaScript性能優化實戰,從理論到落地的全面指南

在前端開發領域&#xff0c;JavaScript的性能優化是提升用戶體驗的核心環節。隨著Web應用復雜度的提升&#xff0c;開發者面臨的性能瓶頸也日益多樣化。本文將從理論分析、代碼實踐和工具使用三個維度&#xff0c;系統性地講解JavaScript性能優化的實戰技巧&#xff0c;并通過大…

SQL、Oracle 和 SQL Server 的比較與分析

SQL、Oracle 和 SQL Server 的比較與分析 一、基礎概念 1. SQL (Structured Query Language) 定義&#xff1a;結構化查詢語言&#xff0c;用于管理關系型數據庫的標準語言類型&#xff1a; DDL (數據定義語言)&#xff1a;CREATE, ALTER, DROPDML (數據操作語言)&#xff1…

Telnet 類圖解析

Telnet 類圖&#xff08;文本描述&#xff09; --------------------------------------- | Telnet | --------------------------------------- | - host: str | # 目標主機 | - port: int …

Ansible安裝與核心模塊實戰指南

Ansible安裝與核心模塊實戰指南 自動化運維入門:從安裝到模塊化任務配置 Ansible作為一款無代理自動化工具,通過模塊化設計實現高效管理,尤其適用于快速部署、配置和維護大規模系統。本文將從安裝、核心模塊使用到實際案例,全面解析其核心功能與最佳實踐。 一、Ansible安裝…

VLLM推理大模型顯存不夠后,導致程序引擎崩潰的調優方案嘗試

背景介紹 硬件 A800 80G模型 chat-glm4-9b-128K環境 生產正常顯存占用情況 glm4 占用32GB 其他顯存工占用38GB左右 總共剩余10GB。 問題描述 推理時報錯日志&#xff0c;由于內網環境無法拿出日志&#xff0c;與下面的類似。 File "/data/miniconda3_new/envs/vllm-new…

【Nacos】env NACOS_AUTH_IDENTITY_KEY must be set.

【Nacos】env NACOS_AUTH_IDENTITY_KEY must be set. 問題描述 env NACOS_AUTH_IDENTITY_KEY must be set.原因分析 在 .env 文件中設置 Nacos 身份驗證相關的所有必要環境變量。 解決方案 添加到 .env 文件中 NACOS_AUTH_IDENTITY_KEYAuthorization NACOS_AUTH_IDENTITY…

C++語法基礎(下)

&#xff08;注&#xff1a;在看本文是如果感覺內容有點突兀&#xff0c;請先瀏覽《C語法基礎&#xff08;上&#xff09;》這篇文章幫助更好理解&#xff09; 一.缺省參數 缺省參數是聲明或定義函數時為函數的參數指定一個缺省值。在調用該函數時&#xff0c;如果沒有指定實參…

力扣Hot100(Java版本)

1. 哈希 1.1 兩數之和 題目描述&#xff1a; 給定一個整數數組 nums 和一個整數目標值 target&#xff0c;請你在該數組中找出 和為目標值 target 的那 兩個 整數&#xff0c;并返回它們的數組下標。 你可以假設每種輸入只會對應一個答案&#xff0c;并且你不能使用兩次相同…