摘要:本文详细介绍了超声波测距模块的驱动原理与STM32实现方法。首先说明超声波工作原理:通过Trig引脚发送至少10us高电平触发信号后,Echo引脚会在收到回波时拉低电平。关键计算公式为"高电平时间*0.017=距离(cm)",对应定时器1us时钟周期配置(主频72MHz时分频71)。硬件接线包括5V供电、Trig触发引脚、Echo接收引脚和GND。软件实现分为三部分:1) GPIO输出10us以上方波驱动Trig;2) 配置TIM1输入捕获模式,分别设置上升沿/下降沿捕获通道;3) 通过差值计算高电平持续时间并转换为距离。文中提供了完整的驱动代码框架,包括微秒延时函数、超声波发送函数和距离计算函数,并解释了输入捕获模式的工作机制。
一、首先当然就是超声波接线:
1.VCC------------------------接3.3v或者5v(我建议5v,有时候5v会出现驱动不了的情况)
2.Trig--------------------------这个引脚为触发引脚(用来接收单片机发送的驱动信号)
3.Echo------------------------这个引脚为接收引脚(当超声波接收到反射回来的信号,该Echo信号会从高电平变为低电平!!!这个很关键)
4.GND-------------------------这个引脚接地(只要是接触过一点硬件的都知道的!!!)
二、使用单片机发送驱动信号(也就是通过Trig引脚驱动超声波)
1.首先我们需要配置一个GPIO口,用于输出特定周期的方波:记住,向Trig引脚输出保持10us以上的高电平,就可以驱动超声波模块内部自动发送 8 个 40kHz 的方波信号。
上图为配置一个GPIO口为输出模式(根据自己适合的选择GPIO口,输出模式即可),通过STM32CubeMX配置一个GPIO输出模式,其连接的是Trig引脚,用于驱动超声波。
三、Echo检测是否收到信号
Echo为超声波的接收端,我们需要计算自超声波模块发送开始,到Echo接收到所需要的时间,当Echo接收到超声波信号,则会输出低电平。
下面我们用定时器的输入捕获功能,来测量超声波的高电平持续时间:
第一步:点击RCC,配置外部时钟
第二步:打开时钟树配置界面,配置主频为72Mhz
第三步:点击Timers时钟选项,点击定时器1(TIM1),配置时钟源(Clock Source)为内部时钟
,打开channel1为输入捕获直接模式,打开channel2为输入捕获间接模式。(什么是直接模式,什么是间接模式:我这里简单的解释一下就是当单片机检测的输入的信号跳变的时候,其单片机内部的计数值会被一个叫ccr1的寄存器给存储起来,间接模式就是在同一个通道可以使用两个寄存器存储两个不同的计数值,这样两个不同的计数值,大家可以先想想有什么用!!!!后面案列说明)
(我来简单解释一下什么是输入捕获模式,输入捕获就是外部电子器件向主控单片机发送信号,输入相当于主控单片机为输入模式,然后单片机在这个模式下能够捕获其高低电平变化情况)。
第四步:点击下方的参数设置(Parameter Settings)设置分频为71,计数周期为65535,输入捕获通道1设置为上升沿捕获(Rising Edge),输入捕获模式二为下降沿捕获(Falling Edge)
////////////////////////////////上面两张图部分为配置定时器1部分为输入捕获模式
打开定时器2,时钟源选择内部时钟,用于生成us延时!!!!!
配置完成后我们就可以生成Keil工程了。
void Delay_us(uint32_t us)//微秒延时
{
__HAL_TIM_SET_COUNTER(&htim2,0);//设置计数值
__HAL_TIM_ENABLE(&htim2);//使能定时器
while(__HAL_TIM_GET_COUNTER(&htim2) < us);//等待延时
__HAL_TIM_DISABLE(&htim2);//关闭定时器
}
上面图中代码为生成us延时的代码(直接赋值即可),解释看注释。
void Send_Ultrasonic()//发送超声波
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET);//引脚电平拉高持续至少10us以上,这里我延时12us
Delay_us(12);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_RESET);//引脚电平拉低
}
上图部分为驱动超声波函数,通过延时至少10us以上来进行驱动超声波(注意也不能延时太久,不然会卡死)
uint16_t Ultrasonic(void)//超声波处理函数
{
__HAL_TIM_SET_COUNTER(&htim1,0);//设置定时器计数值
__HAL_TIM_CLEAR_FLAG(&htim1,TIM_FLAG_CC1);//清除cc1标志位
__HAL_TIM_CLEAR_FLAG(&htim1,TIM_FLAG_CC2);//清除cc2标志位
HAL_TIM_IC_Start(&htim1,TIM_CHANNEL_1);//使能输入捕获通道一
HAL_TIM_IC_Start(&htim1,TIM_CHANNEL_2);//使能输入捕获通道二
Send_Ultrasonic();//发送超声波
uint8_t Success = 0;//设置是否成功标志位
uint32_t Timeout = HAL_GetTick() + 20;//延时20ms
while(Timeout > HAL_GetTick())
{
uint32_t ccr1Flag = __HAL_TIM_GET_FLAG(&htim1,TIM_FLAG_CC1);//获取cc1标志位状态
uint32_t ccr2Flag = __HAL_TIM_GET_FLAG(&htim1,TIM_FLAG_CC2);//获取cc2标志位状态
if(ccr1Flag && ccr2Flag)//同时为1时候
{
Success = 1;//表示成功置1
break;
}
}
HAL_TIM_IC_Stop(&htim1,TIM_CHANNEL_1);//停止通道1输入捕获
HAL_TIM_IC_Stop(&htim1,TIM_CHANNEL_2);//停止通道2输入捕获
if(Success == 1)//如果成功
{
uint32_t ccr1 = __HAL_TIM_GET_COMPARE(&htim1,TIM_CHANNEL_1);//获取计数值,即上升沿采集的值
uint32_t ccr2 = __HAL_TIM_GET_COMPARE(&htim1,TIM_CHANNEL_2);//获取计数值,即下降沿采集的值
distance = (ccr2 - ccr1)*0.017;//带入公式
}
return distance;//返回距离
}
上图为通过输入捕获来计算距离,在此再对输入捕获做详细解释,我们前面设置了通道1上升沿采集触发一个输入捕获,通道二下降沿捕获,那我们就可以想象一下,两个通道是不是刚好可以夹住一个方波,来一个上升沿输入捕获计数值会被给到ccr1寄存器,来一个下降沿就会触发通道二输入捕获把计数值给到ccr2,那很明显(ccr2 - ccr1)则为高电平时间所记的数!!!!(小伙伴们可能会向为什么检测到的一定是高电平而不是低电平,因为当接收端接收到信号时候电平被拉低,然后电平被设备自动拉高触发通道一的输入捕获,当接收到信号再次把电平拉低触发通道二输入捕获,从而实现高电平持续时间内的计数采集)。
把上面的代码复制到keil工程中,用CM = Ultrasonic();即可读出超声波距离。
若出现超声波测距卡死,或者不稳定,检查供电电源是否稳定!!!!!!!,尽量使用USB供电!!!!!