基于stm32的HC-SR04超声波测距模块使用

北城以北 提交于 2020-04-06 19:09:17

1 工作原理

使用超声波模块之前,先了解其IO口和工作原理:

1.1 IO说明

VCC: 供5V电源
GND: 为地线
TRIG: 触发控制信号输入
ECHO: 回响信号输出

 

 

1.2 基本工作原理:

认真看好以下工作原理,后面的代码就是基于工作原理来实现的。
(1)采用IO口TRIG触发测距,给最少10us的高电平信号。
(2)模块自动发送8个40khz的方波,自动检测是否有信号返回;
(3)有信号返回, 通过IO口ECHO输出一个高电平,高电平持续的时间就是超声波从发射到返回的时间。 测试距离=(高电平时间*声速(340M/S))/2
时序图:

 

 

2 程序编写

2.1 外设配置


根据两个信号引脚来配置两个单片机的IO口
trig: 需要产生一个10us高电平, 配置为推挽输出;
echo: 等待高电平脉冲并测量其脉冲宽度, 配置为下拉输入
测量echo的高电平持续的时间,需要用到定时器, 因此配置一个定时器,用来计时

void UltrasonicWave_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;    
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//开启GPIOB时钟
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启TIM2时钟    

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;    // 对应trig引脚
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  GPIO_ResetBits(GPIOB,GPIO_Pin_1);    

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;    // 对应echo引脚
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //下拉输入
  GPIO_Init(GPIOB, &GPIO_InitStructure);    

//定时器初始化,分频系数为71,则频率为1MHZ,每个计数为1us,(频率越高越精确)
//重装载值为65535,溢出时间为1us*65536=    65.536ms=0.065536s
//一个计数周期可以测距 0.065536s * 340m/s / 2 = 11.14112m
  TIM_TimeBaseStructure.TIM_Period = 65535; 
  TIM_TimeBaseStructure.TIM_Prescaler = 71; 
  TIM_TimeBaseStructure.TIM_ClockDivision = 0; 
  TIM_TimeBaseStructure.TIM_CounterMode = 
  TIM_CounterMode_Up; 
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //    
}

2.2 测距函数

根据工作原理 :
(1)采用IO口TRIG触发测距,给最少10us的高电平信号。

/***** 启动超声波 *****/

void UltrasonicWave_StartMeasure(void)
{
  GPIO_SetBits(GPIOB, GPIO_Pin_1); //拉高PB1电平
  delay_us(20);            //持续20us
  GPIO_ResetBits(GPIOB, GPIO_Pin_1); //拉低PB1电平
}

(2)有信号返回, 通过IO口ECHO输出一个高电平,高电平持续的时间就是超声波从发射到返回的时间。 测试距离=(高电平时间*声速(340M/S))/2

/***** 测距 *****/
float UltrasonicWave_Measure(void) //
{
  while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10)==1);//echo为高电平时,则等待至低电平,才启动超声波
  UltrasonicWave_StartMeasure(); //启动超声波    
  while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10) == 0);//等待 echo的高电平到来    
  TIM_SetCounter(TIM2,0); //清零计数器
  TIM_Cmd(TIM2, ENABLE); //使能定时器2,开始计数
  while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_10) == 1);//等待 echo的高电平结束
  TIM_Cmd(TIM2, DISABLE);    //失能定时器2,截止计数    
  return (TIM_GetCounter(TIM2))/1000000*340/2 *100;    //此处单位转换为cm
}

2.3 测距

int main()
{
  float distance;
  UltrasonicWave_Init(void);//初始化
  delay_init();
  while(1)
  {
    distance = UltrasonicWave_Measure(void); //完成测距
    delay_ms(60);//建议测量周期为 60ms以上, 以防止发射信号对回响信号的影响。
    printf("distance:%5.2f ",distance);//打印到串口
  }    
}

还可以使用中断方式进行测距, 大致框架如下, 有兴趣自行研究

//先开启对应引脚双边沿触发中断, 中断服务函数大致如下
float Distance;
void EXTI15_10_IRQHandler(void)
{    
  if(//发生中断)
  { 
    if(//上升沿) 
    {
      TIM_SetCounter(TIM2,0); //清零计数器
      TIM_Cmd(TIM2, ENABLE); //使能定时器2,开始计数
    }
    if(//下降沿)
    {
      TIM_Cmd(TIM2, DISABLE);    //失能定时器2,截止计数
      Distance=(TIM_GetCounter(TIM2))/1000000*340/2 *100;//此处单位转换为cm
    }
  }
  EXTI_ClearITPendingBit(EXTI_Line10); //清除中断标志    
} 

//主函数
extern float Distance;
int main()
{
  UltrasonicWave_Init(void);//初始化
  while(1)
  {
    UltrasonicWave_StartMeasure();//启动超声波
    delay_ms(60);//建议测量周期为 60ms以上, 以防止发射信号对回响信号的影响。
  //Distance 在中断服务函数中被重新赋值
    printf("Distance:%5.2f ",Distance);//打印到串口
  }    
}

以上超声波模块的使用一次记录,欢迎一起讨论
版权声明:本文为CSDN博主「hhh_little_hu」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_40134414/article/details/105290644

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!