如何為編程愛好者設計一款好玩的智能硬件(六)——初嘗試·把溫濕度給收集了(下)!


 

一、我的構想:如何為編程愛好者設計一款好玩的智能硬件(一)——即插即用、積木化、功能重組的智能硬件模塊構想

二、別人家的孩子:如何為編程愛好者設計一款好玩的智能硬件(二)——別人是如何設計硬件積木的!

三、MCU選型:如何為編程愛好者設計一款好玩的智能硬件(三)——該選什么樣的MCU呢?

四、溫濕度傳感器DHT11驅動封裝(上):如何為編程愛好者設計一款好玩的智能硬件(四)——初嘗試·把溫濕度給收集了(上)!

五、溫濕度傳感器DHT11驅動封裝(中):如何為編程愛好者設計一款好玩的智能硬件(五)——初嘗試·把溫濕度給收集了(中)!

 

六、溫濕度傳感器DHT11驅動封裝(下):

  

  這幾天該進程稍微中斷,一方面是因為幫助一個好朋友處理保研的事情,另一方面是由於我在思考每天一篇是否會因為過於頻繁而缺少干貨。於是我決定每個月的模3余0的日子總結一下~特此通告!在四、五兩篇中我們詳細分析了DHT11的驅動流程,由於我們需要一個便於移植的版本,所以上次挖了個坑說會采用宏定義來盡量方便移植。因此,本節將首先討論宏定義相關知識,而后封裝一個稍微改進的DHT11驅動。

 

C Macros

 
理解宏:
 
  宏是一種預處理指令,它提供了一種機制,可以用來替換源代碼中的字符串,宏是用“#define"語句定義的,下面是一個宏定義的例子:
    #define VERSION—STAMP "1.02"
  上例中所定義的這種形式的宏通常被稱為標識符。在上例中,標識符VERSION_STAMP即代表字符串"1.02"——在編譯預處理時,源代碼中的每個VERSION_STAMP標識符都將被字符串“1.02”替換掉。

  以下是另一個宏定義的例子:
      #define CUBE(x)  ((x)*(x)*(x))
  上例中定義了一個名為CUBE的宏,它有一個參數x。CUBE宏有自己的宏體,即((x)*(x)*(x))——在編譯預處理時,源代碼中的每個CUBE(x)宏都將被((x)*(x)*(x))替換掉。

使用宏有以下幾點好處:

     (1)在輸入源代碼時,可省去許多鍵入操作。   
    (2)因為宏只需定義一次,但可以多次使用,所以使用宏能增強程序的易讀性和可靠性。
    (3)使用宏不需要額外的開銷,因為宏所代表的代碼只在宏出現的地方展開,因此不會引起程序中的跳轉。
    (4)宏的參數對類型不敏感,因此你不必考慮將何種數據類型傳遞給宏。
 
容易出錯的地方:

  需要注意的是,在宏名和括起參數的括號之間絕對不能有空格。此外,為了避免在翻譯宏時產生歧義,宏體也應該用括號括起來。

你可能不知道的:

  宏也可使用一些特殊的運算符,例如字符串化運算符“#”和。連接運算符“##”。“#”運算符能將宏的參數轉換為帶雙引號的字符串,請看下例:
      define DEBUG_VALUE(v)  printf(#v"is equal to %d.\n",v)
  你可以在程序中用DEBUG_VALUE宏檢查變量的值,請看下例:
      int x=20;
      DEBUG_VALUE(x);
  上述語句將在屏幕上打印"x is equal to 20"。這個例子說明,宏所使用的“#”運算符是一種非常方便的調試工具。
  “##”運算符的作用是將兩個獨立的字符串連接成一個字符串。
 
這篇文章對宏的種類進行簡單的介紹:http://blog.csdn.net/ocean181/article/details/6818687
這篇文章單獨讀宏里面的#進行介紹:http://blog.sina.com.cn/s/blog_550405a10100bqar.html
這篇文章講了宏中的幾個高級的用法:http://www.cnblogs.com/Anker/p/3418792.html (do while)
 
 
DHT11驅動封裝 
 
DHT11.H
 1 #ifndef __DHT11_H__
 2 #define __DHT11_H__
 3 
 4 #include "delay.h"
 5 
 6 //some typedef need to do
 7 typedef unsigned char t_uc; 8 typedef unsigned short t_us; 9 typedef unsigned int t_ui; 10 typedef char t_c; 11 typedef short t_s; 12 typedef int t_i; 13 
14 #define DHT11_DELAY_US(x) Delay_us((x)) 15 #define DHT11_DELAY_MS(x) Delay_ms((x)) 16 #define DHT11_DATA_PIN P0_0 17 #define DHT11_DATA_PIN_READ DHT11_DATA_PIN //read the data_pin's data function 18 #define DHT11_DATA_PIN_SET DHT11_DATA_PIN=1 19 #define DHT11_DATA_PIN_CLEAR DHT11_DATA_PIN=0 20 #define DHT11_DATA_PIN_IN P0DIR&=~0x01 21 #define DHT11_DATA_PIN_OUT P0DIR|=0x01
22 
23 
24 extern t_i DHT11_GetData(t_us *humidity, t_us *temperature); 25 
26 
27 #endif

 

移植的時候只要對.H進行修改就行啦! 

  上面是封裝的DHT11的驅動.H文件,可見為了達到方便移植到各個平台的目的,我們在紅色部分重定義了數據類型,並且在綠色部分將幾個外部依賴全部定義成宏。這樣移植到不同平台的時候只需要根據特定的平台,稍微調動下紅色部分重定義的數據類型,並且根據宏定義部分相應的功能進行封裝和修改(這樣.C文件是不需要動的,是不是很方便!)

  這里對部分宏定義進行說明:

  ① DHT11_DATA_PIN 是DHT11通信數據線連在單片機上的引腳  
  ② DHT11_DATA_PIN_READ是讀取DHT11_DATA_PIN引腳上的數據函數,返回為該引腳的狀態(高電平為1,低電平為0)
  ③ DHT11_DATA_PIN_SET和DHT11_DATA_PIN_CLEAR功能分別是置DHT11_DATA_PIN引腳為高電平和低電平功能函數
  ④ DHT11_DATA_PIN_IN和DHT11_DATA_PIN_OUT功能分別是設置DHT11_DATA_PIN引腳為輸入和輸出模式

    PS:

  這里第4行引入的外部文件提供delay延時相關函數,同樣的第14、15行宏定義也將所要用到的延時微秒和毫秒的函數進行宏定義,總的來說就是方便移植~

 

DHT11.C

 1 #include "DHT11.H"
 2 
 3 
 4 t_uc COM(void)//read 8bits data from com
 5 {
 6     t_uc flag, temp; //flag and temp
 7     t_uc comdata;//the 8bits data read from com
 8     t_uc i;
 9     for(i = 0; i < 8; i++)
10     {
11         flag = 2;
12         while((!DHT11_DATA_PIN_READ) && flag++);
13         DHT11_DELAY_US(30);
14         temp = 0;
15         if(DHT11_DATA_PIN_READ)temp = 1;
16         flag = 2;
17         while((DHT11_DATA_PIN_READ) && flag++);
18         if(flag == 1)break;
19         comdata <<= 1;
20         comdata |= temp;
21     }
22     return comdata;
23 }
24 
25 t_i DHT11_GetData(t_us *humidity, t_us *temperature)//get the hunidity and temperature data
26 {
27     t_uc flag, temp; //flag and temp
28     t_uc ucharT_data_H_temp, ucharT_data_L_temp,
29          ucharRH_data_H_temp, ucharRH_data_L_temp,
30          ucharcheckdata_temp;
31 
32 //1、start 33 DHT11_DATA_PIN_OUT; //set the data pin as out mode 34 DHT11_DATA_PIN_CLEAR; 35 DHT11_DELAY_MS(19); //>18MS 36 DHT11_DATA_PIN_SET; 37 DHT11_DATA_PIN_IN; //set the data pin as input mode 38 DHT11_DELAY_US(40); 39     
40     if(!DHT11_DATA_PIN_READ)
41     {
42 //2、wait 43 flag = 2; 44 while((!DHT11_DATA_PIN_READ) && flag++); 45 flag = 2; 46 while((DHT11_DATA_PIN_READ) && flag++); 47 
48 //3、read data 49 ucharRH_data_H_temp = COM(); 50 ucharRH_data_L_temp = COM(); 51 ucharT_data_H_temp = COM(); 52 ucharT_data_L_temp = COM(); 53 ucharcheckdata_temp = COM(); 54 
55 //4、stop 56  DHT11_DATA_PIN_SET; 57         
58         temp = (ucharT_data_H_temp + ucharT_data_L_temp + ucharRH_data_H_temp + ucharRH_data_L_temp);
59         if(temp == ucharcheckdata_temp) //check the data ,then updata humidity and temperature
60         {
61             *humidity = ucharRH_data_H_temp;
62             *temperature = ucharT_data_H_temp;
63         }
64     }
65     else //fail return -1
66     {
67         return -1;
68     }
69     
70     return 0;
71 }

 .C文件是不用改的~和前兩節講解的相比,這里基本沒變,只是將部分函數換成了宏

 

得說明的:

  前兩節講過從DHT11中讀出來的40bits數據包括溫濕度整數和小數部分各8bit表示+一個8bit的校驗,上面.C文件第61、62行僅將整數部分提取

 

小結&接下來計划:

  至此,我們終於把DHT11給封裝好了,接下來不會那么頻繁更新(畢竟太快沒干貨!)。下次我將首先展示該驅動在CC2541(上面的便是基於它的)、STM32、51平台上的移植方法,然后開啟一個新的驅動封裝——顯示器。至於要選擇哪一款,暫時還沒定,也先留個懸念吧~

 

 

鏈接

基於CC2541平台的實驗工程

>只有DHT11.C和DHT11.H經過整理,其它可能有點亂,見諒<

http://pan.baidu.com/s/1hq6N168 

 

DHT11.C和DHT11.H文件

http://pan.baidu.com/s/1dD0ibDJ

http://pan.baidu.com/s/1qeHBK

 

 

  

@beautifulzzzz

  2015-9-17 持續更新中~

 
 
 


免責聲明!

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



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