超声波传感器-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
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
您将学习如何将超声波传感器HC-SR04与Arduino连接。它可以是超声波范围传感器或任何用途。 超声波传感器HC-SR04是可以测量距离的传感器。它会发出40 000 Hz(40kHz)的超声波,该超声波在空中传播,如果路径上有物体或障碍物,它将反弹回模块。考虑到传播时间和声音的速度,您可以计算出距离。 HC-SR04的配置引脚为VCC(1),TRIG(2),ECHO(3)和GND(4)。VCC的电源电压为+ 5V ,您可以将TRIG和ECHO引脚连接到Arduino板中的任何数字I / O。 进行此项目所需的材料: 1. Arduino UNO R3 CH340(您可以使用任何Arduino开发板) 2.超声波传感器HC-SR04 3.公对公跳线 4.面包板 为了产生超声波,我们需要将触发引脚设置为高状态10 s 。这将发出一个8周期的声音脉冲,将以速度声音行进,并且将在回音针中接收。回音针将输出声波传播的时间(以微秒为单位)。 例如,如果物体距传感器20厘米,并且声音的速度为340 m / s或0.034 cm / µs,则声波将需要传播约588微秒。但是由于声波需要向前传播和向后反弹,所以从回声针所得到的将会是这个数字的两倍。因此,为了获得以厘米为单位的距离,我们需要将从回波引脚接收的行进时间值乘以0.034,然后将其除以2。 对于编程代码,首先我们需要定义连接到Arduino板的触发引脚和回波引脚。在此项目中,EchoPin附加到D2 ,TrigPin附加到D3。然后定义距离(整数)和持续时间(长整数)的变量。 在循环中,首先必须确保trigPin是透明的,所以我们必须将该引脚设置为LOW状态仅2 µs 。现在,用于生成超声波,我们必须设置trigPin的高态为10微秒。使用pulseIn()函数,您必须读取行程时间并将该值放入变量“ duration”中。此功能有2个参数,第一个是回波引脚的名称,第二个可以写入HIGH或LOW。在这种情况下,HIGH表示pulseIn()该功能将等待由反弹的声波引起的引脚变为高电平并开始计时,然后在声波结束时等待引脚变为低电平而停止计时。最后,该函数将返回脉冲长度(以微秒为单位)。为了获得距离,我们将持续时间乘以0.034,然后将其除以2,如我们之前解释此方程式。最后,我们将在串行监视器上打印距离的值。 脚步 : 1.首先进行如图所示的接线 2.打开Arduino IDE软件并写下您的代码,或下载下面的代码并打开它 3.通过选择工具>板> Arduino / Geniuno Uno选择您自己的Arduino板(在本例中为Arduino Uno) 4.选择“ COM端口”(通常只显示一个现有端口),在“工具” >“端口” >“ COM。”中。(如果有多个端口,请一一尝试) 5.通过按Ctrl + U或Sketch > Upload上载代码 6.要显示测量数据,可以使用串行监视器,方法是按Ctrl + Shift + M (确保波特率是9600) 上载代码后,使用串行监视器显示数据。现在,尝试将一个物体放在传感器前面,然后查看测量结果。 考虑到这一点,您可以使用手动卷尺测量距离并将其与串行监视器上的距离进行比较。如果要在LCD上显示,可以按照第二个接线图并上传以下代码。
以下是 CC2530 控制超声波传感器和步进电机的程序示例: ```c #include "contiki.h" #include "dev/serial-line.h" #include "dev/leds.h" #include "dev/cc2530-rf.h" #include "dev/sht11-sensor.h" #include "dev/ultrasonic-sensor.h" #include "dev/stepper-motor.h" PROCESS(main_process, "Main process"); AUTOSTART_PROCESSES(&main_process); PROCESS_THREAD(main_process, ev, data) { PROCESS_BEGIN(); // 初始化超声波传感器和步进电机 ultrasonic_sensor_init(); stepper_motor_init(); while (1) { static struct etimer et; // 每隔 1 秒启动超声波传感器并读取距离 etimer_set(&et, CLOCK_SECOND); PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); ultrasonic_sensor_start(); int distance = ultrasonic_sensor_read(); // 如果距离小于 10 厘米则启动步进电机 if (distance < 10) { // 步进电机向前转动 50 步 stepper_motor_step(50, STEPPER_MOTOR_DIRECTION_FORWARD); // 等待一段时间后再将步进电机向后转动 50 步 etimer_set(&et, CLOCK_SECOND / 2); PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et)); stepper_motor_step(50, STEPPER_MOTOR_DIRECTION_BACKWARD); } } PROCESS_END(); } ``` 在这个示例程序中,我们使用了 Contiki 操作系统和 CC2530 的 GPIO 端口控制超声波传感器和步进电机。首先,我们在主进程中初始化超声波传感器和步进电机。然后,我们使用一个循环来启动超声波传感器并读取距离。如果距离小于 10 厘米,则启动步进电机。 在步进电机启动时,我们使用 `stepper_motor_step()` 函数来控制步进电机向前或向后转动一定的步数。我们还使用了 `etimer_set()` 函数来设置延迟时间以便在步进电机向前转动一段时间后再将其向后转动。这个延迟时间也可以根据具体的步进电机和应用需求进行调整。 需要注意的是,这个示例程序中使用了 Contiki 操作系统和 CC2530 的特定驱动程序和库函数,如果您使用的是其他硬件或操作系统,则需要相应地修改代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值