超声波传感器一发多收测距系统

超声波传感器一发多收测距系统

一、系统架构设计

1、一发多收拓扑

       发射探头
          │
          ▼
   ┌─────────────┐
   │  超声波束   │
   └──────┬──────┘
          │
    ┌─────┼─────┐
    ▼     ▼     ▼
接收1  接收2  接收3
(Rx1)  (Rx2)  (Rx3)
    │     │     │
    └──┬──┴──┬──┘
       │     │
   时间差Δt1  Δt2
       │     │
   距离解算 → 目标位置

2、系统指标

参数 指标
工作频率 40kHz
探测距离 0.2m ~ 5m
角度覆盖范围 120°
测距精度 ±2cm
响应时间 < 50ms
接收通道 3~8个

二、硬件设计方案

1、核心器件选型

器件 型号 说明
MCU STM32F407ZGT6 168MHz,17个定时器
发射驱动 MAX232/TXS0108E 高压驱动
接收放大 LM358×2级联 带通滤波+放大
超声波探头 TCT40-16T/R 16mm,40kHz
模拟开关 CD4051 多路复用
电平转换 TXS0108E 5V/3.3V

2、发射电路

STM32 PWM ── 74HC04 ── BS170 MOSFET ── 变压器 ── 发射探头
              │
            MAX232 (倍压)

3、接收电路(每个通道)

接收探头 ── 前置放大(LM358) ── 带通滤波(40kHz) ── 比较器 ── STM32
                │
            增益可调(电位器)

三、STM32 资源配置

1、定时器分配

/* 定时器功能分配 */
TIM1 ── 发射PWM(40kHz,8个周期)
TIM2 ── 接收通道1捕获
TIM3 ── 接收通道2捕获  
TIM4 ── 接收通道3捕获
TIM5 ── 系统时间基准
TIM6 ── 采样周期控制

2、GPIO 引脚定义

/* 发射控制 */
#define TRIG_PIN    GPIO_PIN_8
#define TRIG_PORT   GPIOA

/* 接收通道 */
#define ECHO1_PIN   GPIO_PIN_0    // TIM2_CH1
#define ECHO2_PIN   GPIO_PIN_6    // TIM3_CH1  
#define ECHO3_PIN   GPIO_PIN_6    // TIM4_CH1

/* 模拟开关控制 */
#define SEL_A_PIN   GPIO_PIN_12
#define SEL_B_PIN   GPIO_PIN_13
#define SEL_C_PIN   GPIO_PIN_14

四、核心代码实现

1、超声波参数定义

#ifndef ULTRASONIC_H
#define ULTRASONIC_H

#include "stm32f4xx_hal.h"

#define NUM_RECEIVERS       3
#define SOUND_SPEED         340.0f     // 声速 m/s
#define TRIGGER_PULSE_US    10         // 触发脉冲宽度
#define MEASURE_TIMEOUT_MS  50         // 测量超时
#define SAMPLE_RATE_HZ      20         // 采样频率

/* 接收通道结构体 */
typedef struct {
    uint8_t channel_id;               // 通道ID
    uint32_t echo_time_us;            // 回波时间(μs)
    float distance_m;                 // 距离(m)
    uint8_t valid_flag;               // 数据有效性
    uint32_t last_update;             // 最后更新时间
} Receiver_t;

/* 一发多收系统 */
typedef struct {
    Receiver_t receivers[NUM_RECEIVERS];
    uint32_t trigger_time;            // 触发时间
    uint8_t measurement_done;         // 测量完成标志
    float target_x;                  // 目标X坐标
    float target_y;                  // 目标Y坐标
    float confidence;                // 置信度
} Ultrasonic_System_t;

extern Ultrasonic_System_t us_system;

#endif

2、定时器初始化

/* TIM1 - 发射PWM初始化 */
void TIM1_Trigger_Init(void)
{
    TIM_HandleTypeDef htim1;
    TIM_OC_InitTypeDef sConfigOC = {0};
    
    __HAL_RCC_TIM1_CLK_ENABLE();
    
    htim1.Instance = TIM1;
    htim1.Init.Prescaler = 84-1;      // 84MHz/84 = 1MHz
    htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim1.Init.Period = 25-1;         // 40kHz (1MHz/40kHz = 25)
    htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim1.Init.RepetitionCounter = 0;
    HAL_TIM_PWM_Init(&htim1);
    
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = 12;             // 50%占空比
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
    sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
    sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
    
    HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
}

/* 接收通道定时器初始化 */
void TIM_Receiver_Init(void)
{
    TIM_HandleTypeDef htim2, htim3, htim4;
    
    // TIM2_CH1 - 接收通道1
    __HAL_RCC_TIM2_CLK_ENABLE();
    htim2.Instance = TIM2;
    htim2.Init.Prescaler = 84-1;      // 1MHz
    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim2.Init.Period = 0xFFFFFFFF;   // 32位最大计数
    HAL_TIM_IC_Init(&htim2);
    
    TIM_IC_InitTypeDef sConfigIC = {0};
    sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
    sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
    sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
    sConfigIC.ICFilter = 0x0;
    HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1);
    HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
    
    // 类似配置TIM3、TIM4...
}

3、发射控制

/* 发射超声波脉冲 */
void Ultrasonic_Trigger(void)
{
    uint32_t start_time;
    
    // 记录触发时间
    us_system.trigger_time = HAL_GetTick();
    
    // 启动PWM发射
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
    
    // 发射8个周期后停止
    start_time = HAL_GetTick();
    while(HAL_GetTick() - start_time < 1);  // 延迟200μs
    
    HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);
    
    // 重置所有接收通道
    for(int i = 0; i < NUM_RECEIVERS; i++) {
        us_system.receivers[i].valid_flag = 0;
        us_system.receivers[i].echo_time_us = 0;
    }
    
    us_system.measurement_done = 0;
}

4、输入捕获中断处理

/* TIM2输入捕获中断 - 接收通道1 */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    static uint32_t ic_val1[NUM_RECEIVERS] = {0};
    static uint8_t is_first_capture[NUM_RECEIVERS] = {1};
    
    if(htim->Instance == TIM2 && htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) {
        if(is_first_capture[0] == 0) {
            // 第二次捕获(下降沿)
            uint32_t ic_val2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
            uint32_t diff = ic_val2 - ic_val1[0];
            
            us_system.receivers[0].echo_time_us = diff;
            us_system.receivers[0].distance_m = (diff * 0.001f) * SOUND_SPEED / 2.0f;
            us_system.receivers[0].valid_flag = 1;
            us_system.receivers[0].last_update = HAL_GetTick();
            
            is_first_capture[0] = 1;
        } else {
            // 第一次捕获(上升沿)
            ic_val1[0] = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
            is_first_capture[0] = 0;
        }
    }
    
    // 类似处理TIM3、TIM4...
}

5、一发多收距离解算

/* 一发多收位置解算 */
void Multistatic_Position_Estimation(void)
{
    float distances[NUM_RECEIVERS];
    uint8_t valid_count = 0;
    
    // 收集有效距离数据
    for(int i = 0; i < NUM_RECEIVERS; i++) {
        if(us_system.receivers[i].valid_flag &&
           us_system.receivers[i].distance_m > 0.2f &&
           us_system.receivers[i].distance_m < 5.0f) {
            distances[valid_count++] = us_system.receivers[i].distance_m;
        }
    }
    
    if(valid_count < 2) {
        us_system.confidence = 0.0f;
        return;
    }
    
    // 基于时间差的多基站定位算法
    // 简化版本:使用最近的两个接收器进行三角定位
    if(valid_count >= 2) {
        float d1 = distances[0];
        float d2 = distances[1];
        
        // 假设接收器间距已知(例如30cm)
        float receiver_spacing = 0.3f;
        
        // 简化三角定位
        float x = (d1*d1 - d2*d2 + receiver_spacing*receiver_spacing) / 
                  (2 * receiver_spacing);
        float y = sqrt(d1*d1 - x*x);
        
        us_system.target_x = x;
        us_system.target_y = y;
        us_system.confidence = (float)valid_count / NUM_RECEIVERS;
    }
    
    us_system.measurement_done = 1;
}

6、主循环处理

/* 主任务 */
void Ultrasonic_Task(void)
{
    static uint32_t last_trigger = 0;
    uint32_t current_time = HAL_GetTick();
    
    // 周期性触发测量
    if(current_time - last_trigger > 1000/SAMPLE_RATE_HZ) {
        Ultrasonic_Trigger();
        last_trigger = current_time;
    }
    
    // 检查是否所有通道都有数据
    uint8_t all_received = 1;
    for(int i = 0; i < NUM_RECEIVERS; i++) {
        if(us_system.receivers[i].valid_flag == 0) {
            all_received = 0;
            break;
        }
    }
    
    // 超时处理
    if(current_time - us_system.trigger_time > MEASURE_TIMEOUT_MS) {
        all_received = 1;  // 强制处理
    }
    
    // 进行位置解算
    if(all_received) {
        Multistatic_Position_Estimation();
        
        // 输出结果
        if(us_system.measurement_done) {
            printf("Target: (%.2f, %.2f)m, Confidence: %.1f%%\n",
                   us_system.target_x, us_system.target_y, 
                   us_system.confidence * 100);
        }
    }
}

五、高级功能实现

1、自适应增益控制

/* 自动增益控制 */
void AGC_Control(void)
{
    static uint8_t gain_level = 1;
    
    for(int i = 0; i < NUM_RECEIVERS; i++) {
        if(us_system.receivers[i].echo_time_us < 100) {
            // 信号太强,降低增益
            gain_level = (gain_level > 1) ? gain_level - 1 : 1;
            break;
        } else if(us_system.receivers[i].echo_time_us > 5000) {
            // 信号太弱,增加增益
            gain_level = (gain_level < 8) ? gain_level + 1 : 8;
            break;
        }
    }
    
    // 设置模拟开关选择增益档位
    HAL_GPIO_WritePin(SEL_A_PORT, SEL_A_PIN, (gain_level & 0x01) ? GPIO_PIN_SET : GPIO_PIN_RESET);
    HAL_GPIO_WritePin(SEL_B_PORT, SEL_B_PIN, (gain_level & 0x02) ? GPIO_PIN_SET : GPIO_PIN_RESET);
    HAL_GPIO_WritePin(SEL_C_PORT, SEL_C_PIN, (gain_level & 0x04) ? GPIO_PIN_SET : GPIO_PIN_RESET);
}

2、多目标识别

/* 多目标检测 */
typedef struct {
    float distance;
    uint8_t amplitude;
    uint8_t channel_mask;
} Echo_Target_t;

void Multi_Target_Detection(void)
{
    #define MAX_TARGETS 5
    Echo_Target_t targets[MAX_TARGETS];
    uint8_t target_count = 0;
    
    // 分析每个通道的回波信号
    for(int ch = 0; ch < NUM_RECEIVERS; ch++) {
        // 检测多个回波峰值
        uint32_t *echo_times = Get_Echo_Timeline(ch);
        uint8_t peak_count = Find_Echo_Peaks(echo_times);
        
        for(int p = 0; p < peak_count && target_count < MAX_TARGETS; p++) {
            targets[target_count].distance = echo_times[p] * 0.001f * SOUND_SPEED / 2.0f;
            targets[target_count].channel_mask |= (1 << ch);
            target_count++;
        }
    }
    
    // 聚类分析,合并同一目标的多个回波
    Cluster_Targets(targets, &target_count);
}

六、误差分析与补偿

1、温度补偿

/* 温度补偿声速 */
float Get_Sound_Speed(float temperature_c)
{
    // v = 331.4 + 0.6 × T
    return 331.4f + 0.6f * temperature_c;
}

/* 在距离计算中使用 */
us_system.receivers[i].distance_m = 
    (diff * 0.001f) * Get_Sound_Speed(current_temp) / 2.0f;

2、时间延迟补偿

/* 硬件延迟补偿 */
#define HW_DELAY_US    2.5f    // 发射电路延迟
#define SW_DELAY_US    1.2f    // 软件处理延迟

float Compensate_Distance(float raw_distance)
{
    float time_compensation = (HW_DELAY_US + SW_DELAY_US) * 0.001f;
    float distance_compensation = time_compensation * SOUND_SPEED / 2.0f;
    return raw_distance - distance_compensation;
}

参考代码 实现超声波传感器一发多收的测距功能 www.youwenfan.com/contentcsv/72819.html

七、性能优化

1、实时性优化

优化项 方法
中断处理 使用DMA减少CPU占用
数据缓存 环形缓冲区存储回波数据
算法优化 查表法替代浮点运算
并行处理 多通道同时采样

2、抗干扰措施

/* 中值滤波 */
float Median_Filter(float *data, uint8_t len)
{
    // 冒泡排序取中值
    for(int i = 0; i < len-1; i++) {
        for(int j = 0; j < len-i-1; j++) {
            if(data[j] > data[j+1]) {
                float temp = data[j];
                data[j] = data[j+1];
                data[j+1] = temp;
            }
        }
    }
    return data[len/2];
}

八、测试验证

1、测试项目

测试项目 方法 标准
单目标测距 固定距离测量 ±2cm
多目标分辨 前后放置障碍物 最小间距>15cm
角度特性 旋转目标 120°覆盖
抗干扰性 添加噪声源 误检率<5%
长期稳定性 连续运行24h 漂移<3cm

2、标定流程

1. 静态标定:在0.5m、1m、2m、3m、4m处测量
2. 温度标定:-10°C、0°C、25°C、50°C
3. 角度标定:0°、30°、60°、90°
4. 多目标标定:前后目标分离测试

 

专注于matlab/simulink,电子电路,编程