超声波传感器一发多收测距系统
一、系统架构设计
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. 多目标标定:前后目标分离测试