赞
踩
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);
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。