STM32超声波模块(HC-SR04)HAL库实战指南
一、工作原理
HC-SR04超声波模块的工作原理(简洁版):
-
触发信号(Trig)
-
向Trig引脚发送 10µs的高电平脉冲,触发模块发射超声波。
-
超声波发射与接收
-
模块自动发射 8个40kHz的超声波脉冲,并等待回波(障碍物反射的超声波)。
-
回波信号(Echo)
-
当模块接收到回波时,Echo引脚输出 高电平脉冲,脉冲宽度与超声波往返时间成正比。
-
距离计算
-
测量Echo高电平时间(记为
t
,单位µs),距离公式:
距离(cm) = (t × 声速) / 2
(声速按340m/s,即 0.0343cm/µs,除以2因时间为往返)
(1)工作原理图
触发信号就是拉高Trig引脚10us,当模块接收到这个信号就会回传超声波,此时Echo引脚被拉高,记录此时的实现为start时间,当Echo引脚被拉低后记录此时的时间为end_time。
二、代码
我们将以STM32F103C8T6,HCSR04,并以HAL库为例展示代码。
首先配置CUBEMX,配置TRGI口为输出模式。开启TIM3的输入捕获功能。
开启TIM3后会自动捕获PB0(ECHO)口的电平变化。并在NVIC中开启TIM3的中断。
代码的具体流程如下图所示:
#ifndef HC_SR04_H
#define HC_SR04_H
#include "stm32f1xx_hal.h"
typedef struct {
TIM_HandleTypeDef *htim; // 定时器句柄
uint16_t trig_pin; // Trig引脚
GPIO_TypeDef *trig_port; // Trig端口
float distance_cm; // 测量距离(cm)
} HC_SR04;
void HC_SR04_Init(HC_SR04 *sensor, TIM_HandleTypeDef *htim, GPIO_TypeDef *trig_port, uint16_t trig_pin);
void HC_SR04_StartMeasurement(HC_SR04 *sensor);
float HC_SR04_GetDistance(HC_SR04 *sensor);
#endif
#include "hc_sr04.h"
volatile uint32_t rising_time = 0;
volatile uint32_t pulse_width = 0;
volatile uint8_t measurement_done = 0;
void HC_SR04_Init(HC_SR04 *sensor, TIM_HandleTypeDef *htim, GPIO_TypeDef *trig_port, uint16_t trig_pin) {
sensor->htim = htim;
sensor->trig_port = trig_port;
sensor->trig_pin = trig_pin;
sensor->distance_cm = 0.0;
HAL_TIM_IC_Start_IT(sensor->htim, TIM_CHANNEL_1); // 启动输入捕获中断
}
void HC_SR04_StartMeasurement(HC_SR04 *sensor) {
// 发送10us高电平触发信号
HAL_GPIO_WritePin(sensor->trig_port, sensor->trig_pin, GPIO_PIN_SET);
delay_us(10); // 10us高电平 触发信号
HAL_GPIO_WritePin(sensor->trig_port, sensor->trig_pin, GPIO_PIN_RESET);
measurement_done = 0;
}
float HC_SR04_GetDistance(HC_SR04 *sensor) {
if (measurement_done) {
// 计算距离(声速340m/s,时间单位为µs)
sensor->distance_cm = (pulse_width * 0.0343) / 2; // 单位cm
measurement_done = 0;
return sensor->distance_cm;
}
return -1.0; // 测量未完成
}
// 定时器输入捕获中断回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) {
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET) { // 上升沿
rising_time = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
__HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING); // 改为下降沿捕获
} else { // 下降沿
uint32_t falling_time = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
pulse_width = falling_time - rising_time;
measurement_done = 1;
__HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING); // 恢复上升沿捕获
}
}
}
实例:
#include "main.h"
#include "hc_sr04.h"
HC_SR04 us_sensor;
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM2_Init();
HC_SR04_Init(&us_sensor, &htim2, GPIOA, GPIO_PIN_1); // Trig引脚PA1
while (1) {
HC_SR04_StartMeasurement(&us_sensor);
HAL_Delay(100); // 测量间隔至少60ms
float distance = HC_SR04_GetDistance(&us_sensor);
if (distance > 0) {
// 通过串口输出距离(需自行实现printf)
printf("Distance: %.2f cm\r\n", distance);
}
}
}
可以用串口打印输出效果。
作者:m0_63127436