基於stm32的HC-SR04超聲波測距模塊使用


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM