在嵌入式开发中,经常会遇到需要测量距离的场景。超声波测距模块以其成本低廉、使用方便等优点,成为了许多工程师的首选。本文将以 stm32之超声波测距 为例,深入探讨其原理、实现和优化,并分享实战中的一些经验教训。
超声波测距模块原理:回声定位的艺术
超声波测距的核心原理是利用超声波在空气中的传播速度恒定(约为 340m/s),通过测量超声波从发射到接收的时间差,来计算出距离。模块通常包含一个超声波发射器和一个超声波接收器。发射器发出一段特定频率的超声波脉冲,当遇到障碍物时,超声波会反射回来,被接收器接收。STM32 通过测量发射和接收的时间间隔,即可计算出障碍物的距离。
距离 = (时间差 * 声速) / 2
公式中除以 2 是因为超声波经历了从发射器到障碍物,再从障碍物返回发射器的两个过程。
STM32 超声波测距的具体实现步骤
GPIO 口配置: 首先,需要配置 STM32 的两个 GPIO 口,一个用于输出超声波触发信号(Trig),另一个用于接收超声波回响信号(Echo)。Trig 口配置为推挽输出模式,Echo 口配置为输入模式,并开启外部中断功能。

// 初始化 Trig 引脚 GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = TRIG_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(TRIG_GPIO_Port, &GPIO_InitStruct); // 初始化 Echo 引脚 GPIO_InitStruct.Pin = ECHO_Pin; GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; // 上升沿和下降沿触发中断 GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(ECHO_GPIO_Port, &GPIO_InitStruct); // 使能外部中断 HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);定时器配置: 使用 STM32 的定时器来测量超声波的传播时间。配置定时器为向上计数模式,并设置合适的分频系数,以获得足够高的精度。在 Echo 引脚的上升沿启动定时器,在下降沿停止定时器,读取定时器的计数值,即为超声波的传播时间。
// 初始化定时器 TIM_HandleTypeDef htim3; htim3.Instance = TIM3; htim3.Init.Prescaler = 71; // 72MHz / 72 = 1MHz, 1us per count htim3.Init.CounterMode = TIM_COUNTERMODE_UP; htim3.Init.Period = 0xFFFF; // 最大计数周期 htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; HAL_TIM_Base_Init(&htim3);中断处理函数: 编写外部中断处理函数,在 Echo 引脚的上升沿启动定时器,在下降沿停止定时器,并读取定时器的计数值。同时需要注意,在中断处理函数中需要进行一些防抖处理,以避免误触发。
// 外部中断处理函数 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == ECHO_Pin) { if (HAL_GPIO_ReadPin(ECHO_GPIO_Port, ECHO_Pin) == GPIO_PIN_SET) // 上升沿 { __HAL_TIM_SET_COUNTER(&htim3, 0); // 清零计数器 HAL_TIM_Base_Start(&htim3); // 启动定时器 } else // 下降沿 { HAL_TIM_Base_Stop(&htim3); // 停止定时器 time = __HAL_TIM_GET_COUNTER(&htim3); // 获取时间 distance = (float)time * 0.034 / 2; // 计算距离,单位 cm } } }主循环: 在主循环中,周期性地触发超声波发射,并等待接收回响信号。需要设置合适的触发周期,以避免多次测量之间的干扰。
while (1) { HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_SET); // 发送触发信号 HAL_Delay(10); // 保持 10us 以上高电平 HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_RESET); HAL_Delay(100); // 等待接收回响信号 // ... 其他代码 ... }
实战避坑经验总结:细节决定成败
- 数据滤波: 由于环境噪声等因素的影响,测量的距离数据可能会存在一定的波动。可以采用滑动平均滤波等算法对数据进行平滑处理,提高测量的精度。
- 温度补偿: 声速会受到温度的影响,因此需要进行温度补偿。可以通过温度传感器测量环境温度,并根据温度计算出修正后的声速。
- 死区范围: 超声波测距模块存在一定的死区范围,即在一定距离内无法进行测量。需要根据模块的datasheet,了解模块的死区范围,并避免在死区范围内使用。
- 角度限制: 超声波具有一定的指向性,当障碍物与超声波发射方向的夹角过大时,超声波可能无法反射回来。需要注意超声波模块的安装角度,尽量保证超声波能够垂直照射到障碍物上。
- 电源稳定: 电源不稳定可能导致测量数据出现偏差,建议使用稳压电源为超声波模块供电。
掌握了以上技巧,你就可以轻松地将超声波测距模块应用到你的 STM32 项目中,让你的嵌入式系统拥有“眼睛”,感知周围的世界。记得根据实际应用场景进行调整和优化,才能获得最佳的测量效果。
冠军资讯
加班到秃头