【STM32小案例02】用STM32F103ZET6使用HC-SR04超声波模块测距

本文将简单介绍如何通过HC-SR04超声波模块实现测距功能,希望对大家的学习有所帮助。

1.所需硬件

正点原子战舰V3开发板 X1

HC-SR04超声波模块 X1

杜邦线 若干

2.HC-SR04超声波模块介绍

在这里插入图片描述

上图为HC-SR04超声波模块实物图,从图中可以看到,该模块一共有四个引脚,分别是VCC、GND、Trig、Echo,关于该模块这里不做过多的详细介绍,感兴趣的同学可以自行百度了解,下面将简单介绍该模块的原理及使用方法。根据时序图可知,首先给TRIG引脚至少10us的高电平信号触发测距,模块自动发送8个40KHz的方波,自动检测是否有信号返回,若有信号返回,通过Echo引脚输出一个高电平,高电平的持续时间就是超声波从发射到返回的时间,
测 量 距 离 = ( 高 电 平 的 持 续 时 间 ∗ 声 速 ( 340 m / s ) ) / 2 测量距离 =(高电平的持续时间 * 声速(340m/s))/ 2 =340m/s/2
时序图如下
在这里插入图片描述

该模块使用较简单,难点在于程序的编写。

3.硬件连接

Vcc3.3/5V
GNDGND
TrigPB5
EchoPB6

4.程序编写思路是

1、配置好使用到的GPIO以及定时器;
2、给模块TRIG端口发送大于10us的高电平信号,当收、收到ECHO回响信号是,打开定时器开始定时;
3、当回响信号消失,关闭定时器;
4、通过定时器定时时间来确定距离。

5.程序代码

HCSR04.c源文件

#include "hcsr04.h"
#include "sys.h"
#include "delay.h"

#define HCSR04_PORT     GPIOB
#define HCSR04_CLK      RCC_APB2Periph_GPIOB
#define HCSR04_TRIG     GPIO_Pin_5
#define HCSR04_ECHO     GPIO_Pin_6
 
#define TRIG_Send  PBout(5) 
#define ECHO_Reci  PBin(6)

void Delay_Ms(uint16_t time);
void Delay_Us(uint16_t time);
void hcsr04_NVIC();


u16 msHcCount = 0;      //ms计数


void Hcsr04Init()
{  
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;     //生成用于定时器设置的结构体
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(HCSR04_CLK, ENABLE);
     
        //IO初始化
    GPIO_InitStructure.GPIO_Pin =HCSR04_TRIG;           //发送电平引脚
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;    //推挽输出
    GPIO_Init(HCSR04_PORT, &GPIO_InitStructure);
    GPIO_ResetBits(HCSR04_PORT,HCSR04_TRIG);
     
    GPIO_InitStructure.GPIO_Pin =   HCSR04_ECHO;        //返回电平引脚
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   //浮空输入
    GPIO_Init(HCSR04_PORT, &GPIO_InitStructure);  
	  GPIO_ResetBits(HCSR04_PORT,HCSR04_ECHO);	
 
		//定时器初始化 使用基本定时器TIM6
	  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);   //使能对应RCC时钟
		//配置定时器基础结构体
		TIM_DeInit(TIM2);
		TIM_TimeBaseStructure.TIM_Period = (1000-1);      //设置在下一个更新事件装入活动的自动重装载寄存器周期的值         计数到1000为1ms
		TIM_TimeBaseStructure.TIM_Prescaler =(72-1);      //设置用来作为TIMx时钟频率除数的预分频值  1M的计数频率 1US计数
		TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;         //不分频
		TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;   //TIM向上计数模式
		TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);   //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位		 
		
		TIM_ClearFlag(TIM6, TIM_FLAG_Update);       //清除更新中断,免得一打开中断立即产生中断
		TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);    //打开定时器更新中断
		hcsr04_NVIC();
		TIM_Cmd(TIM6,DISABLE);     
}
 
 
//tips:static函数的作用域仅限于定义它的源文件内,所以不需要在头文件里声明
static void OpenTimerForHc()        //打开定时器
{
	TIM_SetCounter(TIM6,0);  //清除计数
	msHcCount = 0;
	TIM_Cmd(TIM6, ENABLE);   //使能TIMx外设
}
 
static void CloseTimerForHc()        //关闭定时器
{
	TIM_Cmd(TIM6, DISABLE);  //使能TIMx外设
}
 
 
//NVIC配置
void hcsr04_NVIC()
{
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

	NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;             //选择串口1中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;   //抢占式中断优先级设置为1
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;          //响应式中断优先级设置为1
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             //使能中断
	NVIC_Init(&NVIC_InitStructure);
}
 
 
//定时器6中断服务程序
void TIM6_IRQHandler(void)   //TIM3中断
{
	if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)  //检查TIM3更新中断发生与否
	{
			TIM_ClearITPendingBit(TIM6, TIM_IT_Update  );   //清除TIMx更新中断标志 
			msHcCount++;
	}
}
 
 
//获取定时器时间
u32 GetEchoTimer(void)
{
	u32 t = 0;
	t = msHcCount*1000;    //得到MS
	t += TIM_GetCounter(TIM6);    //得到US
	  TIM6->CNT = 0;     //将TIM2计数寄存器的计数值清零
			Delay_Ms(50);
	return t;
}
 
 
//一次获取超声波测距数据 两次测距之间需要相隔一段时间,隔断回响信号
//为了消除余震的影响,取五次数据的平均值进行加权滤波。
float Hcsr04GetLength(void )
{
	u32 t = 0;
	int i = 0;
	float lengthTemp = 0;
	float sum = 0;
	while(i!=5)
	{
	TRIG_Send = 1;      //发送口高电平输出
	Delay_Us(20);
	TRIG_Send = 0;
	while(ECHO_Reci == 0);      //等待接收口高电平输出
		OpenTimerForHc();        //打开定时器
		i = i + 1;
		while(ECHO_Reci == 1);
		CloseTimerForHc();        //关闭定时器
		t = GetEchoTimer();        //获取时间,分辨率为1US
		lengthTemp = ((float)t/58.0);//cm
		sum = lengthTemp + sum ;
	
	}
	lengthTemp = sum/5.0;
	return lengthTemp;
}
 
 
/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
** 函数名称: Delay_Ms_Ms
** 功能描述: 延时1MS (可通过仿真来判断他的准确度)			
** 参数描述:time (ms) 注意time<65535
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
void Delay_Ms(uint16_t time)  //延时函数
{ 
	uint16_t i,j;
	for(i=0;i<time;i++)
  		for(j=0;j<10260;j++);
}
/*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
** 函数名称: Delay_Ms_Us
** 功能描述: 延时1us (可通过仿真来判断他的准确度)
** 参数描述:time (us) 注意time<65535				 
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
void Delay_Us(uint16_t time)  //延时函数
{ 
	uint16_t i,j;
	for(i=0;i<time;i++)
  		for(j=0;j<9;j++);
}

main.c源文件

#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "led.h"

int main()
{		
			float length;
			delay_init();	    	 //延时函数初始化	  
			NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
			uart_init(115200);	 //串口初始化为115200

	
			while(1)
			{
					delay_ms(1000);
					printf("串口初始化成功!\r\n");

					Hcsr04Init();	
					printf("超声波初始化成功!\r\n");      //测试程序是否卡在下面两句上面

					length = Hcsr04GetLength();
					printf("距离为:%.3f\r\n",length);
			}
			return 0;
}	

5.总结

通过本次的项目,我们对STM32的定时器的应用有一定了解,在学习STM32单片机的过程中自己可以边学边做项目,这样会提高自己的动手能力,也会巩固理论知识,本篇博客简单介绍了利用超声波模块测距,如需进一步了解可自行求助度娘,希望对大家的学习有所帮助!

程序源码已上传,如有需要请自行下载

如有错误,欢迎指正!
部分内容来源于网络,如有侵权请告知!

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值