STM32:两种方式实现超声波测距

本文详细介绍了在STM32F10x平台中使用HC-SR04超声波模块进行测距的方法,包括利用定时器中断法和输入捕获法,分别展示了相应的初始化配置和中断处理过程。
摘要由CSDN通过智能技术生成

超声波模块HC-SR04的工作原理很简单,有很多办法可以完成超声波测距,这里简单介绍两种。

1.定时器中断法

配置定时器的中断并声明一个Time的变量,在中断中先判断标志位,然后检查echo端口是否为高电平,如果是,Time++,然后变量time乘以定时时间就能得到echo端口高电平持续的时间,经过计算就可以得到距离。

Timer.c

#include "stm32f10x.h"                  // Device header
#include "Timer.h"

extern uint16_t Time;   //Time变量在HCSR04.c文件中定义

void Timer_Init()
{
 	Time = 0;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);	//选择APB1总线下的定时器Timer3
	
	TIM_InternalClockConfig(TIM3);		//TIM3使用内部时钟
										//默认使用内部时钟,不写这句代码也没关系
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;		//时钟1分频
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;		//计数模式,此处为向上计数
	TIM_TimeBaseInitStructure.TIM_Period = 7200 - 1;		//ARR 1 = 0.0001S,自动重装器的值
	TIM_TimeBaseInitStructure.TIM_Prescaler = 0;		//PSC,预分频器的值
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;		//高级计时器特有,重复计数
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
	
	TIM_ClearFlag(TIM3, TIM_FLAG_Update);
	TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);		//使能中断
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);		//将中断优先级分为两组,即组1和组2。

	
	NVIC_InitTypeDef NVIC_InitStructure;// 定义一个NVIC_InitTypeDef结构体变量,用于初始化中断控制器
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;// 设置中断通道为TIM3的IRQn中断
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;// 使能中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;// 设置中断优先级为2,表示高优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;// 设置中断子优先级为1,表示低优先级
	NVIC_Init(&NVIC_InitStructure);// 使用NVIC_Init函数初始化中断控制器
	
	TIM_Cmd(TIM3, ENABLE);// 使能定时器TIM3

}

void TIM3_IRQHandler(void)		// 定时器3的中断函数
{
    if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET) // 检查定时器3的更新中断标志位是否被设置
    {
        if (GPIO_ReadInputDataBit(Echo_Port, Echo_Pin) == 1) // 读取回声传感器端口上的引脚状态
        {
            Time++; // 如果引脚状态为高电平,则增加时间计数器
        }
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);		// 清空标志位,表示中断已经处理完毕
    }
}

Timer.h

#ifndef __TIMER_H
#define __TIMER_H

#define Trig_Port 		GPIOA
#define Trig_Pin 		GPIO_Pin_5
#define Trig_RCC		RCC_APB2Periph_GPIOA

#define Echo_Port 		GPIOA
#define Echo_Pin 		GPIO_Pin_6
#define Echo_RCC		RCC_APB2Periph_GPIOA

void Timer_Init(void);

#endif

2.输入捕获法

配置定时器的输入捕获,在echo端口的上升沿捕获一次,下降沿捕获一次,通过“TIM_GetCapture2(TIM3)”这句代码直接可以将时间读取出来。

IC.c

#include "stm32f10x.h"                  // Device header

void IC_Init(void)
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);  	// TIM3->使用引脚PA6
	
	//在超声波模块已经配置过
//	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//	GPIO_InitTypeDef GPIO_InitStructure;
//	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
//	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//PB6引脚,接入超声波Echo引脚
//	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	TIM_InternalClockConfig(TIM3);
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//配置时基单元
	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;		//ARR
	TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;		//PSC分频系数
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);
	
	
	//通道一
	TIM_ICInitTypeDef TIM_ICInitStructure;
	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;//TIM3的通道1
	TIM_ICInitStructure.TIM_ICFilter = 0xF;//配置滤波器,参数决定滤波效果,高频滤波
	TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;//极性选择,选择上升沿触发
	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//每次都触发捕获
	TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//通道触发选择
	
	
	//通道二
//	TIM_ICInitStructure.TIM_Channel=TIM_Channel_2;//捕获通道二
//	TIM_ICInitStructure.TIM_ICFilter=0xF;//滤除高频波动
//	TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Falling;//下降触发捕获
//	TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;//不分频
//	TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_IndirectTI;//交叉通道输入
//	TIM_ICInit(TIM3,&TIM_ICInitStructure);
	 
	TIM_PWMIConfig(TIM3, &TIM_ICInitStructure);//pwmi模式配置通道2,效果相当于上面的代码
	
	TIM_SelectInputTrigger(TIM3, TIM_TS_TI1FP1);
	TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Reset);
	
	TIM_Cmd(TIM3, ENABLE);
}

IC.h

#ifndef __IC_H
#define __IC_H

void IC_Init(void);

#endif

#超声波部分

这里将展示如何将获取到的时间值计算得到距离,定时器中断和输入捕获两种方法的实现都在下面的文件中,我们正确添加完文件后,在main文件中直接调用就可以实现测距的功能了。

HCSR04.c

#include "stm32f10x.h"                  // Device header
#include "HCSR04.h"
#include "Timer.h"
#include "Delay.h"

uint16_t Time;

void HCSR04_Init()
{
	RCC_APB2PeriphClockCmd(Trig_RCC, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStruct;
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Pin = Trig_Pin;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(Trig_Port, &GPIO_InitStruct);
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPD;
	GPIO_InitStruct.GPIO_Pin = Echo_Pin;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(Echo_Port, &GPIO_InitStruct);
	
	GPIO_ResetBits(Trig_Port, Trig_Pin);//Trig引脚给低电平,为后续启动做准备
	
}

void HCSR04_Start(void)
{
	GPIO_SetBits(Trig_Port, Trig_Pin);
	Delay_us(40);
	GPIO_ResetBits(Trig_Port, Trig_Pin);
	
	Timer_Init();//定时器初始化
}

uint16_t HCSR04_GetValue(void) //定时器中断测距
{
	HCSR04_Start();
	Delay_ms(100);
	return ((Time * 0.0001) * 34000) / 2;
//	return Time;                          
}


float GetLength(void) //输入捕获测距
{
	int i=0;
	float length=0;
	float sum=0;
	float Length;
	for(i=0;i<5;i++)
	{
		//减小误差,计算五次
		GPIO_SetBits(GPIOA,GPIO_Pin_5);
		Delay_us(20);//发送一段40us的高电平
		GPIO_ResetBits(GPIOA,GPIO_Pin_5);
		Time=TIM_GetCapture2(TIM3); //获取捕获值
		length=(Time/58.0);//固定计算超声波距离公式:时间/58.0;单位厘米
		sum=sum+length;
	}
	
	Length=sum/5.0;
	return Length;
}

HCSR04.h

#ifndef __HCSR04_H
#define __HCSR04_H

#define Trig_Port 		GPIOA
#define Trig_Pin 		GPIO_Pin_5
#define Trig_RCC		RCC_APB2Periph_GPIOA

#define Echo_Port 		GPIOA
#define Echo_Pin 		GPIO_Pin_6
#define Echo_RCC		RCC_APB2Periph_GPIOA

void HCSR04_Init(void);
uint16_t HCSR04_GetValue(void);
float GetLength(void);
	
#endif 

  • 20
    点赞
  • 90
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
实现STM32的两路超声波测距可以使用定时器和外部中断的方式,以下是一种基本的实现方法: 1. 初始化定时器和外部中断 使用STM32的定时器和外部中断功能,需要在代码中初始化并设置相应的参数。具体的配置可以参考开发板的手册或者相关的资料。 2. 配置超声波模块 将两个超声波模块连接到STM32的GPIO引脚上,并在代码中配置相应的引脚为输入模式。超声波模块通常需要发送一个脉冲信号来触发测距操作,所以还需要配置一个GPIO引脚为输出模式,用于发送触发信号。 3. 测距操作 在代码中使用定时器和外部中断来控制超声波的发送和接收,计算出测距的距离。具体的操作流程如下: - 发送触发信号:将控制超声波发送的GPIO引脚输出一个高电平脉冲信号,持续一段时间后自动恢复为低电平。 - 接收超声波信号:当超声波模块接收到触发信号后,会发送一定的超声波信号,并等待超声波反射回来。将接收超声波的GPIO引脚配置为外部中断模式,当接收到超声波信号时会触发中断,此时记录定时器的计数值。 - 计算距离:根据超声波的速度和计数值,计算出距离值。 4. 循环测距 使用以上的方法可以实现单次测距,如果需要连续测距,可以将以上的操作放在一个循环中,不断地发送触发信号并接收超声波信号,计算出距离值并输出到显示屏或者串口等输出设备中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值