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);
}