stm32f407超声波测距hal 非模块
时间: 2025-07-11 17:07:05 浏览: 8
在 STM32F407 微控制器上使用 HAL 库实现超声波测距功能而不依赖模块化代码,需要手动编写底层驱动逻辑。以下是一个详细的实现方案:
### 硬件配置
HC-SR04 模块的基本工作原理是通过发送 10μs 的触发脉冲来启动一次测距操作,然后模块会自动发出 8 个 40kHz 的超声波信号,并等待回波返回。当接收到回波时,模块的 Echo 引脚输出一个高电平,其持续时间对应于从发射到接收的时间差。
- **Trig(触发)引脚**:连接至任意 GPIO 输出口(例如 `GPIO_PIN_5` 在 `GPIOA` 上)。
- **Echo(回波)引脚**:连接至支持输入捕获的定时器通道(例如 `TIM2_CH1` 对应 `GPIOA_PIN_0`)[^2]。
### 软件实现步骤
#### 1. 初始化 Trig 引脚
将 Trig 引脚配置为推挽输出模式,并初始化为低电平状态。
```c
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
```
#### 2. 初始化 Echo 引脚与定时器
选择一个定时器(如 `TIM2`)并配置为输入捕获模式,用于测量 Echo 引脚的高电平持续时间。
```c
htim2.Instance = TIM2;
htim2.Init.Prescaler = 83; // 84MHz / (83 + 1) = 1MHz
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 0xFFFFFFFF;
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
```
#### 3. 发送触发信号
在 Trig 引脚上生成一个 10μs 的高电平脉冲以触发 HC-SR04 测距操作。
```c
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
usDelay(10); // 使用微秒级延时函数
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
```
#### 4. 捕获回波信号
使用定时器中断捕获 Echo 引脚的上升沿和下降沿,计算出高电平持续时间。
```c
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
static uint32_t rise_time = 0;
static uint32_t fall_time = 0;
static uint8_t state = 0;
if (htim == &htim2)
{
if (state == 0)
{
rise_time = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
state = 1;
}
else
{
fall_time = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
state = 0;
uint32_t pulse_width = fall_time - rise_time;
float distance = (pulse_width * 0.034) / 2; // 单位 cm
}
}
}
```
#### 5. 计算距离
根据公式 `distance = (time × speed_of_sound) / 2` 计算目标的距离,其中声速约为 340m/s 或 0.034cm/μs。
---
### 注意事项
- **定时器精度**:确保定时器的预分频值设置正确,以获得精确的时间测量能力。
- **中断处理**:必须启用定时器的中断并正确配置 NVIC。
- **去抖动**:可能需要对 Echo 输入进行软件或硬件去抖动处理。
- **电源管理**:确保 HC-SR04 模块供电稳定,避免因电压波动导致测量误差。
---
### 示例代码片段
以下是一个完整的超声波测距程序框架:
```c
#include "main.h"
TIM_HandleTypeDef htim2;
uint32_t rise_time = 0, fall_time = 0;
uint8_t edge_detected = 0;
float distance = 0.0f;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM2_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM2_Init();
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
while (1)
{
// 触发测距
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
HAL_Delay(10);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
// 延迟一段时间再进行下一次测量
HAL_Delay(500);
}
}
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if (htim == &htim2)
{
if (edge_detected == 0)
{
rise_time = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
edge_detected = 1;
__HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING);
}
else
{
fall_time = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
edge_detected = 0;
__HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING);
uint32_t pulse_width = fall_time - rise_time;
distance = (pulse_width * 0.034f) / 2.0f;
}
}
}
static void MX_TIM2_Init(void)
{
TIM_IC_InitTypeDef sConfigIC;
htim2.Instance = TIM2;
htim2.Init.Prescaler = 83;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 0xFFFFFFFF;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_IC_Start(&htim2, &sConfigIC, TIM_CHANNEL_1);
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
}
```
---
###
阅读全文
相关推荐


















