
這次我們來看一個基于 STM32L432KC 微控制器的簡易超聲波測距裝置。這個項目的核心不是復雜的算法而是如何用一塊低成本、低功耗的 MCU 和常見的 HC-SR04 超聲波模塊快速搭建一個可用的測距系統。對于嵌入式初學者、電子愛好者或需要快速驗證測距功能的開發者來說這是一個非常直接的實踐案例。本文將帶你從零開始理解超聲波測距原理完成 STM32L432KC 的硬件連接、軟件編程并最終實現一個能夠穩定測量距離并在串口顯示結果的裝置。整個過程重點關注代碼的可讀性、測量的穩定性以及如何在實際環境中進行校準和優化。如果你手頭有 STM32 開發板和 HC-SR04 模塊跟著做一遍就能跑通。1. 核心能力速覽能力項說明核心控制器STM32L432KC (ARM Cortex-M4 低功耗)測距模塊HC-SR04 超聲波傳感器測距原理測量超聲波發射到接收回波的時間差根據聲速計算距離有效測距范圍通常為 2cm ~ 400cm (實際效果受環境、模塊精度影響)輸出方式通過 USART 串口輸出距離數據到 PC 端串口助手供電需求3.3V 或 5V (STM32開發板供電注意HC-SR04邏輯電平)開發環境STM32CubeIDE / Keil MDK關鍵外設GPIO (輸出觸發、輸入捕獲)、定時器 (高精度計時)、USART (通信)適合場景嵌入式學習、課程設計、避障小車原型、簡單物體檢測2. 適用場景與使用邊界這個簡易超聲波測距裝置最適合以下幾類人群和場景嵌入式初學者通過一個完整的“傳感器-控制器-輸出”項目學習 STM32 的 GPIO、定時器、中斷和串口編程。快速原型驗證在開發機器人、智能小車或安防設備初期需要快速驗證測距功能是否可行。電子課程設計或畢業設計作為一個功能明確、硬件成本低、代碼量適中的選題。它的能力邊界也很清晰精度有限HC-SR04 模塊本身精度通常在毫米到厘米級且聲速受溫度、濕度影響。不適合需要亞毫米級高精度測量的場合。測量對象對平坦、堅硬的表面反射效果最好。對棉花、泡沫等吸音材料或角度過大的斜面可能無法測距或誤差極大。環境干擾多個超聲波模塊同時工作可能互相干擾。嘈雜的聲學環境也可能影響測量。非接觸式只能測量傳感器正前方障礙物的距離無法識別物體材質、形狀。重要提醒本項目用于學習和功能驗證。若用于實際產品需考慮更專業的傳感器、溫度補償算法以及嚴格的電磁兼容和安全設計。3. 環境準備與前置條件在開始編程和接線之前請確保你已準備好以下軟硬件環境。硬件清單STM32L432KC 開發板一塊如 NUCLEO-L432KC。HC-SR04 超聲波模塊一個。杜邦線若干母對母、公對母根據開發板接口而定。USB 數據線一根用于給開發板供電和程序下載/調試。PC 電腦一臺。(可選) 邏輯電平轉換模塊如果開發板只有3.3V電平而你的HC-SR04是5V邏輯版本則需要一個5V轉3.3V的電平轉換器用于Echo回波信號線。軟件清單集成開發環境 (IDE)STM32CubeIDE 或 Keil MDK (uVision)。本文以 STM32CubeIDE 為例因為它集成了STM32CubeMX圖形化配置工具對新手更友好。串口調試助手如 Putty、SecureCRT、或者 IDE 自帶的串口終端。用于查看測距結果。STM32CubeProgrammer用于程序燒錄STM32CubeIDE 已集成燒錄功能可備用。4. 硬件連接與電路原理HC-SR04 模塊通常有 4 個引腳VCC、Trig (觸發)、Echo (回波)、GND。連接示意圖如下HC-SR04 STM32L432KC NUCLEO 板 VCC ----------- 5V 或 3.3V 引腳 (注意模塊電壓) Trig ----------- 任意 GPIO 輸出引腳 (如 PA5) Echo ----------- 任意 GPIO 輸入引腳 (如 PA6) GND ----------- GND關鍵連接說明VCC 與 GND為模塊供電。務必確認你的 HC-SR04 模塊的工作電壓。老版本多為5V新版本有3.3V/5V兼容的。如果是5V模塊接到開發板的5V引腳如果是3.3V模塊接到3.3V引腳。NUCLEO-L432KC 板上有標注的 5V (VIN) 和 3.3V (3V3) 輸出。Trig (觸發)連接到一個配置為推挽輸出的 GPIO 引腳。STM32 通過向此引腳發送一個至少 10us 的高電平脈沖來觸發模塊發射超聲波。Echo (回波)連接到一個配置為浮空輸入或上拉輸入的 GPIO 引腳。該引腳在模塊接收到回波后會輸出一個高電平脈沖其寬度與距離成正比。這是最需要注意的地方如果 HC-SR04 是 5V 邏輯輸出而 STM32L432KC 的 GPIO 引腳只能容忍 3.3V則必須通過電平轉換電路如分壓電阻或電平轉換芯片將 5V 降至 3.3V 后再接入 PA6否則可能損壞 MCU如果是 3.3V 邏輯的模塊則可以直接連接。電平轉換簡易方案針對5V Echo信號使用兩個電阻組成分壓電路Echo 信號先串聯一個 1kΩ 電阻然后連接到 STM32 的 GPIO同時在 GPIO 引腳與 GND 之間并聯一個 2kΩ 電阻。這樣可以將 ~5V 電壓分壓到 ~3.3V。5. STM32CubeMX 工程配置我們使用 STM32CubeMX 進行圖形化配置生成初始化代碼框架。創建新工程打開 STM32CubeIDE選擇 “Start new STM32 project”搜索并選擇 MCU 型號 “STM32L432KCUx”。配置系統時鐘 (SYS)在 “Pinout Configuration” 標簽頁左側找到 “System Core” - “SYS”。將 “Debug” 設置為 “Serial Wire” (這是 ST-LINK 調試接口所需)。配置時鐘樹 (RCC)找到 “RCC”。將 “High Speed Clock (HSE)” 設置為 “Crystal/Ceramic Resonator”。如果板載外部高速晶振。進入 “Clock Configuration” 標簽頁。輸入 HSE 頻率如 8MHz然后通過 PLL 將系統時鐘 (SYSCLK) 配置到最高 80MHz。APB1 和 APB2 總線時鐘也會自動配置。配置 GPIO 引腳在芯片引腳圖上找到你計劃使用的引腳例如 PA5 和 PA6。單擊 PA5選擇 “GPIO_Output”。在左側的 GPIO 配置中可以設置用戶標簽為 “TRIG”。單擊 PA6選擇 “GPIO_Input”。用戶標簽設置為 “ECHO”。根據是否需要內部上拉在 GPIO 設置中選擇 “Pull-up” 或 “No pull-up and no pull-down”。配置定時器 (TIM) 用于高精度計時超聲波測距需要微秒級的時間測量。我們將使用一個通用定時器如 TIM2的輸入捕獲功能或者更簡單的方式在代碼中利用定時器的計數器直接計算時間。這里我們采用定時器中斷計數器讀取的方式更直觀。找到 “TIM2”或其他空閑的通用定時器。在 “Parameter Settings” 中Prescaler (PSC) 設置為 80-1。如果系統時鐘是80MHz分頻后計數器時鐘為 1MHz (1us計數一次)。Counter Period (ARR) 設置為 65535-1 (16位定時器的最大值) 或更大值如果定時器是32位。Counter Mode Up。auto-reload preload Disable。在 “NVIC Settings” 中不要使能定時器中斷。我們只用它的計數器。配置串口 (USART) 用于輸出找到 “USART2”NUCLEO板通常通過 ST-LINK 的虛擬串口連接到 USART2。將 “Mode” 設置為 “Asynchronous”。在 “Parameter Settings” 中波特率設置為 115200 Bits/s其他默認8位數據無校驗1停止位。引腳 PA2 和 PA3 會自動配置為 USART_TX 和 USART_RX。生成工程代碼轉到 “Project Manager” 標簽頁。設置 “Project Name” 和 “Project Location”。“Toolchain / IDE” 選擇 “STM32CubeIDE”。點擊 “Generate Code”。6. 核心代碼編寫與解析工程生成后我們主要在main.c和stm32l4xx_it.c如果用到中斷中添加業務邏輯。6.1 宏定義與全局變量在main.c的/* USER CODE BEGIN PV */區域定義引腳和變量。/* USER CODE BEGIN PV */ // 超聲波模塊引腳定義 (根據你的實際連接修改) #define TRIG_PIN GPIO_PIN_5 #define TRIG_PORT GPIOA #define ECHO_PIN GPIO_PIN_6 #define ECHO_PORT GPIOA // 聲速定義 (單位厘米/微秒)在20°C干燥空氣中約為 0.0343 cm/us #define SOUND_SPEED_CM_US 0.0343 // 也可以定義為 34300 cm/s然后在計算時轉換時間單位 volatile uint32_t pulse_start 0; volatile uint32_t pulse_end 0; volatile uint8_t echo_received 0; float distance_cm 0; /* USER CODE END PV */6.2 超聲波觸發與回波捕獲函數在/* USER CODE BEGIN 0 */區域編寫驅動函數。/* USER CODE BEGIN 0 */ #include stdio.h // 用于 printf // 微秒級延時函數簡易實現精度受系統時鐘和優化影響用于觸發脈沖 void Delay_us(uint16_t us) { uint32_t ticks us * (SystemCoreClock / 1000000) / 5; // 粗略計算循環次數 while(ticks--) { __NOP(); } } // 發送觸發脈沖 void Ultrasonic_Trigger(void) { HAL_GPIO_WritePin(TRIG_PORT, TRIG_PIN, GPIO_PIN_SET); // 拉高 Trig Delay_us(12); // 保持高電平至少10us這里給12us HAL_GPIO_WritePin(TRIG_PORT, TRIG_PIN, GPIO_PIN_RESET); // 拉低 Trig } // 獲取高電平脈沖寬度單位微秒 // 方法輪詢等待 Echo 引腳上升沿和下降沿利用定時器計數器計算時間差。 uint32_t Get_Pulse_Width_us(void) { uint32_t start_time 0, end_time 0; uint32_t timeout 0; // 等待 Echo 變為高電平 (上升沿) timeout 100000; // 超時計數防止死等 while (HAL_GPIO_ReadPin(ECHO_PORT, ECHO_PIN) GPIO_PIN_RESET) { if (timeout-- 0) return 0; // 超時返回0 } start_time __HAL_TIM_GET_COUNTER(htim2); // 記錄定時器當前值 // 等待 Echo 變為低電平 (下降沿) timeout 100000; while (HAL_GPIO_ReadPin(ECHO_PORT, ECHO_PIN) GPIO_PIN_SET) { if (timeout-- 0) return 0; // 超時返回0 } end_time __HAL_TIM_GET_COUNTER(htim2); // 計算時間差 (us)因為定時器時鐘是1MHz // 注意處理定時器溢出的情況簡單項目可暫不考慮或確保測量距離內不會溢出 if (end_time start_time) { return (end_time - start_time); } else { // 計數器溢出計算溢出后的值 return (0xFFFFFFFF - start_time end_time); // 假設是32位定時器 } } // 重定向 printf 到串口 (方便打印) int _write(int file, char *ptr, int len) { HAL_UART_Transmit(huart2, (uint8_t*)ptr, len, HAL_MAX_DELAY); return len; } /* USER CODE END 0 */6.3 主循環邏輯在main()函數的while (1)循環中添加測距和打印邏輯。/* USER CODE BEGIN WHILE */ HAL_TIM_Base_Start(htim2); // 啟動定時器2計數器 printf(Ultrasonic Ranging System Started.\r\n); while (1) { Ultrasonic_Trigger(); // 發送觸發脈沖 HAL_Delay(60); // 等待至少60ms防止發射信號對回波的干擾 uint32_t pulse_width Get_Pulse_Width_us(); // 獲取高電平時間微秒 if (pulse_width 0) { // 計算距離距離 (時間 * 聲速) / 2 // 時間單位是 us聲速是 cm/us除以2是因為聲音走了來回兩倍路程 distance_cm (pulse_width * SOUND_SPEED_CM_US) / 2.0; printf(Pulse Width: %lu us, Distance: %.2f cm\r\n, pulse_width, distance_cm); } else { printf(Measurement timeout or error.\r\n); } HAL_Delay(200); // 主循環延時控制測量頻率 } /* USER CODE END WHILE */7. 功能測試與效果驗證編譯與下載在 STM32CubeIDE 中點擊 “Build” 按鈕編譯工程。使用 USB 線連接開發板點擊 “Debug” 按鈕將程序下載到 MCU 并進入調試模式或直接點擊 “Run” 運行。串口監視退出調試模式如果進入了。在 IDE 的 “Window” - “Show View” - “Other…” 中搜索 “Serial Monitor” 并打開。或者在電腦上打開獨立的串口調試助手如 Putty。選擇正確的串口號在設備管理器中查看 STM32 ST-LINK 虛擬串口的 COM 號。設置波特率為 115200數據位 8停止位 1無校驗無流控。連接串口。觀察結果將超聲波傳感器模塊正面朝向空曠處或一個固定距離的物體如墻壁。觀察串口終端輸出的信息。你應該能看到類似以下的輸出Ultrasonic Ranging System Started. Pulse Width: 588 us, Distance: 10.09 cm Pulse Width: 588 us, Distance: 10.09 cm ...改變傳感器與物體之間的距離輸出值應相應變化。校準與優化基準測試用一個卷尺測量實際距離與串口輸出的距離對比。計算誤差。調整聲速SOUND_SPEED_CM_US常量是基于 20°C 空氣的。如果環境溫度差異大可以根據公式V 331.4 0.6 * T(m/s T為攝氏溫度) 重新計算并更新該常量。處理異常值在實際應用中可以連續測量多次然后取中值或平均值以濾除偶然的干擾脈沖。檢查超時如果總是測量超時檢查 Echo 引腳連接、電平轉換是否正確以及Get_Pulse_Width_us函數中的超時值是否合理。8. 資源占用與性能觀察CPU 占用主循環中主要的耗時操作是HAL_Delay(200)即每 200ms 測量一次CPU 大部分時間處于空閑或低功耗狀態。Get_Pulse_Width_us函數中的輪詢等待會短暫占用 CPU。對于 STM32L432KC 來說負載極低。定時器資源我們占用了一個通用定時器 (TIM2) 作為高精度時鐘源。它被配置為自由運行模式不產生中斷只提供計數器值。GPIO 資源占用兩個 GPIO 引腳。USART 資源占用一個 USART 用于調試輸出。內存占用代碼量小全局變量少對 RAM 和 Flash 的占用可忽略不計。功耗STM32L432KC 本身是超低功耗 MCUHC-SR04 模塊在非觸發狀態下功耗也很低。整個系統非常適合電池供電的便攜設備。性能提升方向使用定時器的輸入捕獲中斷來測量 Echo 高電平寬度可以更精確且不阻塞 CPU。使用 DMA 傳輸串口數據進一步降低 CPU 干預。實現溫度傳感器 (如 DS18B20) 實時補償聲速。9. 常見問題與排查方法問題現象可能原因排查方式解決方案串口無任何輸出1. 串口線未連接或端口錯誤。2. 波特率設置錯誤。3. 代碼未成功運行。1. 檢查設備管理器中的串口號。2. 確認串口助手波特率為115200。3. 檢查程序是否下載成功MCU是否復位。1. 選擇正確的COM口。2. 雙方波特率保持一致。3. 重新下載程序按復位鍵。串口一直輸出 “Measurement timeout or error.”1. Echo 引腳始終為低電平。2. 觸發信號未發出。3. 模塊供電不足或損壞。4. 物體超出測距范圍或表面不反射。1. 用邏輯分析儀或示波器檢查 Trig 和 Echo 信號。2. 用萬用表測量 VCC 和 GND 電壓。3. 將模塊對準近距離的平整墻壁測試。1. 檢查 Trig/Echo 連線確認電平轉換電路如果需要。2. 確保供電電壓符合模塊要求5V或3.3V。3. 更換模塊測試。測量距離固定不變或明顯錯誤1. 聲速常量設置錯誤。2. 定時器分頻系數計算錯誤導致時間單位不對。3. 測量對象是軟質或斜面。1. 用尺子測量一個固定距離如20.0cm對比輸出反推實際聲速或時間系數。2. 檢查Get_Pulse_Width_us函數返回的時間值是否合理。1. 根據實測結果校準SOUND_SPEED_CM_US或計算時的系數。2. 檢查定時器時鐘配置確認計數器加1是否代表1us。3. 對硬質平面進行測量。測量值跳動大不穩定1. 環境噪聲干擾。2. 電源紋波大。3. 軟件中沒有濾波算法。觀察多次測量的原始脈沖寬度值。1. 在軟件中實現多次測量取中值或平均值濾波。2. 為模塊電源增加濾波電容。3. 避免在嘈雜的聲學環境中使用。程序下載失敗1. 調試器連接問題。2. 芯片被寫保護。1. 檢查 USB 線、驅動。2. 查看 IDE 中的調試配置。1. 重新插拔 USB 線重啟 IDE。2. 使用 STM32CubeProgrammer 連接并解除保護。10. 最佳實踐與擴展建議最佳實踐首次上電先不接 Echo 線用示波器或邏輯分析儀觀察 Trig 引腳是否有正確的 10us 以上脈沖。這是確認 MCU 控制邏輯正確的第一步。電平安全始終將“5V Echo 信號連接至 3.3V MCU”作為重點檢查項務必使用電平轉換或分壓電路。電源去耦在 HC-SR04 的 VCC 和 GND 引腳附近并聯一個 10uF 電解電容和一個 0.1uF 陶瓷電容以穩定電源減少干擾。軟件濾波在產品代碼中務必實現軟件濾波。例如連續采樣 5 次去掉最大最小值后求平均能極大提升讀數穩定性。錯誤處理增加對超長回波超出量程、超短回波低于最小測距的判斷和處理。擴展建議增加顯示將距離值顯示在 LCD 屏如 OLED或數碼管上做成一個獨立的測距儀。報警功能設置一個距離閾值當測量值低于該閾值時讓一個 LED 閃爍或蜂鳴器鳴叫實現簡易報警器。多傳感器使用多個超聲波模塊通過 GPIO 分時復用或不同的定時器通道實現多方向測距用于機器人環境感知。無線傳輸通過藍牙模塊 (如 HC-05) 或 WiFi 模塊 (如 ESP8266) 將距離數據發送到手機或云端。低功耗優化利用 STM32L4 的低功耗模式讓 MCU 在兩次測量之間進入 Sleep 或 Stop 模式HC-SR04 模塊也只在測量時上電大幅延長電池壽命。這個基于 STM32L432KC 的超聲波測距項目麻雀雖小五臟俱全。它串聯了 GPIO 控制、定時器計時、串口通信等嵌入式核心知識點。通過動手實現它你不僅能得到一個可工作的測距工具更能透徹理解傳感器與控制器的交互方式。建議在成功實現基礎功能后嘗試上述一兩個擴展功能這對提升工程能力非常有幫助。