STM32 | HC-SR04 超声波传感器测距
模块: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 计数)
void UltraSonic_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;// UlatrSonic-->PG14,PG15RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE); //使能PG端口时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14; // TrigGPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHzGPIO_Init(GPIOG, &GPIO_InitStructure); //根据设定参数初始化GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; // EchoGPIO_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) 计算距离
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) * 17distance_cm = time_us * 0.017; // distance = time / 58;return distance_cm;
}
调用程序:
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);}
}
输出结果: