久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 8867|回復: 10
收起左側

STM32+HC-SR04超聲波測距

  [復制鏈接]
ID:302936 發表于 2018-4-6 22:16 | 顯示全部樓層 |閱讀模式
首先,先來看一下這個模塊的基本功能和原理。

HC-SR04超聲波測距模塊可提供2cm-400cm的非接觸式距離感測功能,測距精度可達高到3mm;模塊包括超聲波發射器、接收器與控制電路。像智能小車的測距以及轉向,或是一些項目中,常常會用到。智能小車測距可以及時發現前方的障礙物,使智能小車可以及時轉向,避開障礙物。

注意是5v輸入,但是我用stm32 的3.3v輸入也是沒有問題的。
892371-20160405175004984-1373897222.png
二.工作原理
      1.給超聲波模塊接入電源和地。
      2.給脈沖觸發引腳(trig)輸入一個長為20us的高電平方波
      3.輸入方波后,模塊會自動發射8個40KHz的聲波,與此同時回波引腳(echo)端的電平會由0變為1;(此時應該啟動定時器計時)
      4.當超聲波返回被模塊接收到時,回波引 腳端的電平會由1變為0;(此時應該停止定時器計數),定時器記下的這個時間即為超聲波由發射到返回的總時長。
      5.根據聲音在空氣中的速度為344米/秒,即可計算出所測的距離。
      要學習和應用傳感器,學會看懂傳感器的時序圖是很關鍵的,所以我們來看一下HC-SR04的時序觸發圖。
    892371-20160405175234031-1177610742.png

    我們來分析一下這個時序圖,先由觸發信號啟動HC-RS04測距模塊,也就是說,主機要先發送至少10us的高電平,觸發HC-RS04,模塊內部發出信號是傳感器自動回應的,我們不用去管它。輸出回響信號是我們需要關注的。信號輸出的高電平就是超聲波發出到重新返回接收所用的時間。用定時器,可以把這段時間記錄下來,算出距離,別忘了結果要除于2,因為總時間是發送和接收的時間總和。
下面是親測可用的驅動程序。
芯片型號為stm32f103zet6,超聲波測距后通過串口打印到電腦上面。
驅動和測距;




實驗結果: 1083998-20170608202310075-325550842.png

好了,其實這個模塊很簡單,但是要是把他用的很好的話還是比較困難的,比如用超聲波做一個四軸定高的程序,還是有一定的挑戰性的。
寫這篇博客的目的不僅僅是介紹這個模塊的使用,其實這種使用介紹網上一搜一大把,我只是想紀錄一下,我在做這個模塊的時候遇到的一些其他的問題。
其中有一個小插曲,就是當吧寫好的程序燒進去之后,運行時總是出現每次返回一個同樣的比正常值小的多的數據,比如說0.034cm,這明顯是一個錯誤的數據,但是剛開始的時候,不知道為什么
總是這樣,多次復位從新上電總是這一個數據。讓我很是苦惱。但是幸運的是,在這樣的情況中間,他又會有時出現一兩個正常的的數據,讓你有點摸不著頭腦。
上網查了一下才慢慢明白,這種現象叫做“余震”,網上關于余震的解釋大致有三種:
  1、探頭的余震。即使是分體式的,發射頭工作完后還會繼續震一會,這是物理效應,也就是余震。這個余震信號也會向外傳播。如果你的設計是發射完畢后立刻切換為接收狀態(無盲區),那么這個余震波會通過殼體和周圍的空氣,直接到達接收頭、干擾了檢測(注:通常的測距設計里,發射頭和接收頭的距離很近,在這么短的距離里超聲波的檢測角度是很大的,可達180度)。
  2、殼體的余震。就像敲鐘一樣,能量仍來自發射頭。發射結束后,殼體的余震會直接傳導到接收頭,當然這個時間很短,但已形成了干擾。另外,在不同的環境溫度下,殼體的硬度和外形會有所變化,其余震有時長、有時短、有時干擾大、有時干擾小,這是設計工業級產品時必須要考慮的問題。
  3、電路串擾。超聲波發射時的瞬間電流很大,例如某種工業級連續測距產品瞬間電流會有15A,通常的產品也能達到1A,瞬間這么大的電流會對電源有一定影響,并干擾接收電路。通過改善電源設計可以緩解這種情況,但在低成本設計中很難根除。所以每次發射完畢,接收電路還需要一段時間穩定工作狀態。在此期間,其輸出的信號很難使用。

消除上述現象的方法之一就是在檢測的時候多次循環檢測,取平均值,也就是加權平均濾波,一個簡單的濾波處理。就是下面這一段:
  1. u32 t = 0;  
  2. int i = 0;  
  3. float lengthTemp = 0;  
  4. float sum = 0;  
  5. while(i!=5)  
  6. {  
  7. TRIG_Send = 1;      //發送口高電平輸出  
  8. Delay_Us(20);  
  9. TRIG_Send = 0;  
  10. while(ECHO_Reci == 0);      //等待接收口高電平輸出  
  11.     OpenTimerForHc();        //打開定時器  
  12.     i = i + 1;  
  13.     while(ECHO_Reci == 1);  
  14.     CloseTimerForHc();        //關閉定時器  
  15.     t = GetEchoTimer();        //獲取時間,分辨率為1US  
  16.     lengthTemp = ((float)t/58.0);//cm  
  17.     sum = lengthTemp + sum ;  
  18.   
  19.   
  20. lengthTemp = sum/5.0;  
  21. return lengthTemp;  
復制代碼

加了這個之后,基本上就沒有出現余震現象了。

還有一點就是測試程序前一定要檢查引腳有沒有接錯,不管多有把握,也要看一遍,不然很容易出大事的,一個芯片也許就因為你的大意給GG了。切記,這個應該也算我們這個行業的基本素養吧。

  1.      //超聲波測距  
  2.       
  3.     #include "hcsr04.h"  
  4.       
  5.     #define HCSR04_PORT     GPIOB  
  6.     #define HCSR04_CLK      RCC_APB2Periph_GPIOB  
  7.     #define HCSR04_TRIG     GPIO_Pin_5  
  8.     #define HCSR04_ECHO     GPIO_Pin_6  
  9.       
  10.     #define TRIG_Send  PBout(5)   
  11.     #define ECHO_Reci  PBin(6)  
  12.       
  13.     u16 msHcCount = 0;//ms計數  
  14.       
  15.     void Hcsr04Init()  
  16.     {   
  17.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;     //生成用于定時器設置的結構體  
  18.         GPIO_InitTypeDef GPIO_InitStructure;  
  19.         RCC_APB2PeriphClockCmd(HCSR04_CLK, ENABLE);  
  20.            
  21.             //IO初始化  
  22.         GPIO_InitStructure.GPIO_Pin =HCSR04_TRIG;       //發送電平引腳  
  23.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
  24.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽輸出  
  25.         GPIO_Init(HCSR04_PORT, &GPIO_InitStructure);  
  26.         GPIO_ResetBits(HCSR04_PORT,HCSR04_TRIG);  
  27.            
  28.         GPIO_InitStructure.GPIO_Pin =   HCSR04_ECHO;     //返回電平引腳  
  29.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空輸入  
  30.         GPIO_Init(HCSR04_PORT, &GPIO_InitStructure);   
  31.             GPIO_ResetBits(HCSR04_PORT,HCSR04_ECHO);      
  32.            
  33.                 //定時器初始化 使用基本定時器TIM6  
  34.             RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);   //使能對應RCC時鐘  
  35.             //配置定時器基礎結構體  
  36.             TIM_DeInit(TIM2);  
  37.             TIM_TimeBaseStructure.TIM_Period = (1000-1); //設置在下一個更新事件裝入活動的自動重裝載寄存器周期的值         計數到1000為1ms  
  38.             TIM_TimeBaseStructure.TIM_Prescaler =(72-1); //設置用來作為TIMx時鐘頻率除數的預分頻值  1M的計數頻率 1US計數  
  39.             TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;//不分頻  
  40.             TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上計數模式  
  41.             TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure); //根據TIM_TimeBaseInitStruct中指定的參數初始化TIMx的時間基數單位         
  42.               
  43.             TIM_ClearFlag(TIM6, TIM_FLAG_Update);   //清除更新中斷,免得一打開中斷立即產生中斷  
  44.             TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);    //打開定時器更新中斷  
  45.             hcsr04_NVIC();  
  46.         TIM_Cmd(TIM6,DISABLE);      
  47.     }  
  48.       
  49.       
  50.     //tips:static函數的作用域僅限于定義它的源文件內,所以不需要在頭文件里聲明  
  51.     static void OpenTimerForHc()        //打開定時器  
  52.     {  
  53.             TIM_SetCounter(TIM6,0);//清除計數  
  54.             msHcCount = 0;  
  55.             TIM_Cmd(TIM6, ENABLE);  //使能TIMx外設  
  56.     }  
  57.       
  58.     static void CloseTimerForHc()        //關閉定時器  
  59.     {  
  60.             TIM_Cmd(TIM6, DISABLE);  //使能TIMx外設  
  61.     }  
  62.       
  63.       
  64.      //NVIC配置  
  65.     void hcsr04_NVIC()  
  66.     {  
  67.                 NVIC_InitTypeDef NVIC_InitStructure;  
  68.                 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  
  69.          
  70.                 NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;             //選擇串口1中斷  
  71.                 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //搶占式中斷優先級設置為1  
  72.                 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;         //響應式中斷優先級設置為1  
  73.                 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;        //使能中斷  
  74.                 NVIC_Init(&NVIC_InitStructure);  
  75.     }  
  76.       
  77.       
  78.     //定時器6中斷服務程序  
  79.     void TIM6_IRQHandler(void)   //TIM3中斷  
  80.     {  
  81.             if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET)  //檢查TIM3更新中斷發生與否  
  82.             {  
  83.                     TIM_ClearITPendingBit(TIM6, TIM_IT_Update  );  //清除TIMx更新中斷標志   
  84.                     msHcCount++;  
  85.             }  
  86.     }  
  87.       
  88.       
  89.     //獲取定時器時間  
  90.     u32 GetEchoTimer(void)  
  91.     {  
  92.             u32 t = 0;  
  93.             t = msHcCount*1000;//得到MS  
  94.             t += TIM_GetCounter(TIM6);//得到US  
  95.               TIM6->CNT = 0;  //將TIM2計數寄存器的計數值清零  
  96.                     Delay_Ms(50);  
  97.             return t;  
  98.     }  
  99.       
  100.       
  101.     //一次獲取超聲波測距數據 兩次測距之間需要相隔一段時間,隔斷回響信號  
  102.     //為了消除余震的影響,取五次數據的平均值進行加權濾波。  
  103.     float Hcsr04GetLength(void )  
  104.     {  
  105.             u32 t = 0;  
  106.             int i = 0;  
  107.             float lengthTemp = 0;  
  108.             float sum = 0;  
  109.             while(i!=5)  
  110.             {  
  111.             TRIG_Send = 1;      //發送口高電平輸出  
  112.             Delay_Us(20);  
  113.             TRIG_Send = 0;  
  114.             while(ECHO_Reci == 0);      //等待接收口高電平輸出  
  115.                 OpenTimerForHc();        //打開定時器  
  116.                 i = i + 1;  
  117.                 while(ECHO_Reci == 1);  
  118.                 CloseTimerForHc();        //關閉定時器  
  119.                 t = GetEchoTimer();        //獲取時間,分辨率為1US  
  120.                 lengthTemp = ((float)t/58.0);//cm  
  121.                 sum = lengthTemp + sum ;  
  122.               
  123.         }  
  124.             lengthTemp = sum/5.0;  
  125.             return lengthTemp;  
  126.     }  
  127.       
  128.       
  129.     /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  130.     ** 函數名稱: Delay_Ms_Ms
  131.     ** 功能描述: 延時1MS (可通過仿真來判斷他的準確度)           
  132.     ** 參數描述:time (ms) 注意time<65535
  133.     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/  
  134.     void Delay_Ms(uint16_t time)  //延時函數  
  135.     {   
  136.         uint16_t i,j;  
  137.         for(i=0;i<time;i++)
  138.             for(j=0;j<10260;j++);  
  139.     }  
  140.     /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  141.     ** 函數名稱: Delay_Ms_Us
  142.     ** 功能描述: 延時1us (可通過仿真來判斷他的準確度)
  143.     ** 參數描述:time (us) 注意time<65535                 
  144.     :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/  
  145.     void Delay_Us(uint16_t time)  //延時函數  
  146.     {   
  147.         uint16_t i,j;  
  148.         for(i=0;i<time;i++)
  149.             for(j=0;j<9;j++);  
  150.     }  
復制代碼

但是關于USART的函數我就不往上寫了,這個簡單的串口打印大家應該都會寫。下面簡單貼一下我的主函數吧。
  1.      /*
  2.     教訓:實驗前一定要檢查引腳連接是否正確,萬不可搞錯,不然又要燒壞芯片!!!!
  3.     2017.6.8
  4.     */  
  5.       
  6.     #include "hcsr04.h"  
  7.     #include "chao_usart.h"  
  8.       
  9.     int main()  
  10.     {  
  11.          
  12.             float length;  
  13.               
  14.             GPIO_cfg();  
  15.           NVIC_cfg();  
  16.             USART_cfg();      
  17.             printf("串口初始化成功!");  
  18.          
  19.             Hcsr04Init();     
  20.             printf("超聲波初始化成功!");//測試程序是否卡在下面兩句上面  
  21.       
  22.             length = Hcsr04GetLength();  
  23.             printf("距離為:%.3f",length);  
  24.          
  25.          
  26.     }  
復制代碼


全部資料51hei下載地址:
programcsb.rar (347.19 KB, 下載次數: 342)

評分

參與人數 3黑幣 +60 收起 理由
ren-jiong + 5
cheeselala + 5 很給力!
admin + 50 共享資料的黑幣獎勵!

查看全部評分

回復

使用道具 舉報

ID:107559 發表于 2018-4-7 16:42 | 顯示全部樓層
那這個經過改進后的代碼,最小最精細的測距能達到多少毫米?
回復

使用道具 舉報

ID:712537 發表于 2020-4-6 23:47 | 顯示全部樓層
測試的速度不夠快,也就是靈活性不太好。
回復

使用道具 舉報

ID:727047 發表于 2020-4-11 17:17 | 顯示全部樓層
特別給力,謝謝
回復

使用道具 舉報

ID:727047 發表于 2020-4-11 17:17 | 顯示全部樓層
特別給力,謝謝樓主。
回復

使用道具 舉報

ID:763242 發表于 2020-5-28 11:25 | 顯示全部樓層
這個有protues8.6版本的仿真圖么?
回復

使用道具 舉報

ID:777315 發表于 2020-6-12 15:02 | 顯示全部樓層
正在研究這個,,不錯不錯,參考下,
回復

使用道具 舉報

ID:591382 發表于 2020-8-17 18:37 | 顯示全部樓層
超聲波模塊我這幾天有在學,它的功能用處很多,值得學習。
回復

使用道具 舉報

ID:859370 發表于 2022-4-1 11:32 | 顯示全部樓層
非常感謝,非常有用
回復

使用道具 舉報

ID:842688 發表于 2022-4-2 00:51 來自手機 | 顯示全部樓層
高手!但是遇到一個問題,靈活性好像不太好啊
回復

使用道具 舉報

ID:361216 發表于 2022-10-24 11:12 | 顯示全部樓層
51用的話應該也沒有問題哈
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 欧美一区二区在线观看 | 成人久久视频 | 日韩精品久久久久 | 国产精品久久国产精品 | 亚洲高清在线免费观看 | 久久久精品网 | 精品国产乱码久久久久久蜜柚 | 国产精品久久久久久久久久尿 | 欧美综合在线观看 | 国产 日韩 欧美 在线 | 国产精品视频播放 | 国产免费福利在线 | 亚洲精品一区二区二区 | 91亚洲国产成人久久精品网站 | 亚洲一区二区三区四区五区午夜 | japanhd成人| 精品国模一区二区三区欧美 | 一级毛片视频 | 日韩精品一区二区三区在线观看 | 天天操天天天 | 亚洲 欧美 精品 | 日韩精品一区二区三区在线播放 | 亚洲人成人一区二区在线观看 | 日韩精品一区在线 | 日韩欧美一级精品久久 | 日韩在线欧美 | 爱爱视频在线观看 | 午夜免费视频 | 国产高清在线精品一区二区三区 | 精品日韩欧美一区二区 | 91精品国产日韩91久久久久久 | 婷婷在线免费 | 91 在线 | 亚洲婷婷一区 | 蜜桃臀av一区二区三区 | 狠狠综合网 | 成人在线不卡 | 日韩在线视频一区 | 久久成人国产精品 | 国产精品一区二区三区四区五区 | 国产一区二区三区四 |