一、HC_SR04简述
HC-SR04超声波测距模块可提供 2cm-400cm的非接触式距离感测功能,测距精度可达高到 3mm;模块包括超声波发射器、接收器与控制电路。
基本工作原理:
(1)采用IO 口TRIG 触发测距,给最少10us 的高电平信呈。
(2)模块自动发送8 个40khz 的方波,自动检测是否有信号返回;
(3)有信号返回,通过IO 口ECHO 输出一个高电平,高电平持续的时间就是超声
波从发射到返回的时间。测试距离=(高电平时间*声速(340M/S))/2;
注意:当测距时间大于38ms时,便超时了,这是无论如何,ECHO都会被拉低
二、代码编写
通过定时器定时测量测距时间再通过上述公式计算对应的距离,这里定时器可以通过定时中断计时。
1.定时器基本配置
#include "Timer.h"
void Timer_Init(uint16_t ARR,uint16_t PSC)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);
TIM_TimeBaseInitTypeDef Tim4_InitStructure;
Tim4_InitStructure.TIM_ClockDivision=TIM_CKD_DIV1;//不分频
Tim4_InitStructure.TIM_CounterMode=TIM_CounterMode_Up;//向上计数
Tim4_InitStructure.TIM_Period=ARR;
Tim4_InitStructure.TIM_Prescaler=PSC;
Tim4_InitStructure.TIM_RepetitionCounter=0x00;
TIM_TimeBaseInit(TIM4,&Tim4_InitStructure);
TIM_ClearFlag(TIM4, TIM_FLAG_Update); //清除由于初始化而置的标志位
TIM_Cmd(TIM4,DISABLE);
TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);
/***************初始化定时器,开启更新中断****************/
NVIC_InitTypeDef TIM4_IT_InitStructure;
TIM4_IT_InitStructure.NVIC_IRQChannel=TIM4_IRQn;
TIM4_IT_InitStructure.NVIC_IRQChannelCmd=ENABLE;
TIM4_IT_InitStructure.NVIC_IRQChannelPreemptionPriority=4;
TIM4_IT_InitStructure.NVIC_IRQChannelSubPriority=4;
NVIC_Init(&TIM4_IT_InitStructure);
}
2.传感器函数编写
1.基本配置
#include "HC_SR04.h"
#define Trigo GPIO_Pin_14
#define Echo GPIO_Pin_15
static uint16_t count;
/*内部调用*/
/**********Trigo为输出引脚************/
void Trigo_Write(uint8_t val)
{
GPIO_WriteBit(GPIOE,Trigo,(BitAction)val);
}
/**********Echo为输入引脚************/
/*内部调用*/
uint8_t Echo_Read(void)
{
return GPIO_ReadInputDataBit(GPIOE,Echo);
}
2.初始化
void HCSR04_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin=Trigo;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOE,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin=Echo;
GPIO_Init(GPIOE,&GPIO_InitStructure);
Trigo_Write(0);
}
3.距离测量
完整的时间=产生更新中断的次数*产生一次中断需要的时间+TIM->CNT里的时间
/*CNT f=1000 000HZ */
/*ARR 1000*/
/*PSC 72 */
/*假设返回单位为cm distance=340*100*time/2/1000 000 */
float HCSR04_GetDistance(void)
{
/****************先将Trigo拉高*******************/
Trigo_Write(1);
/****************延迟20us确保脉冲足够触发测距*******************/
delay_us(20);
/****************再拉低脉冲使其开始测距*******************/
Trigo_Write(0);
/****************当Echo变高时便说明其开始测距*******************/
while(Echo_Read()==0);
/****************开启定时器,开始计数*******************/
TIM_Cmd(TIM4,ENABLE);
/****************测距结束的时候便是Echo再次变低*******************/
while(Echo_Read()==1);
/****************计算时间,即为完整的产生中断的时间加上CNT上的时间*******************/
float time=count*1000+TIM4->CNT;
printf("time:%f\r\n",time);
/****************超时判断*******************/
if(time/1000>38)//如果大于38ms则不能测距
{
return 0;
}
/****************再次清零,回到开始状态等待下一次的测距指令*******************/
count=0;
TIM4->CNT=0;
/****************失能定时器*******************/
TIM_Cmd(TIM4,DISABLE);
/****************返回距离*******************/
float distance;
distance=time*340/2/10000;
return distance;
}
/****************中断函数用于计时*******************/
void TIM4_IRQHandler(void)
{
if(TIM_GetITStatus(TIM4,TIM_IT_Update)==SET)
{
count++;
TIM_ClearITPendingBit(TIM4,TIM_IT_Update);
}
}
4.主函数
#include "main.h"
float distance;
int main(void)
{
delay_init();
uart_init(115200);
Timer_Init(1000,72);
NVIC_PriorityGroupConfig (NVIC_PriorityGroup_2 );
HCSR04_Init();
while(1)
{
distance=HCSR04_GetDistance();
if(distance) printf("distance :%f\r\n",distance);
else printf("distance erro\r\n");
delay_ms(500);
}
}
三、最终现象
实际距离约18-20cm,通过串口观察现象可知符合现象
超时检测
以上便是本次学习的记录