【Timer】超声波测距
下载例程代码: 下载代码
请一定按照 例程使用方法 🔗 导入例程,否则下载的可能不是例程而是其他工程。
HC-SR04 超声波模块简介
HC-SR04 工作原理
模块有 2 个超声波换能器(如图所示),一个发出声波,另一个接收物体反射回来的声波,这中间所经过的时间即声波传播的时间,再结合声速就能计算出:
- 距离 = 声速 * 时间 ÷ 2

如何使用 HC-SR04 模块
模块具有 4 个引脚,除了电源外,有 TRIG、ECHO 两个引脚需要操作:
-
首先,向TRIG 引脚发送一个高电平脉冲,来触发模块输出声波
-
记录 ECHO 引脚输出高电平的时间,即声波的飞行时间
-
距离 = 声速(340m/s) * 声波的飞行时间 ÷ 2

更多资料请查看资料包 -> 配套模块资料 -> 超声波测距 HC-SR04-P
如何使用例程
下载程序,并连接硬件,即可看到效果
硬件连接
- 使用配套 TYPE-C 数据线,将学习板连接到计算机

-
需要使用:4P 杜邦线、超声波模块
-
连接模块时请核对好线序:
| 循迹模块 | 学习板 |
|---|---|
| VCC | VCC |
| TRIG | A11 |
| ECHO | A10 |
| GND | GND |

程序效果
-
打开 小智精灵 串口助手 在线串口调试助手,点击“选择串口”,选择 USB Single Serial
-
将超声波模块对准一个平面(量程 2 - 400 cm),可以在串口助手看到测距结果

例程讲解
下面介绍了如何自己实现该例程的功能
1、工程配置
- 开启外部晶振:在 Pinout&Configuration -> System Core -> RCC 页面,将 High Speed Clock (HSE) 配置为 Crystal/Ceramic Resonator

- 配置时钟频率:在 Clock Configuration 页面,将 PLL Source 选择为 HSE,将 System Clock Mux 选择为 PLLCLK,然后在 HCLK (MHz) 输入 72 并回车,将 HCLK 频率配置为 72 MHz

-
分配引脚:在 Pinout&Configuration 页面,将 PA11、PA10 分别配置为 GPIO_Output、TIM1_CH3,并将 PA11 命名为 TRIG
-
配置 TIM1:在 Pinout&Configuration -> Timers -> TIM1
-
Mode -> Clock Source 设为 Internal Clock,Channel3 设为 Input Capture direct mode,即输入捕获
-
Configuration -> Parameter Settings -> Counter Settings -> Prescaler 设为 72-1,使定时器计数周期刚好为 1 us
-
(可选)开启输入滤波,以提高稳定性:Configuration -> Parameter Settings -> Input Capture Channel 3 -> Input Filter,填写范围 0 - 15,数值越大,滤波效果越强
-
Configuration -> NVIC Settings -> 勾选 TIM1 capture compare interrupt,开启捕获中断
-

-
打开串口 2 外设:Pinout&Configuration -> Connectivity -> USART2,将 Mode 选择为 Asynchronous
-
启用 float 打印:在 cubeIDE 菜单栏中,Project Properties -> C/C++ Build -> Settings -> Tool Settings -> MCU Settings,勾选 Use float with printf ... -nano
默认情况下,sprintf 函数不能打印小数。因此我们需要配置一下编译器,使其能够打印小数
2、代码
-
引用头文件
- 因为需要打印输出变量,所以应该引用几个头文件:
#include "stdio.h"
#include "string.h" -
触发测量
- 将 TRIG 引脚拉高至少 10us 后拉低,触发测量
// 触发
HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, 1);
HAL_Delay(5);
HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, 0); -
打开脉冲捕获
- 先清零变量
__HAL_TIM_SET_CAPTUREPOLARITY配置为上升沿捕获HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_3)开始捕获
// 清零
rising_cnt = 0;
falling_cnt = 0;
echo_flag = 0;
__HAL_TIM_SET_COUNTER(&htim1, 0);
// 开始捕获
__HAL_TIM_SET_CAPTUREPOLARITY(&htim1, TIM_CHANNEL_3, TIM_INPUTCHANNELPOLARITY_RISING);
HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_3); -
重定义输入捕获中断函数
-
捕获到边沿时,Timer 会自动记录当前的计数值,通过
__HAL_TIM_SET_CAPTUREPOLARITY函数即可获取 -
捕获到上升沿时,立即配置成下降沿捕获,以捕获下降沿
-
将上升沿、下降沿的值分别保存到变量
rising_cnt、falling_cnt
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if (htim == &htim1 && htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3)
{
// 捕获到上升沿
if (!echo_flag)
{
rising_cnt = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_3);
echo_flag = 1;
__HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_3, TIM_INPUTCHANNELPOLARITY_FALLING);
}
// 捕获到下降沿
else
{
falling_cnt = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_3);
echo_flag = 0;
__HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_3, TIM_INPUTCHANNELPOLARITY_RISING);
}
}
} -
-
计算距离
- 当
rising_cnt、falling_cnt都捕获完成时,计算距离,并通过串口发送结果
if (rising_cnt != 0 && falling_cnt != 0)
{
// 计算距离
// 定时器每1us计数1次,因此 距离=计数*0.34/2(毫米)
float distance = (falling_cnt - rising_cnt) * 0.017;
// 发送到串口
char buf[32];
sprintf(buf, "Distance: %.2f cm\r\n", distance);
HAL_UART_Transmit(&huart2, (uint8_t *)buf, strlen(buf), 1000);
break;
} - 当