模块:HC-SR04

感应角度:不大于15度
探测距离:2cm-450cm
高精度:可达0.3cm
Trig: 触发信号,接收MCU发送的控制脉冲,MCU对应GPIO 设置为输出
Echo: 反馈信号,向MCU发送数据脉冲, MCU对应GPIO 设置为输入
VCC:3.3V~5V
超声波测距原理:
- 超声波发射装置向某一方向发出超声波,并开始计时
- 超声波在空气中传播,途中碰到障碍物就立即返回来
- 接收器接收到超声波的时间差,就停止计时
- 根据超声波在空气中传播速度(340m/s),再根据计时器记录的时间t,可以算出距离(s)

似乎有多种模式,本文只使用GPIO模式:
单片机操作步骤:

(1)采用IO口TRIG触发测距,给最少10us的高电平信号。
(2)模块自动发送8个40khz的方波,自动检测是否有信号返回;
(3)有信号返回, 超声波模块通过ECHO引脚输出一个高电平(ECHO输出的高电平持续时间,就是处理的结果), 高电平持续的时间就是超声波从发射到返回的时间。
代码
UltraSonic_Init()
- 配置 GPIOG 的 14 脚为 Trig 输出,15 脚为 Echo 输入
- 配置 TIM4 定时器为 1MHz 计数频率 (1us / 计数)
- 设置最大测量时间为 50ms (50000 计数)
cpp
void UltraSonic_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
// UlatrSonic-->PG14,PG15
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE); //使能PG端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; // Trig
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOG, &GPIO_InitStructure); //根据设定参数初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; // Echo
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
GPIO_Init(GPIOG, &GPIO_InitStructure); //推挽输出 ,IO口速度为50MHz
// 设置一个定时器,1us计数1个数,不用中断,且开始时不使能定时器
//1、能定时器时钟。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);
TIM_TimeBaseInitStruct.TIM_Prescaler = 84-1; //84MHZ/8400 = 10000HZ Prescaler范围1~65536
TIM_TimeBaseInitStruct.TIM_Period = 50000-1; //在10000HZ时钟频率下,用时1ms 自动重装载寄存器值
TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseInitStruct.TIM_ClockDivision= TIM_CKD_DIV1; //分频因子
//2、初始化定时器
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStruct);
//【不使能定时器】
TIM_Cmd(TIM4, DISABLE);
}
UltraSonic_GetDistance()
- 发送 15us 的高电平触发信号,然后拉低引脚
- 等待模块返回的 Echo 信号(高电平)
- 高电平来了,开始定时器计时,目的是测量 Echo 高电平持续时间
- 低电平来了,停止定时器计时,得到 Echo 高电平持续时间
- 根据超声波在空气中的传播速度 (340m/s) 计算距离
cpp
float UltraSonic_GetDistance()
{
float distance_cm = 0;
u32 time_us = 0;
//**************************************
//启动超声波模块 也就是要发送启动信号
GPIO_ResetBits(GPIOG, GPIO_Pin_14);
delay_us(5);
//高电平需要10us以上---【启动信号】
GPIO_SetBits(GPIOG, GPIO_Pin_14);
delay_us(15);
GPIO_ResetBits(GPIOG, GPIO_Pin_14);
//*********************************
//设置定时器的CNT值为0,设置初值
TIM_SetCounter(TIM4,0);
//等待ECHO的高电平到来
while(GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_15)==Bit_RESET);
//**************************
//【高电平来了】-------启动定时器
TIM_Cmd(TIM4,ENABLE);
//等待ECHO的低电平到来
while(GPIO_ReadInputDataBit(GPIOG, GPIO_Pin_15)==Bit_SET);
//****************************
//【低电平来了】------读时间数据,关定时器
//取出CNT的值-----定时器的当前值
time_us = TIM_GetCounter(TIM4); // 微秒 (μs)。
//关闭定时器
TIM_Cmd(TIM4, DISABLE);
//**************************************
//【通过公式】:
// distance (m) * 2 = time * 10(-6) * 340m/s
// distance (m) = time * 10(-6) * 340m/s / 2
// distance (cm) = time * 10(-6) * 340m/s / 2 * 100 = time * 10(-3) * 17
distance_cm = time_us * 0.017; // distance = time / 58;
return distance_cm;
}
调用程序:
cpp
void ULTRA_SONIC_task(void *pvParameters)
{
float distance_cm = 0;
while(1)
{
printf("ULTRA_SONIC_task \r\n");
distance_cm = UltraSonic_GetDistance();
printf("distance = %f (cm) \r\n",distance_cm);
delay_ms(3000);
}
}
输出结果:
