DHT11數字溫濕度傳感器是一款含有已校準數字信號輸出的溫濕度復合傳感器。其成本低、長期穩定、可以測量相對濕度和溫度測量,并可以只使用一根數據線進行溫濕度采集。
1.模塊來源
模塊實物展示:
資料下載鏈接:https://pan.baidu.com/s/1HQEL699-Yl5Jh3Hp87_FlQ
資料提取碼:2sgq
模塊的廠家資料下載見百度網盤鏈接
工作電壓:3-5.5V
工作電流:1MA
測量分辨率:8 bit
濕度量程: 20 - 90 %RH
濕度精度:±5 %RH
溫度量程: 0 - 50 ℃
溫度精度:±2 ℃
通信協議:單總線
3.移植過程
我們的目標是在立創·地文星·CW32F030C8T6開發板上實現讀取溫濕度的功能。首先要獲取資料,查看數據手冊應如何實現讀取數據,再移植至我們的工程。
3.1查看資料
DHT11使用的是單總線通信,即發送數據與接收數據都在一根數據線上,通過規定的時序進行控制。
從左向右看,時序一開始,主機信號就保持著高電平,所以引腳初始化完畢時,及時給引腳輸出高電平。因為 模塊的數據線要求空閑時,要保持高電平狀態。(其實模塊上已經接了上拉電阻,使數據線一直保持高電平)
根據時序圖可以知道,主機(開發板)發送一次開始信號,待主機開始信號結束后,DHT11 發送響應信號,送出 溫濕度數據,并觸發一次數據采集給下一次數據讀取作準備。因此完成一次數據讀取需要進行起始信號、響應信號、數據接收、結束信號。
讀取數據步驟:
起始信號:主機(開發板)接入數據線的I/O輸出低電平,且低電平保持時間不能小于 18ms
DATA_GPIO_OUT(0); //數據線輸出低電平 delay_1ms(19); //起始信號保持時間19ms DATA_GPIO_OUT(1); //主機釋放總線 delay_uus( 20 ); //拉高等待
2.響應信號:等待模塊的響應信號到來。將數據線改為輸入模式,如果接入到低電平,說明接收到模塊的響應。
DHT11_GPIO_Mode_IN();//數據線轉為輸入模式 //如果前面沒有錯誤,則模塊會發出低電平的應答信號, //所以直接等待DHT11拉高,83us timeout = 5000; while( (! DATA_GPIO_IN ) && ( timeout >0 ) ) { timeout--; //等待高電平的到來 } //模塊當前處于拉高準備輸出數據, //所以直接等待DHT11拉低,87us timeout = 5000;//設置超時時間 while( DATA_GPIO_IN && ( timeout >0 ) ) { timeout-- ; //等待低電平的到來 }
3.數據傳輸:主機接收模塊發送的40位數據,其中,位數據 ‘0’ 表示54us的低電平,27us的高電平;位數據 ‘1’ 表示54us的低電平,74us的高電平。兩個格式的分辨主要是高電平的輸出時長不同。
#define CHECK_TIME 28 //超過0值的高電平時間 for(i=0;i40;i++)//循環接收40位數據 { timeout = 5000; //等待低電平過去 while( ( !DATA_GPIO_IN ) && (timeout > 0) ) timeout--; //54us delay_uus(CHECK_TIME);//等待超過位數據0值的高電平時間 if ( DATA_GPIO_IN )//如果還是高電平,說明是1值 { val=(val<1)+1; } else //如果是低電平,說明是0值 { val<=1; } timeout = 5000; //如果當前還是高電平,等待高電平過去,準備接收下一位數據 while( DATA_GPIO_IN && (timeout > 0) ) timeout-- ; }
4.結束信號:模塊的數據線輸出 40 位數據后,是以低電平結束,它會繼續輸出低電平 54 微秒后轉為輸入狀態,主機需要轉為輸出狀態,輸出高電平釋放總線。
DHT11_GPIO_Mode_OUT();//轉為輸出模式 DATA_GPIO_OUT(1);//主機釋放總線
數據接收完成,但是這40位數據要如何轉化為溫濕度數據?并如何保證傳輸的數據沒有錯誤?
DHT11模塊一次完整的數據傳輸為40bit,高位先出。數據格式:
8bit濕度整數數據 + 8bit濕度小數數據 + 8bi溫度整數數據 + 8bit溫度小數數據 + 8bit校驗和
注意
濕度小數部分數據一直為0。
數據傳送正確時,校驗和數據等于“8bit濕度整數數據+8bit濕度小數數據 +8bi溫度整數數據+8bit溫度小數數據”所得結果的末8位。舉幾個例子。
示例一:接收的40位數據分別為:
0011 0101 | 0000 0000 | 0001 1000 | 0000 0100 | 0101 0001 |
濕度高8位 | 濕度低8位 | 溫度高8位 | 溫度低8位 | 校驗位 |
校驗和為 0011 0101 + 0000 0000 + 0001 1000 + 0000 0100 = 0101 0001,與接收的數據一致
濕度為 0011 0101 + 0000 0000 = 35 + 0 = 35%RH
溫度為 0001 1000 0000 0100 = 24 + 4 = 24.4℃
示例二:接收的40位數據分別為:
0011 0101 | 0000 0000 | 0001 1000 | 0000 0100 | 0100 1001 |
濕度高8位 | 濕度低8位 | 溫度高8位 | 溫度低8位 | 校驗位 |
校驗和為 0011 0101 + 0000 0000 + 0001 1000 + 0000 0100 = 0101 0001,與接收的數據不一致 計算的數據為0101 0001,接收的數據為0100 1001,兩者不一致說明數據不準確,丟棄這次數據,重新接收。
以下為數據處理的實現代碼:
//val為接收到的40位數據。 // 濕高8 + 濕低8 + 溫高8 + 溫低8 verify_num = (val>>32) + (val>>24) + (val>>16) + (val>>8); //計算的校驗和 與 接收的校驗和 的差為0說明一致,不為0說明不一致 //(val&0xff)是因為val的大小為64位,我們只需要val的最后8位校驗和 verify_num = verify_num - (val&0xff); //進行校驗 if( verify_num )//如果不為0,說明校驗失敗 { // 校驗錯誤 return 0; } else //校驗成功 { //數據處理 humidity = (val>>32)&0xff; //濕度前8位(小數點前數據) small_point = (val>>24)&0x00ff; //濕度后8位(小數點后數據) small_point = small_point * 0.1; //換算為小數點 humidity = humidity + small_point; //小數前+小數后 printf("濕度:%.2frn",humidity); temperature = (val>>16)&0x0000ff; //溫度前8位(小數點前數據) small_point = (val>>8)&0x000000ff; //溫度后8位(小數點后數據) small_point = small_point * 0.1; //換算為小數點 temperature = temperature + small_point;//小數前+小數后 printf("溫度:%.2frn",temperature); return val>>8; //返回未處理的數據 }
3.2引腳選擇
該模塊有3個引腳,具體引腳連接見 表 各引腳連接。
3.3移植至工程
工程模板下載請查看入門手冊百度鏈接
然后我們打開空白工程,新建兩個文件dht11.c和dht11.h
在文件dht11.c中,編寫如下代碼。
/* * Change Logs: * Date Author Notes * 2024-06-19 LCKFB-LP first version */ #include "dht11.h" #include "stdio.h" float temperature = 0; float humidity = 0; /****************************************************************** * 函 數 名 稱:DHT11_GPIO_Init * 函 數 說 明:DHT11溫濕度傳感器初始化 * 函 數 形 參:無 * 函 數 返 回:無 * 作 者:LC * 備 注:無 ******************************************************************/ void DHT11_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; // GPIO初始化結構體 RCC_DHT11_GPIO_ENABLE(); // 使能GPIO時鐘 GPIO_InitStruct.Pins = GPIO_DHT11; // GPIO引腳 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽輸出 GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; // 輸出速度高 GPIO_Init(PORT_DHT11, &GPIO_InitStruct); // 初始化 DATA_GPIO_OUT(1); } /****************************************************************** * 函 數 名 稱:DHT11_GPIO_Mode_OUT * 函 數 說 明:配置DHT11的數據引腳為輸出模式 * 函 數 形 參:無 * 函 數 返 回:無 * 作 者:LC * 備 注:無 ******************************************************************/ void DHT11_GPIO_Mode_OUT(void) { GPIO_InitTypeDef GPIO_InitStruct; // GPIO初始化結構體 GPIO_InitStruct.Pins = GPIO_DHT11; // GPIO引腳 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽輸出 GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; // 輸出速度高 GPIO_Init(PORT_DHT11, &GPIO_InitStruct); // 初始化 } /****************************************************************** * 函 數 名 稱:DHT11_GPIO_Mode_IN * 函 數 說 明:配置DHT11的數據引腳為輸入模式 * 函 數 形 參:無 * 函 數 返 回:無 * 作 者:LC * 備 注:無 ******************************************************************/ void DHT11_GPIO_Mode_IN(void) { GPIO_InitTypeDef GPIO_InitStruct; // GPIO初始化結構體 GPIO_InitStruct.Pins = GPIO_DHT11; // GPIO引腳 GPIO_InitStruct.Mode = GPIO_MODE_INPUT_PULLUP; // 上拉輸入 GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; // 輸出速度高 GPIO_Init(PORT_DHT11, &GPIO_InitStruct); // 初始化 } /****************************************************************** * 函 數 名 稱:DHT11_Read_Data * 函 數 說 明:根據時序讀取溫濕度數據 * 函 數 形 參:無 * 函 數 返 回:0=數據校驗失敗 其他=溫濕度未處理的數據 * 作 者:LC * 備 注:無 ******************************************************************/ unsigned int DHT11_Read_Data(void) { int i; long long val=0; int timeout=0; float small_point=0; unsigned char verify_num = 0;//驗證值 DATA_GPIO_OUT(0);//數據線輸出低電平 delay_ms(19); //起始信號保持時間19ms DATA_GPIO_OUT(1);//主機釋放總線 delay_us( 20 );//拉高等待 DHT11_GPIO_Mode_IN();//數據線轉為輸入模式 //如果前面沒有錯誤,則模塊會發出低電平的應答信號,所以直接等待DHT11拉高,80us timeout = 5000; while( (! DATA_GPIO_IN ) && ( timeout >0 ) )timeout--; //等待高電平的到來 //模塊當前處于拉高準備輸出數據,所以直接等待DHT11拉低,80us timeout = 5000;//設置超時時間 //DATA_GPIO_IN=0時,while條件不成立退出while 說明接收到響應信號 //當timeout<=0時,while條件不成立退出while 說明超時 while( DATA_GPIO_IN && ( timeout >0 ) )timeout-- ; //等待低電平的到來 #define CHECK_TIME 28 //實測發現超過0值的高電平時間 for(i=0;i40;i++)//循環接收40位數據 { timeout = 5000; while( ( !DATA_GPIO_IN ) && (timeout > 0) ) timeout--; //等待低電平過去 delay_us(CHECK_TIME);//超過0值的高電平時間 if ( DATA_GPIO_IN )//如果還是高電平,說明是1值 { val=(val<1)+1; } else //如果是低電平,說明是0值 { val<=1; } timeout = 5000; while( DATA_GPIO_IN && (timeout > 0) ) timeout-- ; //如果還是高電平 } DHT11_GPIO_Mode_OUT();//轉為輸出模式 DATA_GPIO_OUT(1);//主機釋放總線 // 濕高8 + 濕低8 + 溫高8 + 溫低8 verify_num = (val>>32) + (val>>24) + (val>>16) + (val>>8); //計算的校驗和 與 接收的校驗和 的差為0說明一致,不為0說明不一致 verify_num = verify_num - (val&0xff); //進行校驗 if( verify_num ) { // 校驗錯誤 return 0; } else //校驗成功 { //數據處理 humidity = (val>>32)&0xff;//濕度前8位(小數點前數據) small_point = (val>>24)&0x00ff;//濕度后8位(小數點后數據) small_point = small_point * 0.1;//換算為小數點 humidity = humidity + small_point;//小數前+小數后 // printf("濕度:%.2frn",humidity); temperature = (val>>16)&0x0000ff;//溫度前8位(小數點前數據) small_point = (val>>8)&0x000000ff;//溫度后8位(小數點后數據) small_point = small_point * 0.1;//換算為小數點 temperature = temperature + small_point;//小數前+小數后 // printf("溫度:%.2frn",temperature); return val>>8; //返回未處理的數據 } } /****************************************************************** * 函 數 名 稱:Get_temperature * 函 數 說 明:獲取溫度數據 * 函 數 形 參:無 * 函 數 返 回:溫度值 * 作 者:LC * 備 注:使用前必須先調用 DHT11_Read_Data 讀取有數據 ******************************************************************/ float Get_temperature(void) { return temperature; } /****************************************************************** * 函 數 名 稱:Get_humidity * 函 數 說 明:獲取濕度數據 * 函 數 形 參:無 * 函 數 返 回:濕度值 * 作 者:LC * 備 注:使用前必須先調用 DHT11_Read_Data 讀取有數據 ******************************************************************/ float Get_humidity(void) { return humidity; }
在文件dht11.h中,編寫如下代碼。
/* * Change Logs: * Date Author Notes * 2024-06-19 LCKFB-LP first version */ #ifndef _BSP_DHT11_H_ #define _BSP_DHT11_H_ #include "board.h" /**************引腳修改此處****************/ #define RCC_DHT11_GPIO_ENABLE() __RCC_GPIOB_CLK_ENABLE() #define PORT_DHT11 CW_GPIOB #define GPIO_DHT11 GPIO_PIN_0 //設置DHT11輸出高或低電平 #define DATA_GPIO_OUT(x) GPIO_WritePin(PORT_DHT11, GPIO_DHT11, x ? GPIO_Pin_SET : GPIO_Pin_RESET) //獲取DHT11數據引腳高低電平狀態 #define DATA_GPIO_IN GPIO_ReadPin(PORT_DHT11, GPIO_DHT11) extern float temperature; extern float humidity; void DHT11_GPIO_Init(void);//引腳初始化 unsigned int DHT11_Read_Data(void);//讀取模塊數據 float Get_temperature(void);//返回讀取模塊后的溫度數據 float Get_humidity(void);//返回讀取模塊后的濕度數據 #endif
4.移植驗證
在自己工程中的main主函數中,編寫如下。
/* * Change Logs: * Date Author Notes * 2024-06-19 LCKFB-LP first version */ #include "board.h" #include "stdio.h" #include "bsp_uart.h" #include "dht11.h" int32_t main(void) { board_init(); // 開發板初始化 uart1_init(115200); // 串口1波特率115200 DHT11_GPIO_Init(); //DHT11引腳初始化 delay_ms(1000); printf("DHT11 demo startrn"); while(1) { //讀取模塊數據 DHT11_Read_Data(); //顯示讀取后的溫度數據 printf("temperature = %.2frn", Get_temperature() ); //顯示讀取后的濕度數據 printf("humidity = %.2frn", Get_humidity() ); delay_ms(1000); } }
上電效果:
模塊移植成功案例代碼:
鏈接:https://pan.baidu.com/s/10WX784WnNQeMiwbLH8Yt7g?pwd=LCKF
提取碼:LCKF
審核編輯 黃宇
-
數字信號
+關注
關注
2文章
969瀏覽量
47538 -
溫濕度傳感器
+關注
關注
5文章
579瀏覽量
35706 -
DHT11
+關注
關注
19文章
277瀏覽量
57580 -
CW32
+關注
關注
1文章
203瀏覽量
626
發布評論請先 登錄
相關推薦
評論