STM32小车篇之超声波测距

超声波模块测量距离防碰撞

1.超声波测距:
原理:超声测距其实就是通过单片机控制超声波模块发出一系列超声波,当超声波遇到障碍物时反弹回来,根据声音在空气中的传播速率340m/s,再结合上述所讲的方法求得时间t,应用初高中物理知识,即可求解距离。(驱动超声波模块需要给它一个10-20us高电平)
测量距离=(高电平持续时间(340M/S))/2
例子详解:我们算出的高电平时间是以us为单位,因此我们可以把声波传输速度看成大约为340M/S,合34,000CM/S。 即34,000除以1,000,000CM/US。 即为:0.0340CM/US 换种角度:1/(0.0343 CM/US) 即:29.00 US/CM。 这就意味着,每290.0US表示10CM的距离。1厘米就是29.00US。 但是发送后到接收到回波,声音走过的是2倍的距离呀。 所以实际距离就是1厘米,对应58.0US。
即 测量距离=(高电平持续时间/58.0(CM))

2.输入捕获:
基本原理:定时器的输入捕获模式可以用来测量脉冲宽度或者测量频率。除了基本定时器,通用和高级均有输入捕获功能。如图所示:
STM32小车篇之超声波测距_第1张图片

  首先,我们设定定时器工作模式为向上计数模式,图中t1-t2时间间隔就是我们需要测量的脉宽时间(即高电平时间)。测量方法如下:
1: 设定定时器某通道为上升沿捕获,这样在t1时刻,就会捕获到当前值CNT值,然后马上清零,同时设置该通道为下降沿捕获,这样到t2时刻,又发生捕获事件,得到此时的CNT值,记为CCRx2。这样,根据定时器的计数频率可以算出t1-t2的时间,从而得到高电平脉宽。
2:在t1-t2的时间段里,有可能发生N次溢出,我们需要对此进一步处理,防止高电平过长,导致数据不准确。因此,CNT计数的次数等于N*ARR+CCRx2,有了这个计数次数,再乘以 CNT 的计数周期,即可得到 t2-t1 的时间长度,即高电平持续时间。

3.(超声波模块)HC_SRO4
实验中所实验的 HC-SR04超声波模块主要是由两个通用的压电陶瓷超声传感器,并加外围信号处理电路构成的。
1)引脚和原理:
该模块有VCC、GND、Trig和Echo针脚。TRIG是输出和ECHO是输入。
该模块的工作原理为:模块所需要的供电是5V
1.先向TRIG脚输入至少10us的触发信号
2.该模块内部将发出 8 个 40kHz 周期电平并检测回波。
3.一旦检测到有回波信号则ECHO输出高电平回响信号。回响信号的脉冲宽度与所测的距离成正比
4.由此通过发射信号到收到的回响信号时间间隔可以计算得到距离。公式: 距离=高电平时间*声速(340M/S)/2。

2)实现功能:通过超声波模块测距离,并将测试距离显示到串口助手上。
根据工作原理,我们可以选择两种模式驱动
1.采用中断+定时器方式,将ECHO定义为上升沿下降沿都能触发中断,trig触发之后,echo高电平进中断打开定时器,echo低电平关闭定时器并统计定时器计数值
2.采用普通IO+定时器模式,触发之后等待echo响应,响应时打开定时器,直到echo恢复低关闭定时器,获取时间

注1:此模块不宜带电连接,如果要带电连接,则先让模块的 Gnd 端先连接。否则会影响模块工作。
注2:测距时,被测物体的面积不少于0.5平方米且要尽量平整。否则会影响测试结果。

通过上面原理的学习,再通过代码hcsr04.c文件加深理解:

#define HCSR04_PORT     GPIOA
#define HCSR04_CLK      RCC_APB2Periph_GPIOA
#define HCSR04_TRIG     GPIO_Pin_4
#define HCSR04_ECHO     GPIO_Pin_0
 
#define TRIG_Send  PAout(4)
#define ECHO_Reci  PAin(0)
 
u16 msHcCount = 0;//整型变量用于ms计数
extern u16 TIM2CH1_CAPTURE_STA,TIM2CH1_CAPTURE_VAL;
void Hcsr04_Init(u32 arr,u32 psc)
{
	  TIM_ICInitTypeDef TIM_ICInitStructure;
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;    
	  GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(HCSR04_CLK, ENABLE);
   
    
	  //IO初始化
    GPIO_InitStructure.GPIO_Pin =HCSR04_TRIG;       //TRIG输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
    GPIO_Init(HCSR04_PORT, &GPIO_InitStructure);
    GPIO_ResetBits(HCSR04_PORT,HCSR04_TRIG);
    
    GPIO_InitStructure.GPIO_Pin =   HCSR04_ECHO;		//ECHO输入
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;//下拉输入
    GPIO_Init(HCSR04_PORT, &GPIO_InitStructure);	
	
  	//初始化定时器TIM2
	  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);   //使能RCC时钟
	  TIM_DeInit(TIM2); 
  	TIM_TimeBaseStructure.TIM_Period = arr; //计数周期为1000/1ms
	  TIM_TimeBaseStructure.TIM_Prescaler =psc; //1M的计数频率  1US计数
	  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //不分频
	  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
		TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); 
		

//	  TIM_ICStructInit(&TIM_ICInitStructure);//设置缺省值
	  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;	//上升沿捕获
	  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
  	TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;	  //配置输入分配
	  TIM_ICInitStructure.TIM_ICFilter = 0x00;	  //IC2F=0000 配置输入滤波器 0 不滤波
  	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; //IC1映射到TI1
	  TIM_ICInit(TIM2, &TIM_ICInitStructure);
		
		
		
//		TIM_ClearFlag(TIM2, TIM_FLAG_Update);   //清除更新中断
  	TIM_ITConfig(TIM2,TIM_IT_Update|TIM_IT_CC1,ENABLE);    //打开定时器更新中断
    TIM_CtrlPWMOutputs(TIM2,ENABLE);	//主输出使能
		Hcsr04_NVIC();
	  TIM_Cmd(TIM2, ENABLE);
}
void Hcsr04_NVIC(void)
{  
    NVIC_InitTypeDef NVIC_InitStructure;  
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
      
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;             
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;   
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;           
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;        
    NVIC_Init(&NVIC_InitStructure);  
}

 
 
//TIM2的中断服务函数
void TIM2_IRQHandler(void)   
{
		  if((TIM2CH1_CAPTURE_STA&0X80)==0)//还未成功捕获
    {      
        if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
         
        {        
            if(TIM2CH1_CAPTURE_STA&0X40)//已经捕获到高电平
            {
                if((TIM2CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长
                {
                    TIM2CH1_CAPTURE_STA|=0X80;//标记成功捕获了一次
                    TIM2CH1_CAPTURE_VAL=0XFFFF;
                }
								else 
									TIM2CH1_CAPTURE_STA++;
            }     
        }
			}
    if (TIM_GetITStatus(TIM2, TIM_IT_CC1) != RESET)//捕获1发送捕获事件
        {    
            if(TIM2CH1_CAPTURE_STA&0X40)        //捕获到一个下降沿      
            {                  
                TIM2CH1_CAPTURE_STA|=0X80;        //标记成功捕获到一次上升沿
                TIM2CH1_CAPTURE_VAL=TIM_GetCapture1(TIM2);
                TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Rising); //CC1P=0 设置为上升沿捕获
            }else   //还未开始,第一次捕获上升沿
            {
                TIM2CH1_CAPTURE_STA=0;            //清空
                TIM2CH1_CAPTURE_VAL=0;
                TIM_SetCounter(TIM2,0);
                TIM2CH1_CAPTURE_STA|=0X40;        //标记捕获到了上升沿
                TIM_OC1PolarityConfig(TIM2,TIM_ICPolarity_Falling); //CCC1P=1 设置为下降沿捕获
            }            
        }                                                

 
    TIM_ClearITPendingBit(TIM2, TIM_IT_CC1|TIM_IT_Update); //清楚中断标志位
    }

你可能感兴趣的:(stm32,单片机)