
一、适用场景
适用场景:距离测量(避障小车、液位检测、门/物体接近报警)、简单测距仪、机器人避障、环境感知原型与嵌入式定时/中断练习。
二、器材清单
HC-SR04 超声波模块 ×1
stm32f103(或其它 STM32)开发板 ×1
若干杜邦线(母对母/公对母)×1组
面包板 / 电源线(模块需稳定 5V)
三、工作原理(要点)
工作流程:MCU 向 TRIG 引脚发送至少 10µs 的高电平触发脉冲,模块发出 40kHz 超声波(8 个周期或更多);如果前方有物体,超声波被反射,模块在 ECHO 引脚输出一个高电平脉冲,脉冲宽度等于超声波从发射到接收的往返时间(µs)。
距离换算(常用公式):速度 ≈ 343 m/s(在 20°C),即 0.0343 cm/µs。往返时间需除以 2 得到单程距离:
distance_cm ≈ (time_us × 0.0343) / 2 ≈ time_us / 58.3。
在工程中常用近似整数公式:distance_cm = time_us / 58。
测量限制与超时:HC-SR04 有盲区(约 2cm 以下测量不稳定),最大量程通常 ~300--400 cm(超远时回波微弱)。对应 4m 的往返时间约 23.3 ms(400 cm × 58.3 ≈ 23320 µs),建议超时设 30ms。
四、接线示意
VCC → +5V
GND → GND
标准库
TRIG → PA3
ECHO → PA1
HAL库
TRIG → PA0
ECHO → PA8
五、示例代码
标准库
cpp
#include "forward_direction.h"
int count;
void tim_init()
{
GPIO_InitTypeDef PA;
NVIC_InitTypeDef nvic;
TIM_TimeBaseInitTypeDef tim;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
PA.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
PA.GPIO_Mode = GPIO_Mode_Out_PP;
PA.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&PA);
PA.GPIO_Pin = GPIO_Pin_3;
PA.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Init(GPIOA,&PA);
tim.TIM_Period = (1000-1);
tim.TIM_Prescaler = (72-1);
tim.TIM_ClockDivision = TIM_CKD_DIV1;
tim.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2,&tim);
TIM_ClearFlag(TIM2,TIM_FLAG_Update);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
nvic.NVIC_IRQChannel = TIM2_IRQn;
nvic.NVIC_IRQChannelPreemptionPriority = 0;
nvic.NVIC_IRQChannelSubPriority = 0;
nvic.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic);
TIM_Cmd(TIM2,DISABLE);
}
void start_hc()
{
int i;
GPIO_ResetBits(GPIOA,GPIO_Pin_1);
GPIO_SetBits(GPIOA,GPIO_Pin_1);
for(i=0;i<1000000;i++);
GPIO_ResetBits(GPIOA,GPIO_Pin_1);
}
void opentime()
{
TIM_SetCounter(TIM2,0);
count = 0;
TIM_Cmd(TIM2,ENABLE);
}
void closetime()
{
TIM_Cmd(TIM2,DISABLE);
}
uint32_t get_time()
{
uint32_t tim_time = 0;
tim_time = count * 1000;
tim_time+=TIM_GetCounter(TIM2);
TIM_SetCounter(TIM2,0);
return tim_time;
}
double get_area()
{
uint32_t time = 0;
start_hc();
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3) == 0);
opentime();
while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3) == 1);
closetime();
time = get_time();
return ((double)time*0.034/2);
}
void TIM2_IRQHandler()
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update) == SET)
{
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
count++;
}
}
int main()
{
double dismiddle;
int j;
tim_init();
while(1)
{
dismiddle = get_area();
if(dismiddle < 10)
{
GPIO_SetBits(GPIOA,GPIO_Pin_2);
}else
{
GPIO_ResetBits(GPIOA,GPIO_Pin_2);
}
for(j=0;j<1000000;j++);
}
// return 0;
}
HAL库


cpp
int main(void)
{
/* USER CODE BEGIN 1 */
char usart[20]={0};
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM1_Init();
MX_USART3_UART_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
//1.让计数器CNT归零
__HAL_TIM_SET_COUNTER(&htim1,0);
//2.清除cC1\cC2标志位
__HAL_TIM_CLEAR_FLAG(&htim1,TIM_FLAG_CC1);
__HAL_TIM_CLEAR_FLAG(&htim1,TIM_FLAG_CC2);
//3.启动输入捕获
HAL_TIM_IC_Start(&htim1,TIM_CHANNEL_1);
HAL_TIM_IC_Start(&htim1,TIM_CHANNEL_2);
//4.向Trig发送脉冲
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET);
// for (volatile uint32_t i = 0; i < 15; i++);
for(uint32_t i=0; i<10; i++);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);
//5.等待测量结束
uint8_t success=0;
uint32_t expireTime = HAL_GetTick()+ 50;
while(expireTime > HAL_GetTick())
{
uint32_t cc1Flag = __HAL_TIM_GET_FLAG(&htim1,TIM_FLAG_CC1);
uint32_t cc2Flag = __HAL_TIM_GET_FLAG(&htim1,TIM_FLAG_CC2);
if(cc1Flag && cc2Flag)
{
success = 1;
break;
}
}
//6.关闭定时器
HAL_TIM_IC_Stop(&htim1,TIM_CHANNEL_1);
HAL_TIM_IC_Stop(&htim1,TIM_CHANNEL_2);
//7.计算测量结果
if(success ==1)
{
uint16_t ccr1 = __HAL_TIM_GET_COMPARE(&htim1,TIM_CHANNEL_1);
uint16_t ccr2 = __HAL_TIM_GET_COMPARE(&htim1,TIM_CHANNEL_2);
float pulseWidth = (ccr2 - ccr1) * 1e-6f;
float distance = 340.0f * pulseWidth / 2.0f;
sprintf(usart,"%.3lf\r\n",distance);
HAL_UART_Transmit(&huart3,usart,strlen(usart),HAL_MAX_DELAY);
if(distance < 0.2)
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
else
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
六、讲解视频