学习HC-SR04超声波测距模块,代码附带卡尔曼滤波

2023-11-14

硬件引脚

VCC-供5V的电压(一定要是5v)

GND-接地

Trig-HC-SR04超声波测距模块上的触发引脚,用于向模块发送一个10微秒的高电平触发信号,触发模块开始进行距离测量

Echo-用于接收超声波回波信号的引脚

工作原理:

使用HC-SR04模块时,需要先向Trig引脚发送一个持续时间不少于10微秒的高电平信号,这会使超声波发射器发射出一个8个周期的40KHz的超声波信号。随后,当超声波遇到障碍物在返回回来时,接收器会将接收到的回波信号转换为电信号,将Echo引脚输出一个高电平信号,其持续时间与回波信号的时间间隔成正比。

  1. 发送超声波:模块通过发送一定频率的超声波(通常为40kHz)来探测周围物体。超声波在空气中传播速度约为340m/s(在常温常压下),且在遇到物体时会被反射回来。

  2. 接收回波:当发出的超声波遇到物体后,会被反射回来。模块内置的接收器会接收到反射回来的超声波信号。

  3. 计算距离:模块通过计算发送超声波和接收回波的时间间隔来计算出物体与模块之间的距离。具体步骤如下:

  • 发送超声波。
  • 等待接收到反射回来的超声波信号。
  • 记录下发送和接收之间的时间差,通过时间差计算出测量距离。时间差需要进行一定的处理,例如除以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毫秒
		
	}
}

有关超声波数值波动,加入的卡尔曼滤波之后减少其波动,如果减少延迟函数的数值也可以减少数值的波动

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

学习HC-SR04超声波测距模块,代码附带卡尔曼滤波 的相关文章

  • Shell脚本进阶版合集

    文章目录 一 Linux监控服务端口脚本 二 Linux编译安装Nginx脚本 三 Linux监控一个主机状态脚本 四 Linux统计内存 CPU使用前十进程脚本 五 Linux 磁盘I O列长度监控脚本 六 Linux计算内存使用率占比
  • 【多元统计分析】09.独立性检验与正态性检验

    文章目录 九 独立性检验和正态性检验 1 独立性检验 2 一元数据正态性检验 3 多元数据的正态性检验 回顾总结 九 独立性检验和正态性检验 1 独立性检验 独立性检验 指的是将一个多元总体 X N p
  • 【cmake】find_package设置查找路径

    1 find package的作用与实例 用来查找第三方依赖包的 cmake文件 并根据 cmake文件生成依赖包的头文件目录和库文件路径等 CMakeLists txt实例 find package Protobuf REQUIRED i
  • [大话设计模式C++版] 第14章 老板回来,我不知道 —— 观察者模式

    源码可以在这里找到 大话设计模式C 版 双向耦合的代码 Secretary h 秘书类 include
  • numpy对array索引

    numpy中array索引 对numpy的array索引时总是容易出错 借此机会总结一下numpy中array最常用的索引方法 1 单个元素的索引 In 1 1 1 一维array 单个元素的索引使用整数 import numpy as n

随机推荐