Follower

2017年5月30日 星期二

【Arduino】溫濕度感測器(DHT11)實作與應用

  Arduino提供了良好的平台讓我們這種無知百姓可以去開發自己想要的東西,當然之於Arduino這種Open Source的硬體,必定會有廠商投入生產相關的週邊元件,比如我們今天要使用的溫濕度感測器─DHT11。

溫濕度感測器DHT11
左:模組版本、右:非模組版本

DHT11的Pin組成十分的簡單,只有正極負極資料端,以下提供模組化和非模組化的Pin角資訊和其功能:

模組化DHT11
1
Vcc
2
DATA
3
GND

非模組化DHT11
1
Vcc
2
DATA
3
NC(空接)
4
GND


DHT11功能
工作電壓
3.5V ~ 5.5V
溫度表示範圍
0~50oC(誤差+-2oC)
濕度表示範圍
20%~95%(誤差+-5%)

※因為要配合上課,所以特地去買了模組化的DHT11進行課程〈因為課程配發的器材的DHT11都已模組化,只有我的DHT11還是非模組化〉,雖然特地去買了一顆模組化DHT11,但最終還是跟課程配發給學生的器材有所不同,課程提供給學生的模組化DHT11是:
模組化DHT11
1
DATA
2
Vcc
3
GND
其中DATA角有標一個"S",這可以解讀為"Signal",也就是訊號的意思,在DHT11裡廣義來講就是資料端,所以在使用元件上還是要依照該元件的Pin角為準。

其實簡單來說,DHT11是一個很單純且不複雜的元件,但要驅動這個元件,需要軟體的加持;而此元件的品質其實並不是很好,就我個人的使用經驗來說,就光是在元件上抹個口水就足以到達破壞至不能使用的程度,就一個電子元件來說,品質確實蠻令人擔憂的,而且精準度頗差,但好在DHT11造價不貴,一顆也才60新臺幣,就算用壞也不會心痛 :D

接下來實作一下,看看DHT11的功能:

【實作1 DHT11 Basic】
DHT11 接線圖

結果:
用Serial Monitor顯示出其結果〈根據Code〉
Code:
#include <dht.h>
#define dht_dpin 2
dht DHT ;
void setup()
{
  Serial.begin(9600) ;
  delay(300) ;
  Serial.println("Humidity and Temperature\n\n") ;
  delay(700) ;
}
void loop()
{
  DHT.read11(dht_dpin) ;
  Serial.print("Humidity = ") ;
  Serial.print(DHT.humidity) ;
  Serial.print("% ") ;
  Serial.print("Temperature = ") ;
  Serial.print(DHT.temperature) ;
  Serial.println("C ") ;
  delay(1000) ;
}
※比較要注意的地方在主程式的"DHT.read11"這部分,read11本身會call "dht.h"這個library裡頭的程式,而read11是針對"DHT11"這個感測器而特別編寫的程式,另外一個是"read22",同理這是針對"DHT22"而寫的程式,而DHT11和DHT22都是溫濕度感測器,差別在於DHT22比DHT11有更好的精準度,但也稍微貴一些。

※本code有使用的library,在此下載


【實作2 利用LCD顯示溫濕度】

實作1 接線圖
結果:

Code:
#include <dht.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define dht_dpin 2
dht DHT ;
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE) ;
void setup()
{
  Serial.begin(9600) ;
  lcd.begin(16, 2) ;
  lcd.backlight() ;
}
void loop()
{
    DHT.read11(dht_dpin) ;
    lcd.setCursor(0, 0) ; 
    lcd.print("Temp: ") ;
    lcd.print(DHT.temperature) ;
    lcd.print("C") ;    
    lcd.setCursor(0, 1) ;
    lcd.print("Humi: ") ;
    lcd.print(DHT.humidity) ;
    lcd.print("% ") ;
}

※這邊使用的LCD是 "型號1602"的I2C(有背板)版本,請不要跟無背板的搞錯。

※此實作有使用到LCD的library,在此下載


【實作3 利用藍芽APP顯示溫濕度】


實作3 接線圖〈跟上次的藍芽實作2 接線圖一模一樣,直接進入"透通模式"〉

結果:

Code:
#include <dht.h>
#define dht_dpin 2
dht DHT ;
void setup()
{
  Serial.begin(9600) ;
}
void loop()
{
 if(Serial.available())
 {
  DHT.read11(dht_dpin) ;
  unsigned char charreceived = Serial.read() ;
  switch(charreceived)
  {
    case '1':
      Serial.print(" Humidity = ") ;
      Serial.print(DHT.humidity) ;
      Serial.println("% ") ;
      break ;
    case '0':
      Serial.print(" Temperature = ") ;
      Serial.print(DHT.temperature) ;
      Serial.println("C ") ;
      break ;
    default:
      break ;
  }
  Serial.flush() ;
 }
 delay(10) ;
}


【實作4 藍接藍芽下指令於LCD顯示】
實作4 接線圖〈就是上面各項實作的綜合版,應該不難〉
結果:


Code:
#include <dht.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define dht_dpin 2
dht DHT ;
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE) ;
void setup()
{
  Serial.begin(9600) ;
  lcd.begin(16, 2) ;
  lcd.backlight() ;
  lcd.setCursor(0, 0) ;
  lcd.print("Waiting Command..") ;
}
void loop()
{
 if(Serial.available())
 {
  DHT.read11(dht_dpin) ;
  unsigned char charreceived = Serial.read() ;
  switch(charreceived)
  {
    case '1':
      lcd.clear() ;  
      Serial.print(" Humidity = ") ;
      Serial.print(DHT.humidity) ;
      Serial.println("% ") ;
      lcd.setCursor(0, 0) ;
      lcd.print("Humi: ") ;
      lcd.print(DHT.humidity) ;
      lcd.print("% ") ;
      break ;
    case '0':
      lcd.clear() ;
      Serial.print(" Temperature = ") ;
      Serial.print(DHT.temperature) ;
      Serial.println("C ") ;
      lcd.setCursor(0, 0) ; 
      lcd.print("Temp: ") ;
      lcd.print(DHT.temperature) ;
      lcd.print("C") ;
      break ;
    default:
      break ;
  }
  Serial.flush() ;
 }
 delay(10) ;
}

※之前上課有同學提出一個問題,為什麼Serial.print和Serial.write前者可以顯示溫濕度、後者無法顯示?這是因為「.print」是直接抓取數據做顯示,而「.write」會把數據轉成ASCII碼顯示出來,同學說的不能顯示是因為ASCII碼有控制字元和顯示字元的分別;而我們室內常溫通常是28度,〝28〞這個數值在ASCII碼裡頭顯示不出來的控制字元〈就像鍵盤上的Shift是控制按鍵〉,可顯示字元是從〝32〞開始〈不過〝32〞是空白,所以廣義來說從〝33〞的驚嘆號符號開始可被顯示〉。

沒有留言:

張貼留言