一、我的構想:如何為編程愛好者設計一款好玩的智能硬件(一)——即插即用、積木化、功能重組的智能硬件模塊構想
二、別人家的孩子:如何為編程愛好者設計一款好玩的智能硬件(二)——別人是如何設計硬件積木的!
三、MCU選型:如何為編程愛好者設計一款好玩的智能硬件(三)——該選什么樣的MCU呢?
四、溫濕度傳感器DHT11驅動封裝(上):如何為編程愛好者設計一款好玩的智能硬件(四)——初嘗試·把溫濕度給收集了(上)!
五、溫濕度傳感器DHT11驅動封裝(中):如何為編程愛好者設計一款好玩的智能硬件(五)——初嘗試·把溫濕度給收集了(中)!
六、溫濕度傳感器DHT11驅動封裝(下):
這幾天該進程稍微中斷,一方面是因為幫助一個好朋友處理保研的事情,另一方面是由於我在思考每天一篇是否會因為過於頻繁而缺少干貨。於是我決定每個月的模3余0的日子總結一下~特此通告!在四、五兩篇中我們詳細分析了DHT11的驅動流程,由於我們需要一個便於移植的版本,所以上次挖了個坑說會采用宏定義來盡量方便移植。因此,本節將首先討論宏定義相關知識,而后封裝一個稍微改進的DHT11驅動。
C Macros
#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"。這個例子說明,宏所使用的“#”運算符是一種非常方便的調試工具。
“##”運算符的作用是將兩個獨立的字符串連接成一個字符串。
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
@beautifulzzzz
2015-9-17 持續更新中~