樹莓派控制HC-SR04超聲波模塊測距(新手向+C語言向)


  因為作業要求使用c語言代碼,這里先附上一段摘自網上的代碼

  感謝KalaerSun的c語言代碼,摘自https://blog.csdn.net/qq_25247589/article/details/62892140

 1 #include <wiringPi.h>  
 2 #include <stdio.h>  
 3 #include <sys/time.h>  
 4 #define Trig    4  
 5 #define Echo    5  
 6   
 7 void ultraInit(void)  8 {  9     pinMode(Echo, INPUT);  //設置端口為輸入
10     pinMode(Trig, OUTPUT);  //設置端口為輸出
11 } 12   
13 float disMeasure(void) 14 { 15     struct timeval tv1;  //timeval是time.h中的預定義結構體 其中包含兩個一個是秒,一個是微秒
16     /*
17  struct timeval 18  { 19  time_t tv_sec; //Seconds. 20  suseconds_t tv_usec; //Microseconds. 21  }; 22     */
23     
24     struct timeval tv2; 25     long start, stop; 26     float dis; 27   
28  digitalWrite(Trig, LOW); 29     delayMicroseconds(2); 30   
31  digitalWrite(Trig, HIGH); 32     delayMicroseconds(10);      //發出超聲波脈沖 
33  digitalWrite(Trig, LOW); 34       
35     while(!(digitalRead(Echo) == 1)); 36     gettimeofday(&tv1, NULL);           //獲取當前時間 開始接收到返回信號的時候 
37   
38     while(!(digitalRead(Echo) == 0)); 39     gettimeofday(&tv2, NULL);           //獲取當前時間 最后接收到返回信號的時候
40     /*
41  int gettimeofday(struct timeval *tv, struct timezone *tz); 42  The functions gettimeofday() and settimeofday() can get and set the time as well as a timezone. 43  The use of the timezone structure is obsolete; the tz argument should normally be specified as NULL. 44     */
45     start = tv1.tv_sec * 1000000 + tv1.tv_usec;   //微秒級的時間 
46     stop  = tv2.tv_sec * 1000000 + tv2.tv_usec; 47   
48     dis = (float)(stop - start) / 1000000 * 34000 / 2;  //計算時間差求出距離 
49   
50     return dis; 51 } 52   
53 int main(void) 54 { 55     float dis; 56   
57     if(wiringPiSetup() == -1){ //如果初始化失敗,就輸出錯誤信息 程序初始化時務必進行
58         printf("setup wiringPi failed !"); 59         return 1; 60  } 61   
62  ultraInit(); 63       
64     while(1){ 65         dis = disMeasure(); 66         printf("distance = %0.2f cm\n",dis); 67         delay(1000); 68  } 69   
70     return 0; 71 }  

  因為是剛開始接觸樹莓派開發,所以文章中可能會出現錯誤,希望大神們能多多指教,不勝感激。

  PS:以下內容出現順序按照代碼閱讀順序

  1.sys/time.h

    360搜索鏈接:https://baike.so.com/doc/1233815-1304991.html

  2.wiringPi.h

    wiringPi是一個很棒的樹莓派IO控制庫,使用C語言開發,提供了豐富的接口:GPIO控制,中斷,多線程,等等。

    wiringPi.h詳解:https://www.cnblogs.com/lulipro/p/5992172.html

  3.wiringPiSetup(void)

    在使用wiringPi.h庫時,在執行任何操作前都必須初始化樹莓派,否則程序便無法正常運行。當初始化操作未完成時,函數返回值為-1

    其他的樹莓派初始化函數還有wiringPiSetupGpio(void),此函數使用方法與wiringPiSetup(void)類似,當函數無法正常運行時返回值也是-1.不同的地方在於,wiringPiSetup(void)初始化樹莓派引腳時使用的是wiringPi 引腳編號表。引腳的編號為 0~16;wiringPiSetupGpio(void)初始化樹莓派引腳時使用的是BCM GPIO 引腳編號表。

    其他兩種函數還有wiringPiSetupPhys(void)和wiringPiSetupSys (void) ,因為不常用,所以在此處不做介紹。

  4.void pinMode(uint8 pin, WiringPinMode mode)

    這個函數是用來確定引腳的功能的,如果在使用某個引腳之前沒有確定這個引腳的功能或者引腳設置模式不正確,就會出現一些不可捉摸的錯誤。

    這個函數有兩個參數,第一個參數pin是一個正整數,用來指定引腳的編號(0-16),第二個參數是用來指定引腳的IO模式,可用的參數有INPUT , OUTPUT , OUTPUT_OPEN_DRAIN , INPUT_ANALOG , INPUT_PULLUP , INPUT_PULLDOWN , INPUT_FLOATING , PWMPWM_OPEN_DRAIN

    每個參數的具體意義請移步:https://book.2cto.com/201311/36087.html

  5.timeval

    在代碼中已經告訴了我們整個結構體的來歷和定義下的架構,這里不做詳解,有興趣的童鞋請移步https://blog.csdn.net/king16304/article/details/52273834

  6.digitalWrite(uint8 pin, uint8 value)

    這又是一個在wiringPi.h中已經定義好的函數,它的作用是對一個已近配置為輸出模式(OUTPUT或者OUTPUT_OPEN_DRAIN)的 引腳  輸出指定的電平信號,其中pin是一個正整數,用來指定一個已經初始化過的引腳,value可以是數字或者參數,數字表示下:1代表高電平,0代表低電平;參數表示下:LOW代表低電平,HIGH代表高電平。

  7.delayMicroseconds (unsigned int howLong)

    將線程暫停指定的微秒數(1000微妙=1毫秒=0.001s),因為Linux是多線程的,所以實際暫停的秒數可能比設置的更多一些

  8.digitalRead (int pin)

    讀取一個引腳的電平值(LOW / HIGH),並且返回。其中pin是引腳的編號,該引腳的初始化類型必須為INPUT等輸入類型。返回值也可以是1 / 0(當輸入信號電壓在0~1.16 V時該函數返回0,當輸入信號在1.83~3.3 V時返回1。如果輸入電壓在1.16~1.83 V之間不確定會返回0還是1。)

  9.gettimeofday(struct timeval *, struct timezone *);

    則個函數返回的是1970年0:00:00到現在經過的秒數,函數的正常傳入時需要用到兩個參數。第一個已經介紹過了,第二個因為在這里沒有用處,所以暫且不表,傳入參數時用NULL即可,這里關於這個問題還有一個小故事:timeval中的tv_sec是time_t類型的,即long的類型。在32位下為4個字節,能夠表示的最大正整數是2147483647,而這個表示的時間最大能到2038-01-19 03:14:07,超過了之后就變為-2147483648,這就是linux2038年的問題。而64位系統下的time_t類型即long類型長度為8個字節,可以用到幾千億年,這么長的時間完全不用擔心溢出的問題。

  10.根據返回的秒數計算出微秒數

    start = tv1.tv_sec * 1000000 + tv1.tv_usec; 

    stop  = tv2.tv_sec * 1000000 + tv2.tv_usec;    

    我們知道 timeval結構體中含有兩個變量,tv_sec表示的是秒數,1秒=1000000微妙,第二個參數tv_usec表示的就是微秒數,所以通過這兩個式子我們就求出了開始和結束時的微秒數,然后做差即可得到超聲波傳遞所使用的時間

  11.根據時間計算距離

    (stop - start) / 1000000 * 34000 / 2

    因為stop和start原本表示的微妙,所以做差之后處1000000換算回是多少秒。因為聲音在物質中的傳播受到物質材質的影響,這里我們暫且不考慮介質的種類,默認為聲音是在空氣中傳播,所以取聲音的速度為340m/s=34000cm/s,因為超聲波測距的誤差較小的范圍200-300cm,所以我們這里計算速度時用cm表示。

  


 

  既然我們已經讀懂了代碼,接下來我們就是硬件方面的鏈接:

  我們先來了解一下各個硬件分別開來的屬性。

  1.樹莓派:

    樹莓派的歷史我們在此不做過多的講解,其他硬件也暫且不講,我們先來看一下樹莓派上的引腳。

    拿起樹莓派,將USB接口向下,面向你那起來,你會發現樹莓派右邊有兩列一共40個引腳,下邊這部分告訴了我們這些引腳各自的功能。

 +-----+-----+---------+------+---+---Pi 3---+---+------+---------+-----+-----+  
 | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |  
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+  
 |     |     |    3.3v |      |   |  1 || 2  |   |      | 5v      |     |     |  
 |   2 |   8 |   SDA.1 | ALT0 | 1 |  3 || 4  |   |      | 5V      |     |     |  
 |   3 |   9 |   SCL.1 | ALT0 | 1 |  5 || 6  |   |      | 0v      |     |     |  
 |   4 |   7 | GPIO. 7 |   IN | 1 |  7 || 8  | 1 | ALT5 | TxD     | 15  | 14  |  
 |     |     |      0v |      |   |  9 || 10 | 1 | ALT5 | RxD     | 16  | 15  |  
 |  17 |   0 | GPIO. 0 |  OUT | 0 | 11 || 12 | 0 | IN   | GPIO. 1 | 1   | 18  |  
 |  27 |   2 | GPIO. 2 |   IN | 0 | 13 || 14 |   |      | 0v      |     |     |  
 |  22 |   3 | GPIO. 3 |   IN | 0 | 15 || 16 | 0 | IN   | GPIO. 4 | 4   | 23  |  
 |     |     |    3.3v |      |   | 17 || 18 | 0 | IN   | GPIO. 5 | 5   | 24  |  
 |  10 |  12 |    MOSI | ALT0 | 0 | 19 || 20 |   |      | 0v      |     |     |  
 |   9 |  13 |    MISO | ALT0 | 0 | 21 || 22 | 0 | IN   | GPIO. 6 | 6   | 25  |  
 |  11 |  14 |    SCLK | ALT0 | 0 | 23 || 24 | 1 | OUT  | CE0     | 10  | 8   |  
 |     |     |      0v |      |   | 25 || 26 | 1 | OUT  | CE1     | 11  | 7   |  
 |   0 |  30 |   SDA.0 |   IN | 1 | 27 || 28 | 1 | IN   | SCL.0   | 31  | 1   |  
 |   5 |  21 | GPIO.21 |   IN | 1 | 29 || 30 |   |      | 0v      |     |     |  
 |   6 |  22 | GPIO.22 |   IN | 1 | 31 || 32 | 0 | IN   | GPIO.26 | 26  | 12  |  
 |  13 |  23 | GPIO.23 |   IN | 0 | 33 || 34 |   |      | 0v      |     |     |  
 |  19 |  24 | GPIO.24 |   IN | 0 | 35 || 36 | 0 | IN   | GPIO.27 | 27  | 16  |  
 |  26 |  25 | GPIO.25 |   IN | 0 | 37 || 38 | 0 | IN   | GPIO.28 | 28  | 20  |  
 |     |     |      0v |      |   | 39 || 40 | 0 | IN   | GPIO.29 | 29  | 21  |  
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+  
 | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |  
 +-----+-----+---------+------+---+---Pi 3---+---+------+---------+-----+-----+

    我們重點來介紹這次試驗用到的兩種引腳:

      ①.電源引腳:分為3.3V / 5V / 0V三種,其中0V代表接地

      ②.GPIO輸入輸出接口:這是非常重要的一類引腳,上圖中標明了GPIO的就是這類接口,樹莓派GPIO接口只能輸入輸出數字信號(0&1等)

  2.超聲波模塊

    超聲波模塊的種類有很多,我們此處選擇的模塊型號為HC-SR04,本模塊的優點為性能穩定,測度距離精確,模塊高精度,盲區小。探測距離為2cm-450cm。

    

    我們可以看到它一共有四個引腳:

      Vcc:接5V電源(接1號引腳)

      Trig:輸出端口(接16號引腳)

      Echo:輸入端口(接18號端口)

      Gnd:接地端(接6號端口)

   3.杜邦線

     杜邦線有三種類型,分別為公對母,母對母,公對公。我們這里需要的是四條母對母的杜邦線。

  

    接下來我們就用杜邦線將超聲波模塊與樹莓派連接,連接時一定要注意引腳之間的對應關系。連接成功后如下

    


 

    連接成功后我們就開始測試程序了,先將程序編譯成可執行的二進制文件

    

    之后輸入ls 查看,我們發現有編譯成功后的disMeasure文件

    

    之后我們輸入sudo ./disMeasure   開始執行程序,程序運行效果如下。

    

    到此,我們的超聲波模塊測距部分就算完美收工了。


 

以上就是超聲波模塊測距的c的代碼和解析的部分了,希望能對大家的樹莓派學習有幫助。

 


免責聲明!

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



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