硬件引脚
VCC-供5V的电压(一定要是5v)
GND-接地
Trig-HC-SR04超声波测距模块上的触发引脚,用于向模块发送一个10微秒的高电平触发信号,触发模块开始进行距离测量
Echo-用于接收超声波回波信号的引脚
工作原理:
使用HC-SR04模块时,需要先向Trig引脚发送一个持续时间不少于10微秒的高电平信号,这会使超声波发射器发射出一个8个周期的40KHz的超声波信号。随后,当超声波遇到障碍物在返回回来时,接收器会将接收到的回波信号转换为电信号,将Echo引脚输出一个高电平信号,其持续时间与回波信号的时间间隔成正比。
-
发送超声波:模块通过发送一定频率的超声波(通常为40kHz)来探测周围物体。超声波在空气中传播速度约为340m/s(在常温常压下),且在遇到物体时会被反射回来。
-
接收回波:当发出的超声波遇到物体后,会被反射回来。模块内置的接收器会接收到反射回来的超声波信号。
-
计算距离:模块通过计算发送超声波和接收回波的时间间隔来计算出物体与模块之间的距离。具体步骤如下:
- 发送超声波。
- 等待接收到反射回来的超声波信号。
- 记录下发送和接收之间的时间差,通过时间差计算出测量距离。时间差需要进行一定的处理,例如除以2,因为超声波的来回路径都要计算在内。
需要注意的是,超声波的测量范围是有限的,一般为2cm至4m之间。而且由于环境因素影响,例如温度、湿度、气压等,也会对超声波的传播和反射造成一定的影响,进而影响测量精度。
代码部分
代码部分参考:HC-SR04超声波测距模块使用方法和例程(STM32)_stm32超声波测距程序讲解_zeruns的博客-CSDN博客
超声波.c文件
#include "stm32f10x.h"
#include "Delay.h"
/*卡尔曼滤波数值配置*/
float P=1;
float P_; //对应公式中的p'
float X=0;
float X_; //X'
float K=0;
float Q=0.01;//噪声
//float R=0.2; //R如果很大,更相信预测值,那么传感器反应就会迟钝,反之相反
float R=0.5;
float distance=0;
float distance1=0;
/*卡尔曼函数*/
float KLM(float Z)
{
X_=X+0;
P_=P+Q;
K=P_/(P_+R);
X=X_+K*(Z-X_);
P=P_-K*P_;
return X;
}
/*********************/
#define Echo GPIO_Pin_6 //HC-SR04模块的Echo脚接GPIOB6
#define Trig GPIO_Pin_5 //HC-SR04模块的Trig脚接GPIOB5
uint64_t time=0; //声明变量,用来计时
uint64_t time_end=0; //声明变量,存储回波信号时间
void HC_SR04_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); //启用GPIOB的外设时钟
GPIO_InitTypeDef GPIO_InitStructure; //定义结构体
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置GPIO口为推挽输出
GPIO_InitStructure.GPIO_Pin = Trig; //设置GPIO口5
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置GPIO口速度50Mhz
GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化GPIOB
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //设置GPIO口为下拉输入模式
GPIO_InitStructure.GPIO_Pin = Echo; //设置GPIO口6
GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化GPIOB
GPIO_WriteBit(GPIOB,GPIO_Pin_5,Bit_RESET); //输出低电平
Delay_us(15); //延时15微秒
}
int16_t sonar_mm(void) //测距并返回单位为毫米的距离结果
{
uint32_t Distance,Distance_mm = 0;
GPIO_WriteBit(GPIOB,Trig,Bit_SET); //输出高电平
Delay_us(15); //延时15微秒
GPIO_WriteBit(GPIOB,Trig,Bit_RESET); //输出低电平
while(GPIO_ReadInputDataBit(GPIOB,Echo)==0); //等待低电平结束
time=0; //计时清零
while(GPIO_ReadInputDataBit(GPIOB,Echo)==1); //等待高电平结束
time_end=time; //记录结束时的时间
if(time_end/100<38) //判断是否小于38毫秒,大于38毫秒的就是超时,直接调到下面返回0
{
Distance=(time_end*346)/2; //计算距离,25°C空气中的音速为346m/s
Distance_mm=Distance/100; //因为上面的time_end的单位是10微秒,所以要得出单位为毫米的距离结果,还得除以100
}
Distance_mm=KLM(Distance_mm);
return Distance_mm; //返回测距结果
}
float sonar(void) //测距并返回单位为米的距离结果
{
uint32_t Distance,Distance_mm = 0;
float Distance_m=0;
GPIO_WriteBit(GPIOB,Trig,Bit_SET); //输出高电平
Delay_us(15);
GPIO_WriteBit(GPIOB,Trig,Bit_RESET); //输出低电平
while(GPIO_ReadInputDataBit(GPIOB,Echo)==0);
time=0;
while(GPIO_ReadInputDataBit(GPIOB,Echo)==1);
time_end=time;
if(time_end/100<38)
{
Distance=(time_end*346)/2;
Distance_mm=Distance/100;
Distance_m=Distance_mm/1000;
}
Distance_m=KLM(Distance_m);
return Distance_m;
}
void TIM3_IRQHandler(void) //更新中断函数,用来计时,每10微秒变量time加1
{ // https://blog.zeruns.tech
if (TIM_GetITStatus(TIM3, TIM_IT_Update) == SET) //获取TIM3定时器的更新中断标志位
{
time++;
TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除更新中断标志位
}
}
超声波.H文件
#ifndef __HCSR04_H
#define __HCSR04_H
void HC_SR04_Init(void);
int16_t sonar_mm(void);
float sonar(void);
#endif
主函数main
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Timer.h"
#include "HCSR04.h"
uint64_t numlen(uint64_t num)//计算数字的长度
{
uint64_t len = 1; // 初始长度为1
for(; num > 9; ++len) // 判断num是否大于9,否则长度+1
num /= 10; // 使用除法进行运算,直到num小于1
return len; // 返回长度的值
}
int main(void)
{
OLED_Init(); //初始化OLED屏
Timer_Init(); //初始化定时器
HC_SR04_Init(); //初始化超声波测距模块
OLED_ShowString(1, 1, "Distance:"); //OLED屏输出字符串
while (1)
{
int Distance_mm=sonar_mm(); //获取距离测量结果,单位毫米(mm)
int Distance_m=Distance_mm/1000; //转换为米(m)为单位,将整数部分放入Distance_m
int Distance_m_p=Distance_mm%1000; //转换为米(m)为单位,将小数部分放入Distance_m_p
OLED_Clear_Part(2,1,16); //将OLDE屏第2行清屏
OLED_ShowNum(2, 1,Distance_m,numlen(Distance_m)); //显示测量结果的整数部分
OLED_ShowChar(2, 1+numlen(Distance_m), '.'); //显示小数点
if(Distance_m_p<100){ //判断是否小于100毫米
OLED_ShowChar(2, 1+numlen(Distance_m)+1,'0'); //因为单位是米,所以小于10cm时要加0
OLED_ShowNum(2, 1+numlen(Distance_m)+2,Distance_m_p,numlen(Distance_m_p)); //显示测量结果的小数部分
OLED_ShowChar(2, 1+numlen(Distance_m)+2+numlen(Distance_m_p), 'm'); //显示单位
}else
{
OLED_ShowNum(2, 1+numlen(Distance_m)+1,Distance_m_p,numlen(Distance_m_p)); //显示测量结果的小数部分
OLED_ShowChar(2, 1+numlen(Distance_m)+1+numlen(Distance_m_p), 'm'); //显示单位
}
OLED_Clear_Part(3,1,16); //将OLDE屏第3行清屏
OLED_ShowNum(3, 1,Distance_mm,numlen(Distance_mm)); //显示单位为毫米的距离结果
OLED_ShowString(3, 1 + numlen(Distance_mm), "mm");
Delay_ms(100); //延时100毫秒
}
}
有关超声波数值波动,加入的卡尔曼滤波之后减少其波动,如果减少延迟函数的数值也可以减少数值的波动