超声波传感器-HC-SR04

     

   HC-SR04 超声波测距模块可提供 2cm-400cm 的非接触式距离感测功能,测距精度可达高到 3mm;

一、超声波工作原理

1、CH-SR04    相关电气参数 

二、计算公式(理解时参考时序图)

(1)采用 IO 触发测距,给至少 10us 的高电平信号;

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

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

(4)超声波从发射到返回的时间.测试距离=(高电平时间*声速(340M/S))/2;

        在此只需要提供一个 10uS 以上脉冲触发信号,该模块内部将循环发出 8 个 40kHz 周期电平并检测回波。一旦检测到有回波信号则输出回响信号。 回响信号的脉冲宽度与所测的距离成正比。由此通过发射信号到收到的回响信号时间间隔可以计算得到距离。公式:uS/58=厘米或者 uS/148=英寸;或是:距离= 高电平时间 * 声速(340M/S)/2;建议测量周期为 60ms 以上,以防止发射信号对 回响信号的影响。

三、超声波时序图

四、定时器计时原理

● 计数器寄存器(TIMx_CNT)
● 预分频寄存器(TIMx_PSC)
● 自动重装载寄存器(TIMx_ARR)

  1.  时钟源(CK_INT)
    定时器时钟 TIMxCLK,即内部时钟 CK_INT,经 APB1 预分频器后分频提供,如果 APB1 预分频系数等于 1,则频率不变,否则频率乘以 2,库函数中 APB1 预分频的系数是 2,即 PCLK1=36M,所以定时器时钟 TIMxCLK=36*2=72M
  2. 预分频器(PSC)
    PSC 是一个 16 位的预分频器,可以对定时器时钟 TIMxCLK 进行 1~65536 之间的任何一个数进行分频。具体计算方式为: CK_CNT=TIMxCLK/(PSC+1)
     
  3. 计数器(CNT)
    计数器 CNT 是一个 16 位的计数器,只能往上计数,最大计数值为 65535。当计数达到自动重装载寄存器的时候产生更新事件,并清零从头开始计数。
     
  4. 自动重装载寄存器(ARR)
    自动重装载寄存器 ARR 是一个 16 位的寄存器,这里面装着计数器能计数的最大数值。当计数到这个值的时候,如果使能了中断的话,定时器就产生溢出中断。

 定时器预分频器设置

	// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
    TIM_TimeBaseStructure.TIM_Period = BASIC_TIM_Period;	

	  // 时钟预分频数为
    TIM_TimeBaseStructure.TIM_Prescaler= BASIC_TIM_Prescaler;

当内部时钟经过PSC预分频器分频后,1000 000Hz, 也就是1us ,ARR设置为1000,意味着,CNT计数器每1us记录一次 , 当1ms 时ARR寄存器清零。

五、公式推导

  因为时钟以微秒为最小计算单位,所有方便理解,将所有的转换成微妙计算

  distance = 定时器时间 (s)* 340(m/s) / 2 

distance = 定时时间(us)* 34000  / 2 / 1000 000  = 定时时间(us)* 0.017

另一种算法:distance = 定时时间(us) / 58

六、相关注意事项:

1、此模块不宜带电连接,若要带电连接,则先让模块的 GND 端先连接,否则会影响 模块的正常工作。

2、测距时,被测物体的面积不少于 0.5 平方米且平面尽量要求平整,否则影响测量的结果

3、当传感器紧贴物体表面时,会出现数值错误,

七、参考文献

(19条消息) 超声波测距为什么除以58_超声波测距公式为什么除以58_总结所学的博客-CSDN博客

深圳市捷深科技有限公司 (raincorn.top)

相关代码

       Ultrasonic.c

/**
  * @brief  超声波相关引脚初始化
  * @param  NULL
  * @retval NULL
  */
static void UltrasonicGpioModeConfig(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    RCC_TE_PeriphClockCmd(ECHO_TRIG_CLK_ENR,ENABLE);    //引脚时钟使能

    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);          //TRIG 引脚

    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;      //ECHO 设置为上拉输入,接受信号
    GPIO_InitStruct.GPIO_Pin =  ECHO_PIN;
    // GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;   
    GPIO_Init(ECHO_PORT,&GPIO_InitStruct);          //ECHO 引脚

    TRIG_LOW();     /* 让两引脚初始化时处于低电平 */
    ECHO_LOW();
}



/**
  * @brief  定时器中断配置
  * @param  NULL
  * @retval NULL
  */
static void NVIC_TIME_Config(void)
{
    NVIC_InitTypeDef NVIC_InitStruct;
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);

    NVIC_InitStruct.NVIC_IRQChannel = BASIC_TIM_IRQ;
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3; 
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);

}
static void BASIC_TIM_Mode_Config(void)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
		
		// 开启定时器时钟,即内部时钟CK_INT=72M
    BASIC_TIM_APBxClock_FUN(BASIC_TIM_CLK, ENABLE);
	
		// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
    TIM_TimeBaseStructure.TIM_Period = BASIC_TIM_Period;	

	  // 时钟预分频数为
    TIM_TimeBaseStructure.TIM_Prescaler= BASIC_TIM_Prescaler;
	
		// 时钟分频因子 ,基本定时器没有,不用管
    //TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
		
		// 计数器计数模式,基本定时器只能向上计数,没有计数模式的设置
    //TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; 
		
		// 重复计数器的值,基本定时器没有,不用管
		//TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
	
	  // 初始化定时器
    TIM_TimeBaseInit(BASIC_TIM, &TIM_TimeBaseStructure);
		
		// 清除计数器中断标志位
    TIM_ClearFlag(BASIC_TIM, TIM_FLAG_Update);
	  
		// 开启计数器中断
    TIM_ITConfig(BASIC_TIM, TIM_IT_Update,ENABLE);
		
		// 使能计数器
//    TIM_Cmd(BASIC_TIM, ENABLE);	
}

/**
  * @brief  超声波触发信号
  * @param  NULL
  * @retval NULL
  */
void WAVE_Start(void)
{
    TRIG_HIGH();                           //TRIG设置为高电平
    CPU_TS_Tmr_Delay_US(20);               //延时大于10us
    TRIG_LOW();
}


/**
  * @brief  超声波相关初始化
  * @param  NULL
  * @retval NULL
  */
void WAVE_Init(void)
{
    UltrasonicGpioModeConfig();
    NVIC_TIME_Config();
    BASIC_TIM_Mode_Config();
}

   Ultrasonic.h

#define TRIG_RCC_CLK_ENR            RCC_APB2Periph_GPIOA
#define RCC_TE_PeriphClockCmd       RCC_APB2PeriphClockCmd
#define TRIG_PORT			        GPIOA
#define TRIG_PIN			        GPIO_Pin_4

#define ECHO_RCC_CLK_ENR            RCC_APB2Periph_GPIOA
#define RCC_ECHO_ClockCmd           RCC_APB2PeriphClockCmd
#define ECHO_PORT 		            GPIOA
#define ECHO_PIN                    GPIO_Pin_5


#define ECHO_TRIG_CLK_ENR           (ECHO_RCC_CLK_ENR|TRIG_RCC_CLK_ENR)


#define BASIC_TIM6 // 如果使用TIM7,注释掉这个宏即可

#ifdef  BASIC_TIM6 // 使用基本定时器TIM6
#define            BASIC_TIM                   TIM6
#define            BASIC_TIM_APBxClock_FUN     RCC_APB1PeriphClockCmd
#define            BASIC_TIM_CLK               RCC_APB1Periph_TIM6
#define            BASIC_TIM_Period            (1000-1)           
#define            BASIC_TIM_Prescaler         (72-1)           //      72000000/72 *1000= 1000us = lms
#define            BASIC_TIM_IRQ               TIM6_IRQn
#define            BASIC_TIM_IRQHandler        TIM6_IRQHandler

#else  // 使用基本定时器TIM7
#define            BASIC_TIM                   TIM7
#define            BASIC_TIM_APBxClock_FUN     RCC_APB1PeriphClockCmd
#define            BASIC_TIM_CLK               RCC_APB1Periph_TIM7
#define            BASIC_TIM_Period            1000-1
#define            BASIC_TIM_Prescaler         71
#define            BASIC_TIM_IRQ               TIM7_IRQn
#define            BASIC_TIM_IRQHandler        TIM7_IRQHandler

#endif    


#define TRIG_HIGH()                  GPIO_SetBits(TRIG_PORT,TRIG_PIN)
#define TRIG_LOW()                   GPIO_ResetBits(TRIG_PORT,TRIG_PIN)

#define ECHO_HIGH()                  GPIO_SetBits(ECHO_PORT,ECHO_PIN)
#define ECHO_LOW()                   GPIO_ResetBits(ECHO_PORT,ECHO_PIN)                

void WAVE_Init(void);
void WAVE_Start(void);

main.c

float distance;
volatile uint32_t time=0;
uint32_t TIME = 0;

int main(void)
{
	uint8_t i;

	USART_Config();
	SysTick_Init();

	LED_GPIO_Config();

	WAVE_Init();

	while (1)
	{
		for (i = 0; i < 5; i++)		//求均值,避免误差
		{
			
			WAVE_Start(); // 开启信号

			while (GPIO_ReadInputDataBit(ECHO_PORT, ECHO_PIN) == RESET); // ECHO 为高电平

			TIM_SetCounter(BASIC_TIM, 0);
			time =0;

			TIM_Cmd(BASIC_TIM, ENABLE);

			while(GPIO_ReadInputDataBit(ECHO_PORT, ECHO_PIN) == SET); // 等待ECHO 低电平

			TIM_Cmd(BASIC_TIM, DISABLE);

			
			TIME += ((time*1000)+ TIM_GetCounter(BASIC_TIM));
			printf("采集到的时间为 %d us\n", TIME);

		}

		printf("采集到的时间平均值 %d ms\n", (TIME/5));
		
		 distance = (TIME/5 * 0.017  );		//第一种算法
		
		//distance = (((TIME) /58 ));		//第二种算法

		
		printf("Distance:%f cm\r\n", distance);
		TIME=0;
		Delay_ms(2000);
		
	}
}

stm32f10x_it.h


extern volatile uint32_t time ;

void TIM6_IRQHandler(void)
{
  if(TIM_GetITStatus(BASIC_TIM,TIM_IT_Update)!=RESET)
  {
     time++;
    TIM_ClearITPendingBit(BASIC_TIM, TIM_IT_Update);
  }
  
}

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值