STM32f407驱动hc-sr04超声波测距模块

最近完了一下测距模块,本想挺简单的一个东西,却折腾了好长时间。总算弄好了,贴到这里和大家分享一下!

HC-SR04超声波测距模块是一种被用烂了的传感器,它的优点是成本低,控制容易,但是掌握不好时序,还是会弄的人一头雾水。

本模块用使用方法如下:

一.  5v直流电压供电,一般的单片机上自带的VCC都能驱动

二.  Trig引脚收到来自单片机时长大于等于20us的高点品后发出超声波

三.  Echo引脚接收Trig引脚发出的超声波的回波,并且单片机开启定时器记录高电平时间

四. 高电平结束后,关闭定时器,从定时器寄存器中取出记录值,换算成距离即可。

在做的过程中注意:

网上有好多代码,但是大多数互相抄袭,而且代码质量都不怎么高,每一句话什么意思也不明白,所以不要照抄网上那些代码,还是要自己琢磨;

在换算距离时,网上的代码各种各样,但结果都不符合实际,于是自己算了一下:

在我的程序中,定时器计时频率是200000,周期就是1/200000,在这个周期里,超声波走的距离是(1/200000)*344/2=0.00085米,换算成毫米是0.86米,精度符合要求。

在获取定时器的计数器值TIM,于是TIM*0.85就是实际距离,单位是毫米。

另外,超声波测距模块的最远测量距离是4米,可以算出距离在4米事定时器的计数值,x*340=4,得x=5000,所以设置定时器的溢出周一为5000.

好了,贴上代码吧!

int main(void)
{
  LED_Init();
  GPIO_Configuration();
  TIM2_Configuration(5000,419);  //定时器频率200000
  
  while (1)
  {
    diatance_Data = get_Diatance();   //得到的距离单位是毫米
    qian = diatance_Data/1000;
    bai = diatance_Data/100%10;
    shi = diatance_Data/10%10;
    ge = diatance_Data%10;
    diatance_Data = qian*1000+bai*100+shi*10+ge;
    if(TIM2_Flag == 1)
    {
      //GPIOD->ODR|=1<<12;    //LED12闪烁
      TIM2_Flag = 0;
    }
    if(diatance_Data<200)     //定义距离在某一范围内
    {
      GPIO_SetBits(GPIOB, GPIO_Pin_10);
    }
    else
    {
      GPIO_ResetBits(GPIOB, GPIO_Pin_10);
    }
  }
}

void Delay(__IO uint32_t nCount)
{
  while(nCount--)
  {
  }
}

void LED_Init()
{
  GPIO_InitTypeDef  GPIO_InitStructure;
  
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  
  GPIO_Init(GPIOD, &GPIO_InitStructure);
}
void GPIO_Configuration()
{
  GPIO_InitTypeDef  GPIO_InitStructure;
  
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
  /*echo*/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  /*trig*/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  /*LED*/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  
  GPIO_Init(GPIOB, &GPIO_InitStructure);
}
void TIM2_Configuration(u16 arr, u16 psc)
{
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructrue;
  NVIC_InitTypeDef NVIC_InitStructure;
  
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
  TIM_DeInit(TIM2);
  
  TIM_TimeBaseStructrue.TIM_Period = arr;                   //定时周期
  TIM_TimeBaseStructrue.TIM_Prescaler = psc;                //欲分频数
  TIM_TimeBaseStructrue.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_TimeBaseStructrue.TIM_CounterMode = TIM_CounterMode_Up;
  
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructrue);
  TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
  
  NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;              //定时器3中断
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x00; //抢占优先级1
  NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x01;        //响应优先级3
  NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
  
  NVIC_Init(&NVIC_InitStructure);                            //初始化NVIC
  
  TIM_Cmd(TIM2, DISABLE); 
}
int get_Diatance()
{
  int distance = 0;
  u16 TIM = 0;
  TIM_Cmd(TIM2, ENABLE);            //开启定时器开始记录
  
  GPIO_SetBits(GPIOB, GPIO_Pin_1);  //给trig大于10us的高电平
  Delay(3000);
  GPIO_ResetBits(GPIOB, GPIO_Pin_1);
 
  while((!GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0))&&TIM2_Flag==0);  //等待echo高电平
  TIM2->CNT = 0;               //定时器计数器置零,因为从这里开始记录高电平时间
  while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0)&&TIM2_Flag==0);    //等待低电平
  TIM_Cmd(TIM2, DISABLE);      //高电平结束,关闭定时器
  
  if(TIM2_Flag==1)
    TIM2_Flag = 0;
  
  TIM = TIM_GetCounter(TIM2);
  distance = TIM*0.85;
  return distance;
}

/************************中断处理函数****************************/
void TIM2_IRQHandler(void)
{
  if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
  {
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    TIM2_Flag=1;
  }
}



你可能感兴趣的:(嵌入式)