输入捕获–超声波测距

  • Post author:
  • Post category:其他



1.HC-SR04基本工作原理


(1)采用IO口TRIG触发测距,给最少10us的高电平信呈。

(2)模块自动发送8个40khz的方波,自动检测是否有信号返回;

(3)有信号返回, 通过IO口ECHO输出一个高电平, 高电平持续的时间就是超声波从发射到返回的时间。

测试距离=(高电平时间*声速(340M/S))/2



在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


2.关于超声波测距的细节

超声波测距时间非常快,所以定时器的频率也要很快,预分频为72的时候,定时器每隔1us记一个数,如果ARR的值设定为50000,那超声波最远可以测量0.034*50000=1700cm,所以不用考虑超声波接收到的信号中,两个边沿时间会超过ARR的情况,况且这个超声波测量距离有限,所以基本不可能存在这种情况


3.超声波测距有三种思路

(Echo—PA0   Trig—PA1)

1)通过读取GPIO口的状态来开启和关闭定时器,清除和读取CNT的值

预先拉低Trig引脚—-拉高Trig—-延迟15us—-拉低Trig—-清空CNT—

等待高电平—-开启定时器—-等待低电平—- 关闭定时器—获取定时器的值—计算得到距离

可看这位兄弟写的:

基于STM32的超声波HC-SR04详解_Lzjusc2017的博客-CSDN博客_hcsr04 stm32

2)外部中断的方式

思路跟第一种方法类似,外部中断是上升沿触发,在外部中断函数中等待低电平,其他操作跟第一种方法差不多

3)输入捕获的方式

定时器2的输入捕获通道1的配置

void Timer2_Capture1_Init(void){
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	TIM_ICInitTypeDef TIM_ICInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
	TIM_InternalClockConfig(TIM2);
	
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;//Echo
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;//Trig
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	GPIO_ResetBits(GPIOA,GPIO_Pin_0|GPIO_Pin_1);
	
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInitStructure.TIM_Period=49999;
	TIM_TimeBaseInitStructure.TIM_Prescaler=72-1;//超声波的测距频率很高,1us记一次数
	TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
	TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
	
	TIM_ICInitStructure.TIM_Channel=TIM_Channel_1;
	TIM_ICInitStructure.TIM_ICFilter=0;
	TIM_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;
	TIM_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;
	TIM_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;
	TIM_ICInit(TIM2,&TIM_ICInitStructure);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;
	NVIC_Init(&NVIC_InitStructure);
	
	TIM_ITConfig(TIM2,TIM_IT_Update|TIM_IT_CC1,ENABLE);
	
	TIM_Cmd(TIM2,ENABLE);
}

中断函数,每采样5次取平均值

void TIM2_IRQHandler(void){
	//如果捕获到了一个上升沿,清除标志位,清空CNT,准备捕获下降沿
	if(TIM_GetITStatus(TIM2,TIM_IT_CC1)==SET&&Falling_Flag==0){	
		TIM_ClearITPendingBit(TIM2,TIM_IT_CC1);
		TIM_SetCounter(TIM2,0);
		Falling_Flag=1;
		TIM_OC1PolarityConfig(TIM2,TIM_OCPolarity_Low);
	}
	//如果捕获到了一个下降沿,清空标志位,保存计数值并进行计算(包含定时器溢出的情况),清空CNT,准备捕获上升沿
	else if(TIM_GetITStatus(TIM2,TIM_IT_CC1)==SET&&Falling_Flag==1){	
		Capture1_Count=TIM_GetCapture1(TIM2);//得到最终的计数值(单位1us)
		TIM_SetCounter(TIM2,0);
		Falling_Flag=0;	
		TIM_OC1PolarityConfig(TIM2,TIM_OCPolarity_High);
		//测量五次取平均值
		Test_Num++;
		Capture1_Count_Sum+=Capture1_Count;
		if(Test_Num==5){
			OLED_ShowNum(3,1,Capture1_Count_Sum/300,3);//除以5得到平均时间,经过计算再除以58约等于60
			OLED_ShowNum(3,5,(int)(Capture1_Count_Sum/3)%100,2);//除以300得到距离,然后乘以100再对100 取余
			Capture1_Count_Sum=0;
			Test_Num=0;
		}
	}	
	TIM_ClearITPendingBit(TIM2,TIM_IT_Update|TIM_IT_CC1);
}

发送超声波

#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "Delay.h"
static uint8_t Falling_Flag;//0表示这次捕获是上升沿,1表示这次捕获是下降沿
static uint16_t Capture1_Count;//两个边沿之间的计数值
static uint32_t Test_Num,Capture1_Count_Sum;
void SR04_SendOut(void){
	GPIO_SetBits(GPIOA,GPIO_Pin_1);
	Delay_us(15);
	GPIO_ResetBits(GPIOA,GPIO_Pin_1);
}



版权声明:本文为weixin_61038901原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。