STM32实战案例:基于HC-SR04的超声波测距与倒车雷达系统

文章目录

    • 一、前言
      • [1.1 技术背景](#1.1 技术背景)
      • [1.2 本文目标](#1.2 本文目标)
      • [1.3 技术栈](#1.3 技术栈)
    • 二、环境准备
      • [2.1 硬件连接](#2.1 硬件连接)
      • [2.2 STM32CubeMX配置](#2.2 STM32CubeMX配置)
        • [2.2.1 GPIO配置](#2.2.1 GPIO配置)
        • [2.2.2 定时器配置](#2.2.2 定时器配置)
        • [2.2.3 I2C配置](#2.2.3 I2C配置)
    • 三、核心实现
      • [3.1 项目文件结构](#3.1 项目文件结构)
      • [3.2 HC-SR04驱动实现](#3.2 HC-SR04驱动实现)
      • [3.3 倒车雷达系统实现](#3.3 倒车雷达系统实现)
      • [3.4 蜂鸣器控制](#3.4 蜂鸣器控制)
      • [3.5 主程序实现](#3.5 主程序实现)
    • 四、系统流程
      • [4.1 测距流程图](#4.1 测距流程图)
    • 五、测试验证
      • [5.1 单传感器测试](#5.1 单传感器测试)
      • [5.2 多传感器测试](#5.2 多传感器测试)
      • [5.3 报警功能测试](#5.3 报警功能测试)
    • 六、故障排查
      • [6.1 测距不准确](#6.1 测距不准确)
      • [6.2 捕获失败](#6.2 捕获失败)
      • [6.3 多传感器干扰](#6.3 多传感器干扰)
    • 七、总结
      • [7.1 核心知识点](#7.1 核心知识点)
      • [7.2 扩展方向](#7.2 扩展方向)
      • [7.3 学习资源](#7.3 学习资源)

一、前言

1.1 技术背景

超声波测距技术广泛应用于倒车雷达、机器人避障、液位检测等场景。HC-SR04是一款经济实用的超声波测距模块,测量范围2cm-400cm,精度可达3mm,通过简单的触发和回响信号即可完成测距。

超声波测距原理:

  1. 发送40kHz超声波脉冲
  2. 超声波遇到障碍物反射回来
  3. 接收回响信号
  4. 根据时间差计算距离:距离 = (声速 × 时间) / 2

本文将实现一个完整的倒车雷达系统,包括多传感器测距、蜂鸣器报警、OLED显示、LED指示等功能。

1.2 本文目标

通过本文,你将学习到:

  • HC-SR04超声波模块的工作原理
  • STM32定时器捕获功能的使用
  • 多传感器轮询测距策略
  • 分级报警逻辑设计
  • 系统集成与优化

完成本文学习后,你将能够构建一个实用的倒车雷达系统,可直接应用于智能小车、机器人等项目。

1.3 技术栈

硬件平台:

  • 主控:STM32F103C8T6(Blue Pill)
  • 传感器:HC-SR04超声波模块 × 4(前后左右)
  • 显示:0.96寸OLED(I2C)
  • 报警:蜂鸣器、LED × 4
  • 调试:ST-Link V2

软件环境:

  • IDE:STM32CubeIDE 1.13.0+
  • 固件库:STM32CubeF1 HAL库
  • 算法:中值滤波、卡尔曼滤波(可选)

二、环境准备

2.1 硬件连接

HC-SR04与STM32连接(以前方传感器为例):

HC-SR04引脚 STM32引脚 说明
VCC 5V 供电
GND GND
Trig PA0 触发信号(输出)
Echo PA1 (TIM2_CH2) 回响信号(输入捕获)

多传感器连接:

位置 Trig引脚 Echo引脚
前方 PA0 PA1 (TIM2_CH2)
后方 PA2 PA3 (TIM2_CH4)
左侧 PB0 PB1 (TIM3_CH4)
右侧 PB6 PB7 (TIM4_CH2)

蜂鸣器与LED:

  • 蜂鸣器 → PB8(PWM输出)
  • LED1(前) → PC13
  • LED2(后) → PC14
  • LED3(左) → PC15
  • LED4(右) → PB9

2.2 STM32CubeMX配置

2.2.1 GPIO配置

Trig引脚(输出):

  • PA0, PA2, PB0, PB6:GPIO_Output

Echo引脚(输入捕获):

  • PA1, PA3, PB1, PB7:配置为对应定时器通道
2.2.2 定时器配置

TIM2(前后传感器):

  • Clock Source:Internal Clock
  • Prescaler:71(1MHz计数频率)
  • Counter Period:65535
  • Channel2(PA1):Input Capture direct mode
  • Channel4(PA3):Input Capture direct mode

TIM3(左侧传感器):

  • 配置同TIM2
  • Channel4(PB1):Input Capture direct mode

TIM4(右侧传感器):

  • 配置同TIM2
  • Channel2(PB7):Input Capture direct mode

TIM1(蜂鸣器PWM):

  • Prescaler:71
  • Counter Period:999(1kHz PWM)
  • Channel1:PWM Generation CH1
2.2.3 I2C配置

I2C1(OLED):

  • Speed Mode:Fast Mode(400kHz)

三、核心实现

3.1 项目文件结构

复制代码
UltrasonicRadar/
├── Core/
│   ├── Inc/
│   │   ├── main.h
│   │   ├── hcsr04.h
│   │   ├── radar.h
│   │   ├── oled.h
│   │   └── buzzer.h
│   └── Src/
│       ├── main.c
│       ├── hcsr04.c
│       ├── radar.c
│       ├── oled.c
│       └── buzzer.c

3.2 HC-SR04驱动实现

📄 创建文件:Core/Inc/hcsr04.h

c 复制代码
/**
 * @file hcsr04.h
 * @brief HC-SR04超声波测距模块驱动头文件
 * 
 * 功能:
 * - 触发测距
 * - 捕获回响信号
 * - 计算距离
 * - 数据滤波
 */

#ifndef __HCSR04_H
#define __HCSR04_H

#include "main.h"
#include <stdint.h>
#include <stdbool.h>

/* ===================== 配置参数 ===================== */

#define HCSR04_TIMEOUT      30000   // 超时时间(us),对应最大距离约5m
#define SOUND_SPEED         340.0f  // 声速(m/s),20℃时
#define HCSR04_MAX_DISTANCE 400     // 最大测量距离(cm)
#define HCSR04_MIN_DISTANCE 2       // 最小测量距离(cm)

/* ===================== 传感器位置枚举 ===================== */

typedef enum {
    SENSOR_FRONT = 0,   // 前方
    SENSOR_REAR,        // 后方
    SENSOR_LEFT,        // 左侧
    SENSOR_RIGHT,       // 右侧
    SENSOR_COUNT        // 传感器总数
} HCSR04_Position_t;

/* ===================== 数据结构 ===================== */

/**
 * @brief 传感器配置结构
 */
typedef struct {
    GPIO_TypeDef *trig_port;    // Trig引脚端口
    uint16_t trig_pin;          // Trig引脚号
    TIM_HandleTypeDef *htim;    // 定时器句柄
    uint32_t channel;           // 定时器通道
} HCSR04_Config_t;

/**
 * @brief 测距数据结构
 */
typedef struct {
    uint16_t distance_cm;       // 距离(cm)
    uint32_t capture_time;      // 捕获时间(us)
    bool valid;                 // 数据有效标志
    uint32_t timestamp;         // 时间戳
} HCSR04_Data_t;

/* ===================== 函数声明 ===================== */

/**
 * @brief 初始化HC-SR04
 */
void HCSR04_Init(void);

/**
 * @brief 触发测距
 * @param position 传感器位置
 */
void HCSR04_Trigger(HCSR04_Position_t position);

/**
 * @brief 读取距离
 * @param position 传感器位置
 * @retval uint16_t 距离(cm),0表示无效
 */
uint16_t HCSR04_ReadDistance(HCSR04_Position_t position);

/**
 * @brief 获取测距数据
 * @param position 传感器位置
 * @param data 输出数据结构
 * @retval bool 成功返回true
 */
bool HCSR04_GetData(HCSR04_Position_t position, HCSR04_Data_t *data);

/**
 * @brief 输入捕获回调(在定时器中断中调用)
 * @param htim 定时器句柄
 */
void HCSR04_CaptureCallback(TIM_HandleTypeDef *htim);

#endif /* __HCSR04_H */

📄 创建文件:Core/Src/hcsr04.c

c 复制代码
/**
 * @file hcsr04.c
 * @brief HC-SR04超声波测距模块驱动实现
 */

#include "hcsr04.h"
#include "tim.h"
#include <stdio.h>

/* ===================== 私有变量 ===================== */

// 传感器配置表
static const HCSR04_Config_t sensor_config[SENSOR_COUNT] = {
    // 前方传感器
    {GPIOA, GPIO_PIN_0, &htim2, TIM_CHANNEL_2},
    // 后方传感器
    {GPIOA, GPIO_PIN_2, &htim2, TIM_CHANNEL_4},
    // 左侧传感器
    {GPIOB, GPIO_PIN_0, &htim3, TIM_CHANNEL_4},
    // 右侧传感器
    {GPIOB, GPIO_PIN_6, &htim4, TIM_CHANNEL_2}
};

// 测距数据
static HCSR04_Data_t sensor_data[SENSOR_COUNT];

// 捕获状态
static volatile bool capture_started[SENSOR_COUNT] = {false};
static volatile uint32_t capture_value1[SENSOR_COUNT] = {0};
static volatile uint32_t capture_value2[SENSOR_COUNT] = {0};

/* ===================== 私有函数 ===================== */

/**
 * @brief 根据定时器和通道获取传感器索引
 */
static int8_t GetSensorIndex(TIM_HandleTypeDef *htim, uint32_t channel)
{
    for (uint8_t i = 0; i < SENSOR_COUNT; i++) {
        if (sensor_config[i].htim == htim && sensor_config[i].channel == channel) {
            return i;
        }
    }
    return -1;
}

/**
 * @brief 中值滤波(3个样本)
 */
static uint16_t MedianFilter(uint16_t *samples, uint8_t count)
{
    // 简单冒泡排序
    for (uint8_t i = 0; i < count - 1; i++) {
        for (uint8_t j = 0; j < count - i - 1; j++) {
            if (samples[j] > samples[j + 1]) {
                uint16_t temp = samples[j];
                samples[j] = samples[j + 1];
                samples[j + 1] = temp;
            }
        }
    }
    return samples[count / 2];  // 返回中值
}

/* ===================== 公有函数实现 ===================== */

/**
 * @brief 初始化HC-SR04
 */
void HCSR04_Init(void)
{
    printf("[HCSR04] 初始化中...\r\n");
    
    // 初始化数据结构
    for (uint8_t i = 0; i < SENSOR_COUNT; i++) {
        sensor_data[i].distance_cm = 0;
        sensor_data[i].capture_time = 0;
        sensor_data[i].valid = false;
        sensor_data[i].timestamp = 0;
        
        capture_started[i] = false;
        capture_value1[i] = 0;
        capture_value2[i] = 0;
    }
    
    // 启动输入捕获
    HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_2);
    HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_4);
    HAL_TIM_IC_Start_IT(&htim3, TIM_CHANNEL_4);
    HAL_TIM_IC_Start_IT(&htim4, TIM_CHANNEL_2);
    
    printf("[HCSR04] 初始化完成\r\n");
}

/**
 * @brief 触发测距
 */
void HCSR04_Trigger(HCSR04_Position_t position)
{
    if (position >= SENSOR_COUNT) {
        return;
    }
    
    const HCSR04_Config_t *config = &sensor_config[position];
    
    // 重置捕获状态
    capture_started[position] = false;
    capture_value1[position] = 0;
    capture_value2[position] = 0;
    
    // 发送10us高电平触发信号
    HAL_GPIO_WritePin(config->trig_port, config->trig_pin, GPIO_PIN_SET);
    HAL_Delay_us(10);  // 需要实现微秒延时
    HAL_GPIO_WritePin(config->trig_port, config->trig_pin, GPIO_PIN_RESET);
}

/**
 * @brief 读取距离
 */
uint16_t HCSR04_ReadDistance(HCSR04_Position_t position)
{
    if (position >= SENSOR_COUNT) {
        return 0;
    }
    
    // 触发测距
    HCSR04_Trigger(position);
    
    // 等待捕获完成(最多等待50ms)
    uint32_t start_time = HAL_GetTick();
    while (!sensor_data[position].valid && (HAL_GetTick() - start_time) < 50) {
        HAL_Delay(1);
    }
    
    if (sensor_data[position].valid) {
        return sensor_data[position].distance_cm;
    }
    
    return 0;  // 超时或无效
}

/**
 * @brief 获取测距数据
 */
bool HCSR04_GetData(HCSR04_Position_t position, HCSR04_Data_t *data)
{
    if (position >= SENSOR_COUNT || data == NULL) {
        return false;
    }
    
    *data = sensor_data[position];
    return data->valid;
}

/**
 * @brief 输入捕获回调
 * 
 * 工作流程:
 * 1. 第一次捕获:上升沿,记录起始时间
 * 2. 第二次捕获:下降沿,记录结束时间
 * 3. 计算时间差,转换为距离
 */
void HCSR04_CaptureCallback(TIM_HandleTypeDef *htim)
{
    // 判断是哪个通道触发
    uint32_t channel = 0;
    if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2) {
        channel = TIM_CHANNEL_2;
    } else if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4) {
        channel = TIM_CHANNEL_4;
    } else {
        return;
    }
    
    // 获取传感器索引
    int8_t index = GetSensorIndex(htim, channel);
    if (index < 0) {
        return;
    }
    
    if (!capture_started[index]) {
        // 第一次捕获:上升沿
        capture_value1[index] = HAL_TIM_ReadCapturedValue(htim, channel);
        capture_started[index] = true;
        
        // 切换为下降沿捕获
        __HAL_TIM_SET_CAPTUREPOLARITY(htim, channel, TIM_INPUTCHANNELPOLARITY_FALLING);
    } else {
        // 第二次捕获:下降沿
        capture_value2[index] = HAL_TIM_ReadCapturedValue(htim, channel);
        capture_started[index] = false;
        
        // 计算时间差(us)
        uint32_t time_diff;
        if (capture_value2[index] > capture_value1[index]) {
            time_diff = capture_value2[index] - capture_value1[index];
        } else {
            // 定时器溢出
            time_diff = (0xFFFF - capture_value1[index]) + capture_value2[index];
        }
        
        // 计算距离(cm)
        // 距离 = (声速 * 时间) / 2
        // 声速 = 340 m/s = 0.034 cm/us
        float distance = (time_diff * 0.034f) / 2.0f;
        
        // 数据有效性检查
        if (distance >= HCSR04_MIN_DISTANCE && distance <= HCSR04_MAX_DISTANCE) {
            sensor_data[index].distance_cm = (uint16_t)distance;
            sensor_data[index].capture_time = time_diff;
            sensor_data[index].valid = true;
            sensor_data[index].timestamp = HAL_GetTick();
        } else {
            sensor_data[index].valid = false;
        }
        
        // 切换回上升沿捕获
        __HAL_TIM_SET_CAPTUREPOLARITY(htim, channel, TIM_INPUTCHANNELPOLARITY_RISING);
    }
}

/**
 * @brief 微秒延时(需要在main.c中实现)
 */
__weak void HAL_Delay_us(uint32_t us)
{
    uint32_t start = DWT->CYCCNT;
    uint32_t cycles = us * (SystemCoreClock / 1000000);
    while ((DWT->CYCCNT - start) < cycles);
}

3.3 倒车雷达系统实现

📄 创建文件:Core/Inc/radar.h

c 复制代码
/**
 * @file radar.h
 * @brief 倒车雷达系统头文件
 * 
 * 功能:
 * - 多传感器轮询测距
 * - 分级报警逻辑
 * - 障碍物检测
 */

#ifndef __RADAR_H
#define __RADAR_H

#include "hcsr04.h"

/* ===================== 报警等级 ===================== */

typedef enum {
    ALARM_NONE = 0,     // 无报警(>100cm)
    ALARM_LOW,          // 低级报警(50-100cm)
    ALARM_MEDIUM,       // 中级报警(20-50cm)
    ALARM_HIGH          // 高级报警(<20cm)
} Alarm_Level_t;

/* ===================== 雷达数据结构 ===================== */

typedef struct {
    uint16_t distance[SENSOR_COUNT];    // 各方向距离
    Alarm_Level_t alarm[SENSOR_COUNT];  // 各方向报警等级
    Alarm_Level_t max_alarm;            // 最高报警等级
    uint32_t timestamp;
} Radar_Data_t;

/* ===================== 函数声明 ===================== */

/**
 * @brief 初始化雷达系统
 */
void Radar_Init(void);

/**
 * @brief 更新雷达数据
 */
void Radar_Update(void);

/**
 * @brief 获取雷达数据
 * @param data 输出数据结构
 */
void Radar_GetData(Radar_Data_t *data);

/**
 * @brief 获取报警等级
 * @param distance 距离(cm)
 * @retval Alarm_Level_t
 */
Alarm_Level_t Radar_GetAlarmLevel(uint16_t distance);

#endif /* __RADAR_H */

📄 创建文件:Core/Src/radar.c

c 复制代码
/**
 * @file radar.c
 * @brief 倒车雷达系统实现
 */

#include "radar.h"
#include "buzzer.h"
#include <stdio.h>

/* ===================== 私有变量 ===================== */
static Radar_Data_t radar_data;

/* ===================== 公有函数实现 ===================== */

/**
 * @brief 初始化雷达系统
 */
void Radar_Init(void)
{
    printf("[Radar] 初始化雷达系统\r\n");
    
    HCSR04_Init();
    Buzzer_Init();
    
    for (uint8_t i = 0; i < SENSOR_COUNT; i++) {
        radar_data.distance[i] = 0;
        radar_data.alarm[i] = ALARM_NONE;
    }
    radar_data.max_alarm = ALARM_NONE;
    radar_data.timestamp = 0;
}

/**
 * @brief 更新雷达数据
 */
void Radar_Update(void)
{
    // 轮询读取各传感器
    for (uint8_t i = 0; i < SENSOR_COUNT; i++) {
        uint16_t distance = HCSR04_ReadDistance(i);
        
        if (distance > 0) {
            radar_data.distance[i] = distance;
            radar_data.alarm[i] = Radar_GetAlarmLevel(distance);
        } else {
            radar_data.distance[i] = 0;
            radar_data.alarm[i] = ALARM_NONE;
        }
        
        HAL_Delay(20);  // 传感器间隔20ms,避免干扰
    }
    
    // 确定最高报警等级
    radar_data.max_alarm = ALARM_NONE;
    for (uint8_t i = 0; i < SENSOR_COUNT; i++) {
        if (radar_data.alarm[i] > radar_data.max_alarm) {
            radar_data.max_alarm = radar_data.alarm[i];
        }
    }
    
    radar_data.timestamp = HAL_GetTick();
    
    // 控制蜂鸣器
    Buzzer_SetAlarm(radar_data.max_alarm);
    
    // 打印数据
    printf("[Radar] 前:%3dcm 后:%3dcm 左:%3dcm 右:%3dcm | 报警:%d\r\n",
           radar_data.distance[SENSOR_FRONT],
           radar_data.distance[SENSOR_REAR],
           radar_data.distance[SENSOR_LEFT],
           radar_data.distance[SENSOR_RIGHT],
           radar_data.max_alarm);
}

/**
 * @brief 获取雷达数据
 */
void Radar_GetData(Radar_Data_t *data)
{
    if (data != NULL) {
        *data = radar_data;
    }
}

/**
 * @brief 获取报警等级
 */
Alarm_Level_t Radar_GetAlarmLevel(uint16_t distance)
{
    if (distance == 0 || distance > 100) {
        return ALARM_NONE;
    } else if (distance > 50) {
        return ALARM_LOW;
    } else if (distance > 20) {
        return ALARM_MEDIUM;
    } else {
        return ALARM_HIGH;
    }
}

3.4 蜂鸣器控制

📄 创建文件:Core/Inc/buzzer.h

c 复制代码
/**
 * @file buzzer.h
 * @brief 蜂鸣器控制头文件
 */

#ifndef __BUZZER_H
#define __BUZZER_H

#include "main.h"
#include "radar.h"

/**
 * @brief 初始化蜂鸣器
 */
void Buzzer_Init(void);

/**
 * @brief 设置报警
 * @param level 报警等级
 */
void Buzzer_SetAlarm(Alarm_Level_t level);

/**
 * @brief 蜂鸣器鸣叫
 * @param duration_ms 持续时间(ms)
 */
void Buzzer_Beep(uint16_t duration_ms);

#endif /* __BUZZER_H */

📄 创建文件:Core/Src/buzzer.c

c 复制代码
/**
 * @file buzzer.c
 * @brief 蜂鸣器控制实现
 */

#include "buzzer.h"
#include "tim.h"

/* ===================== 私有变量 ===================== */
static uint32_t last_beep_time = 0;

/**
 * @brief 初始化蜂鸣器
 */
void Buzzer_Init(void)
{
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
    __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 0);  // 初始关闭
}

/**
 * @brief 设置报警
 */
void Buzzer_SetAlarm(Alarm_Level_t level)
{
    uint32_t current_time = HAL_GetTick();
    uint16_t interval = 0;
    
    switch (level) {
        case ALARM_NONE:
            __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 0);  // 关闭
            break;
            
        case ALARM_LOW:
            interval = 1000;  // 1秒间隔
            break;
            
        case ALARM_MEDIUM:
            interval = 500;   // 0.5秒间隔
            break;
            
        case ALARM_HIGH:
            interval = 200;   // 0.2秒间隔
            break;
    }
    
    if (level != ALARM_NONE && (current_time - last_beep_time) >= interval) {
        Buzzer_Beep(100);
        last_beep_time = current_time;
    }
}

/**
 * @brief 蜂鸣器鸣叫
 */
void Buzzer_Beep(uint16_t duration_ms)
{
    __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 500);  // 50%占空比
    HAL_Delay(duration_ms);
    __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 0);
}

3.5 主程序实现

📝 修改文件:Core/Src/main.c

c 复制代码
/**
 * @brief 主函数
 */
int main(void)
{
    HAL_Init();
    SystemClock_Config();
    
    MX_GPIO_Init();
    MX_TIM1_Init();
    MX_TIM2_Init();
    MX_TIM3_Init();
    MX_TIM4_Init();
    MX_I2C1_Init();
    MX_USART1_UART_Init();
    
    // 使能DWT用于微秒延时
    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
    DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
    
    printf("\r\n========================================\r\n");
    printf("  倒车雷达系统\r\n");
    printf("========================================\r\n");
    
    // 初始化雷达系统
    Radar_Init();
    
    // 初始化OLED
    OLED_Init();
    OLED_Clear();
    OLED_ShowString(0, 0, "Parking Radar");
    OLED_Refresh();
    HAL_Delay(2000);
    
    Radar_Data_t radar_data;
    
    while (1)
    {
        // 更新雷达数据
        Radar_Update();
        
        // 获取数据
        Radar_GetData(&radar_data);
        
        // OLED显示
        OLED_Clear();
        
        // 显示各方向距离
        OLED_ShowString(0, 0, "F:");
        OLED_ShowNum(16, 0, radar_data.distance[SENSOR_FRONT], 3);
        OLED_ShowString(40, 0, "cm");
        
        OLED_ShowString(0, 2, "R:");
        OLED_ShowNum(16, 2, radar_data.distance[SENSOR_REAR], 3);
        OLED_ShowString(40, 2, "cm");
        
        OLED_ShowString(0, 4, "L:");
        OLED_ShowNum(16, 4, radar_data.distance[SENSOR_LEFT], 3);
        OLED_ShowString(40, 4, "cm");
        
        OLED_ShowString(0, 6, "R:");
        OLED_ShowNum(16, 6, radar_data.distance[SENSOR_RIGHT], 3);
        OLED_ShowString(40, 6, "cm");
        
        // 显示报警状态
        const char *alarm_str[] = {"SAFE", "WARN", "ALERT", "DANGER"};
        OLED_ShowString(64, 3, alarm_str[radar_data.max_alarm]);
        
        OLED_Refresh();
        
        // 控制LED指示
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, 
                          radar_data.alarm[SENSOR_FRONT] >= ALARM_MEDIUM ? GPIO_PIN_SET : GPIO_PIN_RESET);
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, 
                          radar_data.alarm[SENSOR_REAR] >= ALARM_MEDIUM ? GPIO_PIN_SET : GPIO_PIN_RESET);
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_15, 
                          radar_data.alarm[SENSOR_LEFT] >= ALARM_MEDIUM ? GPIO_PIN_SET : GPIO_PIN_RESET);
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, 
                          radar_data.alarm[SENSOR_RIGHT] >= ALARM_MEDIUM ? GPIO_PIN_SET : GPIO_PIN_RESET);
        
        HAL_Delay(100);
    }
}

/**
 * @brief 定时器输入捕获回调
 */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    HCSR04_CaptureCallback(htim);
}

四、系统流程

4.1 测距流程图



开始
Trig引脚输出10us高电平
HC-SR04发送8个40kHz脉冲
Echo引脚输出高电平
定时器捕获上升沿
记录起始时间T1
超声波遇障碍物反射
Echo引脚变为低电平
定时器捕获下降沿
记录结束时间T2
计算时间差: ΔT = T2 - T1
计算距离: D = ΔT × 0.034 / 2
距离有效?
保存距离数据
标记无效
结束


五、测试验证

5.1 单传感器测试

  1. 在传感器前放置障碍物
  2. 观察串口输出距离值
  3. 用尺子测量实际距离对比

5.2 多传感器测试

  1. 在四个方向分别放置障碍物
  2. 验证各传感器独立工作
  3. 检查是否有相互干扰

5.3 报警功能测试

  1. 逐渐靠近障碍物
  2. 验证蜂鸣器报警频率变化
  3. 验证LED指示灯亮灭

六、故障排查

6.1 测距不准确

原因:

  • 声速受温度影响
  • 障碍物表面不平整
  • 测量角度偏斜

解决:

  • 温度补偿:声速 = 331.5 + 0.6 × 温度(℃)
  • 多次测量取平均值
  • 调整传感器安装角度

6.2 捕获失败

原因:

  • 定时器配置错误
  • 中断未启用
  • Echo信号被干扰

解决:

  • 检查定时器时钟配置
  • 确认中断优先级
  • 增加硬件滤波电容

6.3 多传感器干扰

原因: 超声波信号相互干扰

解决: 增加传感器轮询间隔(20-50ms)


七、总结

7.1 核心知识点

  1. HC-SR04工作原理:触发-回响机制
  2. 定时器输入捕获:测量脉冲宽度
  3. 多传感器管理:轮询策略
  4. 分级报警:距离阈值判断

7.2 扩展方向

  • 温度补偿:集成温度传感器
  • 数据融合:卡尔曼滤波
  • 可视化:图形化显示障碍物位置
  • 语音提示:集成语音模块

7.3 学习资源

官方文档:

相关推荐
华清远见IT开放实验室2 小时前
智能手表完整项目实现,比赛求职双向加分,基于嵌入式大赛推荐开发板(STM32U5)
stm32·单片机·嵌入式硬件·学习·智能手表·嵌入式大赛
BackCatK Chen2 小时前
STM32保姆级入门教程|第8章:PT100高精度测温实战 + ADS1232驱动 + 24位ADC数据解析(功能超详细+CubeIDE手把手)
stm32·stm32cubeide·高精度测温·ads1232·pt100·24位adc·工业实战
危桥带雨2 小时前
FLASH理论基础
stm32·单片机·嵌入式硬件
进击的小头3 小时前
第18篇:嵌入式电机控制专用外设:正交编码脉冲模块原理与闭环控制应用
arm开发·单片机·嵌入式硬件
feifeigo1234 小时前
STM32 LCD彩色液晶屏显示汉字、英文、数字
stm32·单片机·嵌入式硬件
实在太懒于是不想取名5 小时前
STM32N6的开发日记(4):快速上手LTDC显示图片-让屏幕刷新丝滑流畅
stm32·单片机·嵌入式硬件
实在太懒于是不想取名5 小时前
STM32N6的开发日记(1):上手难度拉满的N6有哪些不同?
stm32·单片机·嵌入式硬件
LingLong_roar5 小时前
keil未指定 PY32F0 具体芯片型号导致编译报错及无法烧录问题
单片机·嵌入式硬件
见行AGV机器人7 小时前
AGV中工控机有什么用?
单片机·嵌入式硬件·非标定制agv·agv控制器