1. 项目背景与核心需求
超声波测距在嵌入式开发中属于基础但极其重要的功能模块,广泛应用于避障机器人、液位检测、停车辅助等场景。STM32CubeMX作为ST官方推出的图形化配置工具,能大幅降低外设初始化复杂度,但实际开发中仍然存在参数配置不合理、中断优先级冲突、数据滤波算法缺失等典型问题。
本系列教程的第四部分将聚焦于如何通过STM32CubeMX完成HC-SR04超声波传感器的完整数据采集链路搭建,重点解决以下三个工程实践中的痛点:
- 如何准确计算超声波回波时间(涉及定时器输入捕获模式的高级配置)
- 多外设(USART+DMA+TIM)协同工作时的资源冲突规避
- 实测数据的滑动加权滤波算法实现
硬件选型提示:建议使用STM32F103C8T6最小系统板(72MHz主频),其TIM2/TIM3定时器支持输入捕获功能,且USART1引脚布局与CH340串口芯片兼容,便于调试输出。
2. 硬件连接与CubeMX基础配置
2.1 传感器接口定义
HC-SR04标准引脚定义如下:
- VCC:5V供电(需注意部分STM32板载LDO输出仅为3.3V,需外接5V电源)
- Trig:触发信号输入(配置为GPIO输出)
- Echo:回波信号输出(需接入定时器输入捕获通道)
- GND:共地连接
典型接线方案:
bash复制HC-SR04 STM32F103
VCC → 5V
Trig → PA0 (GPIO_Output)
Echo → PA6 (TIM3_CH1)
GND → GND
2.2 CubeMX关键配置步骤
- 时钟树配置:确保HCLK=72MHz,APB1 Timer Clock=72MHz(输入捕获需要精确时钟源)
- GPIO设置:
- Trig引脚:推挽输出,无上拉下拉,初始电平Low
- Echo引脚:浮空输入(硬件已内置上拉电阻)
- 定时器配置:
- TIM3 Mode: Input Capture direct mode
- Channel1: Rising/Falling edge detection
- Prescaler: 71 (产生1MHz计数频率,1计数=1μs)
- Counter Period: 65535 (最大测量距离约4m)
- USART配置:
- 波特率115200,8数据位,无校验
- 启用DMA传输(减轻CPU负载)
中断优先级警告:若同时使用USART接收中断和定时器捕获中断,必须设置定时器中断优先级高于串口中断,否则可能导致回波时间测量误差。
3. 超声波测距核心算法实现
3.1 时序触发逻辑
HC-SR04标准工作时序要求:
- 给Trig引脚至少10μs的高电平脉冲
- 传感器自动发送8个40kHz方波
- 回波引脚Echo输出高电平,持续时间与距离成正比
代码实现示例:
c复制// 触发信号生成
void Ultrasonic_StartMeasure(void)
{
HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_SET);
delay_us(12); // 略大于10μs
HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_RESET);
}
3.2 输入捕获中断处理
通过TIM3的输入捕获功能测量Echo高电平持续时间:
c复制// TIM3中断回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
static uint32_t capture_start = 0;
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) {
if(htim->Instance->CCMR1 & TIM_CCMR1_CC1S_0) { // 上升沿捕获
capture_start = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
__HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING);
}
else { // 下降沿捕获
uint32_t capture_end = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
uint32_t pulse_width = (capture_end - capture_start) & 0xFFFF;
distance_mm = pulse_width * 0.34 / 2; // 声速340m/s
__HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING);
}
}
}
3.3 数据滤波算法
原始测量数据通常存在跳变,需采用滑动加权滤波:
c复制#define FILTER_LEN 5
uint32_t filter_buf[FILTER_LEN] = {0};
uint32_t Ultrasonic_Filter(uint32_t raw_val)
{
static uint8_t index = 0;
filter_buf[index++] = raw_val;
if(index >= FILTER_LEN) index = 0;
// 加权系数:最近数据权重更高
const uint8_t weights[FILTER_LEN] = {1, 2, 3, 2, 1};
uint32_t sum = 0, weight_sum = 0;
for(uint8_t i=0; i<FILTER_LEN; i++) {
sum += filter_buf[i] * weights[i];
weight_sum += weights[i];
}
return sum / weight_sum;
}
4. 串口数据输出优化
4.1 DMA非阻塞传输配置
避免在中断中直接调用HAL_UART_Transmit:
- CubeMX中为USART1添加DMA通道(Mode=Normal)
- 定义发送缓冲区:
c复制uint8_t uart_buf[32];
void Send_Distance(void)
{
int len = sprintf((char*)uart_buf, "Dist: %3dcm\r\n", distance_mm/10);
HAL_UART_Transmit_DMA(&huart1, uart_buf, len);
}
4.2 输出频率控制
通过SysTick定时器控制数据发送间隔:
c复制uint32_t last_send = 0;
void HAL_SYSTICK_Callback(void)
{
static uint32_t tick = 0;
if(++tick - last_send >= 100) { // 100ms间隔
Send_Distance();
last_send = tick;
}
}
5. 实测问题排查指南
5.1 常见故障现象与对策
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 持续返回0值 | 未收到回波信号 | 检查Trig/Echo接线,确认传感器供电5V |
| 测量值偏小 | 定时器分频系数错误 | 确认TIM3 Prescaler=71(72MHz→1MHz) |
| 数据剧烈跳动 | 环境噪声干扰 | 增加滤波算法,传感器加装海绵减震 |
| 串口输出乱码 | 波特率不匹配 | 检查CubeMX与终端软件的波特率设置 |
5.2 精度优化技巧
- 温度补偿:声速随温度变化,可添加DS18B20温度传感器进行动态校准
c复制float speed_of_sound = 331.4 + 0.6 * temperature; // m/s - 多次测量取中值:连续测量5次,取中间值作为最终结果
- 硬件去抖:在Echo信号线上并联100nF电容
6. 工程结构建议
规范化的HAL库项目应包含以下模块:
code复制/Drivers
/STM32F1xx_HAL_Driver
/CMSIS
/Inc
ultrasonic.h
dma.h
tim.h
/Src
main.c
ultrasonic.c
stm32f1xx_it.c
关键头文件定义示例(ultrasonic.h):
c复制typedef struct {
uint32_t raw_distance;
uint32_t filtered_distance;
uint8_t measure_status;
} Ultrasonic_TypeDef;
void Ultrasonic_Init(void);
void Ultrasonic_StartMeasure(void);
uint32_t Ultrasonic_GetDistance(void);
在CubeMX生成代码后,建议将外设初始化代码与业务逻辑分离:
c复制/* main.c */
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_TIM3_Init();
MX_USART1_UART_Init();
Ultrasonic_Init();
while (1) {
Ultrasonic_StartMeasure();
HAL_Delay(100);
}
}
7. 进阶扩展方向
- 多传感器协同:通过TIM级联实现4路超声波同时测量
- 低功耗模式:使用TIM唤醒+间歇测量(适合电池供电场景)
- 三维定位:部署3个传感器实现空间坐标计算
- 无线传输:通过HC-05蓝牙模块上传数据到手机APP
实测中发现,当测量距离超过2米时,建议将Trig脉冲宽度增加到20μs以提高声波强度。另外,在潮湿环境中声速会增大约0.5%,对于高精度应用需要相应校准。