溫度和濕度測量通常在家庭自動化、環境監測、氣象站等許多應用中很有用。LM35旁邊最常用的溫度傳感器是 DHT11,我們之前通過與Arduino和Raspberry連接構建了許多DHT11 項目Pi和許多其他開發板。在本文中,我們將學習如何將此DHT11 與 PIC16F87A連接,這是一個 8 位 PIC 微控制器。我們將使用這個微控制器通過 DHT11 讀取溫度和濕度的值并將其顯示在液晶顯示器上。
DHT11 – 規范和工作
DHT11 傳感器以模塊形式或傳感器形式提供。在本教程中,我們使用的是傳感器,兩者之間的唯一區別在于,在模塊形式中,傳感器具有一個濾波電容和一個連接到傳感器輸出引腳的上拉電阻。因此,如果您正在使用該模塊,則無需在外部添加它們。傳感器形式的 DHT11 如下所示。
DHT11 傳感器帶有藍色或白色外殼。 在這個外殼內,我們有兩個重要的組件 可以幫助我們感知相對濕度和溫度。 第一個組件是一對電極;這兩個電極之間的電阻由保持水分的基板決定。所以測得的電阻與環境的相對濕度成反比。相對濕度越高,電阻值越低,反之亦然。另外,請注意相對濕度與實際濕度不同。相對濕度測量空氣中相對于空氣溫度的水含量。
另一個組件是表面貼裝的 NTC 熱敏電阻。術語 NTC 代表負溫度系數,隨著溫度的升高,電阻值將減小。傳感器的輸出經過工廠校準,因此作為程序員,我們不必擔心校準傳感器。1-Wire通信給出的傳感器輸出,我們看一下這個傳感器的引腳和連接圖。
該產品采用 4pin 單排封裝。第 1 個引腳跨接 VDD,第 4 個引腳跨接 GND。第二個引腳是數據引腳,用于通信目的。該數據引腳需要一個 5k 的上拉電阻。但是,也可以使用其他上拉電阻,例如 4.7k 到 10k。第 3 個引腳沒有連接任何東西。所以它被忽略了。
上表顯示了溫度和濕度的測量范圍和精度。它可以測量 0-50 攝氏度的溫度,精度為 +/- 2 攝氏度,測量相對濕度 20-90%RH,精度為 +/- 5%RH。詳細規格見下表。
與 DHT11 傳感器通信
如前所述,為了使用 PIC 從DHT11讀取數據,我們必須使用PIC 單線通信協議。有關如何執行此操作的詳細信息,可以從其數據表中的 DHT 11 的接口圖了解,如下所示。
DHT11 需要來自 MCU 的啟動信號來啟動通信。因此,每次 MCU 都需要向 DHT11 Sensor 發送啟動信號,要求其發送溫度和濕度值。在完成啟動信號后,DHT11 會發送一個 包含溫度和濕度信息的響應信號。數據通信采用單總線數據通信協議。全數據長度為 40 位,傳感器先發送高位數據。
由于上拉電阻,數據線在空閑模式下始終保持在 VCC 電平。MCU 需要將此電壓從高到低拉低至少 18 毫秒。在此期間,DHT11 傳感器檢測到啟動信號,微控制器將數據線拉高 20-40us。這 20-40us 的時間稱為 DHT11 開始響應的等待期。在這個等待期之后,DHT11 將數據發送到微控制器單元。
DHT11 傳感器數據格式
數據由組合在一起的小數部分和整數部分組成。傳感器遵循以下數據格式 -
8bit 積分 RH 數據 + 8bit 十進制 RH 數據 + 8bit 積分 T 數據 + 8bit 十進制 T 數據 + 8bit 校驗和。
可以通過使用接收到的數據檢查校驗和值來驗證數據。可以這樣做是因為,如果一切正常,并且傳感器已經傳輸了正確的數據,那么校驗和應該是“8 位 RH 積分數據+8 位十進制 RH 數據+8 位積分 T 數據+8 位十進制 T 數據”之和。
所需組件
對于這個項目,需要以下內容 -
面包板
5V 500mA 電源裝置。
4.7k電阻2個
1k電阻
PIC16F877A
20mHz晶體
33pF電容2個
16x2 字符 LCD
DHT11傳感器
跳線
示意圖
將DHT11 與 PIC16F877A連接的電路圖如下所示。
我們使用16x2 LCD來顯示我們從 DHT11 測量的溫度和濕度值。LCD 采用4 線模式連接,傳感器和 LCD 均由 5V 外部電源供電。我使用面包板進行所有必需的連接,并使用了外部 5V 適配器。您還可以使用此面包板電源板為您的電路板供電 5V。
電路準備好后,我們要做的就是上傳本頁底部給出的代碼,我們可以開始讀取溫度和濕度,如下所示。如果您想知道代碼是如何編寫的以及它是如何工作的,請進一步閱讀。您還可以在本頁底部的視頻中找到該項目的完整工作。
DHT11 with PIC MPLABX 代碼說明
代碼使用 MPLABX IDE 編寫,并使用 XC8 編譯器編譯,兩者均由 Microchip 提供,可免費下載和使用。請參考基礎教程了解編程基礎知識,下面只討論與 DHT11 傳感器通信所需的三個重要功能。功能是 -
無效 dht11_init(); 無效查找響應(); char read_dht11();
第一個函數用于dht11 的啟動信號。如前所述,與 DHT11 的每次通信都以啟動信號開始,這里首先更改引腳方向以將數據引腳配置為微控制器的輸出。然后數據線被拉低,一直等待18mS。之后,微控制器再次將線路設為高電平,并一直等待長達 30us。等待時間過后,數據引腳設置為微控制器的輸入以接收數據。
無效 dht11_init(){ DHT11_Data_Pin_Direction= 0; //配置RD0為輸出 DHT11_Data_Pin = 0; //RD0向傳感器發送0 __delay_ms(18); DHT11_Data_Pin = 1;//RD0向傳感器發送1 __delay_us(30); DHT11_Data_Pin_Direction = 1;//配置RD0為輸入 }
下一個函數用于根據數據引腳狀態設置校驗位。它用于檢測 DHT11 傳感器的響應。
無效 find_response(){ Check_bit = 0; __delay_us(40); if (DHT11_Data_Pin == 0){ __delay_us(80); if (DHT11_Data_Pin == 1){ Check_bit = 1; } __delay_us(50);} }
最后是dht11讀取函數;此處數據被讀取為 8 位格式,其中數據通過位移操作返回,具體取決于數據引腳狀態。
char read_dht11(){ char 數據,for_count; for(for_count = 0; for_count < 8; for_count++){ while(!DHT11_Data_Pin); __delay_us(30); if(DHT11_Data_Pin == 0){ data&= ~(1<<(7 - for_count)); //清除位 (7-b) } else{ data|= (1 << (7 - for_count)); //設置位 (7-b) while(DHT11_Data_Pin); } } 返回數據; }
???
之后,一切都在 main 函數中完成。首先,系統初始化在 LCD 被初始化并將 LCD 引腳端口方向設置為輸出的地方完成。應用程序在主函數內部運行
無效 main() { system_init(); while(1){ __delay_ms(800); dht11_init(); 查找響應(); if(Check_bit == 1){ RH_byte_1 = read_dht11(); RH_byte_2 = read_dht11(); Temp_byte_1 = read_dht11(); Temp_byte_2 = read_dht11(); 求和 = read_dht11(); if(Summation == ((RH_byte_1+RH_byte_2+Temp_byte_1+Temp_byte_2) & 0XFF)){ 濕度 = Temp_byte_1; RH = RH_byte_1; lcd_com (0x80); lcd_puts("溫度:"); //lcd_puts(""); lcd_data(48 + ((濕度/10) % 10)); lcd_data(48 + (濕度 % 10)); 液晶數據(0xDF); lcd_puts("C"); lcd_com (0xC0); lcd_puts("濕度:"); //lcd_puts(""); lcd_data(48 + ((RH / 10) % 10)); lcd_data(48 + (RH % 10)); lcd_puts("%"); } else{ lcd_puts("校驗和錯誤"); } } 其他 { clear_screen(); lcd_com (0x80); lcd_puts("錯誤!!!"); lcd_com (0xC0); lcd_puts("沒有反應。"); } __delay_ms(1000); } }
與 DHT11 傳感器的通信是在while循環中完成的,在該循環中將啟動信號提交給傳感器。之后,觸發find_response函數。如果Check_bit為 1,則進行進一步的通信,否則 LCD 將顯示錯誤對話框。
根據 40 位數據,read_dht11被調用 5 次(5 次 x 8 位),并按照數據表中提供的數據格式存儲數據。校驗和狀態也被檢查,如果發現錯誤,它也會在 LCD 中通知。最后,數據被轉換并傳輸到 16x2 字符 LCD。
#include
#include
#include "supporting_cfile/lcd.h"
#pragma config FOSC = HS // 振蕩器選擇位(HS 振蕩器)
#pragma config WDTE = OFF // 看門狗定時器使能位(WDT 禁用)
#pragma config PWRTE = ON // 上電定時器使能位(PWRT 使能)
# pragma config BOREN = ON // 欠壓復位使能位(BOR 使能)
#pragma config LVP = OFF // 低電壓(單電源)在線串行編程使能位(RB3 為數字 I/O,HV 開啟MCLR 必須用于編程)
#pragma config CPD = OFF // 數據 EEPROM 存儲器代碼保護位(數據 EEPROM 代碼保護關閉)
#pragma config WRT = OFF // 閃存程序存儲器寫使能位(寫保護關閉;所有程序存儲器可由 EECON 控制寫入)
#pragma config CP = OFF // Flash 程序存儲器代碼保護位(代碼保護關閉)
/*
程序流程相關定義
*/
#define DHT11_Data_Pin PORTDbits.RD5
#define DHT11_Data_Pin_Direction TRISDbits.TRISD5
#define FIRST_LINE 0x80
#define SECOND_LINE 0xC0
#define _XTAL_FREQ 20000000 //20 Mhz
unsigned char Check_bit, Temp_byte_1, Temp_byte_2, RH_byte_1, RH_byte_2;
unsigned char Himudity, RH, Sumation ;
//dht11相關定義
無效 dht11_init();
無效查找響應();
char read_dht11();
// 系統相關定義
無效系統初始化(無效);
無效介紹屏幕(無效);
無效清除屏幕(無效);
無效 main() {
system_init();
while(1){
__delay_ms(800);
dht11_init();
查找響應();
if(Check_bit == 1){
RH_byte_1 = read_dht11();
RH_byte_2 = read_dht11();
Temp_byte_1 = read_dht11();
Temp_byte_2 = read_dht11();
求和 = read_dht11();
if(Sumation == ((RH_byte_1+RH_byte_2+Temp_byte_1+Temp_byte_2) & 0XFF)){
Himudity = Temp_byte_1;
RH = RH_byte_1;
lcd_com (0x80);
lcd_puts("溫度:");
//lcd_puts("");
lcd_data(48 + ((Himudity / 10) % 10));
lcd_data(48 + (濕度 % 10));
液晶數據(0xDF);
lcd_puts("C");
lcd_com (0xC0);
lcd_puts("濕度:");
//lcd_puts("");
lcd_data(48 + ((RH / 10) % 10));
lcd_data(48 + (RH % 10));
lcd_puts("%");
}
else{
lcd_puts("校驗和錯誤");
}
}
其他 {
clear_screen();
lcd_com (0x80);
lcd_puts("錯誤!!!");
lcd_puts("沒有反應。");
}
__delay_ms(1000);
}
}
/*
* 這將初始化 dht22 傳感器。
*/
無效 dht11_init(){
DHT11_Data_Pin_Direction= 0; //配置RD0為輸出
DHT11_Data_Pin = 0; //RD0向傳感器發送0
__delay_ms(18);
DHT11_Data_Pin = 1;//RD0向傳感器發送1
__delay_us(30);
DHT11_Data_Pin_Direction = 1;//配置RD0為輸入
}
/*
* 這將發現 dht22 傳感器是否工作。
*/
無效 find_response(){
Check_bit = 0;
__delay_us(40);
if (DHT11_Data_Pin == 0){
__delay_us(80);
if (DHT11_Data_Pin == 1){
Check_bit = 1;
}
__delay_us(50);}
}
/*
此函數用于讀取 dht22。
*/
char read_dht11(){
char data, for_count;
for(for_count = 0; for_count < 8; for_count++){
while(!DHT11_Data_Pin);
__delay_us(30);
if(DHT11_Data_Pin == 0){
data&= ~(1<<(7 - for_count)); //清除位 (7-b)
}
else{
data|= (1 << (7 - for_count)); //設置位 (7-b)
while(DHT11_Data_Pin);
} //等到 PORTD.F0 變低
}
返回數據;
}
void system_init(){
TRISB = 0; // LCD 引腳設置為輸出。
液晶初始化();
介紹屏幕();
//dht11_init();
}
/*
這個函數是為了在沒有命令的情況下清除屏幕。
*/
void clear_screen(void){
lcd_com(FIRST_LINE);
lcd_puts("");
lcd_com(第二行);
lcd_puts("");
}
/*
此函數用于播放介紹。
*/
void Introduction_screen(void){
lcd_com(FIRST_LINE);
lcd_puts("歡迎來到");
lcd_com(第二行);
lcd_puts("電路文摘");
__delay_ms(1000);
__delay_ms(1000);
清除屏幕();
lcd_com(FIRST_LINE);
lcd_puts("DHT11 傳感器");
lcd_com(第二行);
lcd_puts("用 PIC16F877A");
__delay_ms(1000);
__delay_ms(1000);
}
-
微控制器
+關注
關注
48文章
7566瀏覽量
151605 -
液晶顯示器
+關注
關注
11文章
576瀏覽量
43660 -
DHT11
+關注
關注
19文章
277瀏覽量
57624
發布評論請先 登錄
相關推薦
評論