我的ESP32實做書籍:https://youyouyou.pixnet.net/blog/post/121105860
博客來網址:https://www.books.com.tw/products/0010901195



溫濕度感測是物聯網實驗重要的一環,收集大量的資料可以了解溫濕度數值對環境的影響,例如偵測倉庫的溫濕度,可以避免商品受潮而故障或腐敗,監控教室的溫濕度也可以避免太熱影響到學生的學習效率,而本章將會以DHT11感測器來感測環境溫濕度,並利用1602LCD顯示數值。
一、溫濕度感測(DHT11)
在Arduino中有許多感測溫度的感測器,例如DHT系列(11或22)、DS18B20、LM35等,其中LM35及DS18B20為三極體外型,DHT系列則分成藍色DHT11及白色DHT22,其規格比較表如下,LM35與DS18B20在感測上效果差不多,可以精確到小數點以下兩位,市售DS18B20常包覆不鏽鋼,可以用於偵測一些極端環境,例如測量水族箱溫度,或者化學溶液中。本書則是以DHT11為範例,可同時測量溫度及濕度變化。

image

image

DHT11的外觀如下圖,由左到右依序為訊號(s)、VCC(+)及GND(-)及三個腳位,其中VCC因為位置不夠因此沒標明,特別要說明的是DHT11與其他感測器比較起來較為脆弱,若VCC、GND接反了很快就會燒毀,因此在接線上必須特別注意,以免發生危險。
 

image
DHT11感測器
DHT系列規格上雖然標明為數位傳輸,但是非digitalRead這麼簡單,而是一連串的訊號交換及解譯才能獲得數值,為了減少這個複雜的過程,我們可以安裝simpleDHT.h程式庫,只要呼叫一行指令就可以直接取得感測器數值。

image
DHT 資料時序圖

image
安裝simpleDHT程式庫
接下來我們將DHT11與ESP32連接起來,其腳位圖如下,除了GND及VCC之外,將DHT11的訊號(S)連接到ESP32的GPIO4,不過若要將DHT11接在GPIO12或GPIO2時,則須等程式上傳完畢後,再將DHT11接上,否則可能會遇到Time out的錯誤訊息。
 

image
DHT11 ESP32接線圖

image
DHT11插在GPIO2或12時 導致Time out 錯誤
完成接線後,我們開啟上方功能表/檔案/範例/simpleDHT,找到程式庫提供的範例程式DHT11Default,開啟後,僅須修改第7行的腳位,從預設的2改為4即可執行。

 


#include <SimpleDHT.h>
int pinDHT11 = 4;
SimpleDHT11 dht11(pinDHT11);

void setup() {
  Serial.begin(115200);
}

void loop() {
  // start working...  Serial.println("=================================");
  Serial.println("Sample DHT11...");
  
  // read without samples.
  byte temperature = 0;
  byte humidity = 0;
  int err = SimpleDHTErrSuccess;
  if ((err = dht11.read(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess) {
    Serial.print("Read DHT11 failed, err="); Serial.println(err);delay(1000);
    return;
  }
  Serial.print("Sample OK: ");
  Serial.print((int)temperature); Serial.print(" *C, "); 
  Serial.print((int)humidity); Serial.println(" H");  
  // DHT11 sampling rate is 1HZ.
  delay(1500);
}



上述的範例中,關鍵語法是dht11.read(&temperature, &humidity, NULL)),這句的意思是開始讀取dht11的溫濕度數值,並將結果放置在temperature及humidity變數的位址,也就是說,當執行完dht11.read指令後,就可以得到環境的溫濕度數值了,但因為接線錯誤或者感測器故障而讀取失敗的話,則會顯示錯誤並且返回(return)。
而範例程式在顯示溫濕度時,前方加上(int)則是為了型別轉換,例如(int)temperature,因為dht11.read的資料格式是byte,讀取出來後則用(int)轉成整數,後續我們在使用上也建議都加上(int)以免出錯。
image
DHT11讀取正常與錯誤的訊息


第二節 1602LCD顯示器
上一節當我們想知道溫濕度資料時,可以透過序列監控視窗查看,可是如果手邊沒有電腦可以開啟序列監控,那要如何知道DHT11所感測的資料呢?其實Arduino系列有相當多種的顯示裝置可以利用,例如TFT、OLED,甚至是電子紙(ePaper)都相當流行,各有不同的適用環境,不過對初學者來說最簡單的應該是點陣式LCD(Liquid Crystal Display)了,現在大部份都製作為I2C界面的1602 LCD模組(LCM:Liquid Crystal Display Module),也就是2行每行16個字的LCD顯示模組,為了介紹方便,以下我們通稱為1602LCD,除了1602之外,2004規格也很常見(4行x 20字),讀者可以依需求自行購買。

image
目前常見顯示器(多色電子紙仍不普遍)


讀者在購買1602LCD時,務必要選擇具有I2C界面的LCD,所謂的I2C是Inter-Integrated Circuit的簡稱,也可寫作IIC(讀法為I-squared-C)是一種相當普遍的低速傳輸模式,由於可以利用定址方式連接最多112個節點,大量用於單晶片、手機、主機板之內,I2C界面僅須SDA及SCL兩個腳位,Arduino系列都有支援,若購入沒有I2C界面LCD,則需要用到6~8個腳位,安裝控制都會相當複雜,相形之下I2C安裝較為簡單,且直接呼叫函式庫即可顯示內容相當方便。
image
I2C界面與1602LCD

接下來我們將ESP32與1602LCD連線,除了VCC及GND之外,ESP32預設的I2C界面為SDA是GPIO21、SCL為GPIO22,因此將LCD的SDA->GPIO21,SCL->GPIO22即可。不過使用1602LCD仍有許多常見問題,這裡大致列出如下:
1.    未使用5V:LCD須使用5V電源驅動,否則背光可能無法點亮。
2.    背光接口沒接:當接上5V點源,LCD仍無法點亮,這可能是背光接口沒接,通常背光接口會有一個Jump將腳位短路,若JUMP遺失可使用母母杜邦線對接即可。
3.    位址設定錯誤:i2C裝置都會有一個位址,宣告錯誤的位址是不會有任何反應的,所以必須先以做一次i2c scan掃描,取得正確位址。
4.    對比沒調整:若上述都完成,依然無法顯示文字,那應該是對比沒調整,請利用小螺絲起子旋轉對比旋鈕,調整一個讀者覺得清楚的對比。
我們先來說3的I2C位址掃描是什麼?上一段提及I2C可以透過定址連接最多112個裝置,那麼不同裝置必然會有不同的位址,當我們要執行程式時就要先指定這個命令是要給哪一個裝置執行,不然命令會被錯誤的裝置接收,就導致運作不正常,因此我們要在使用前先利用以下的程式掃描裝置的位址是多少。
 image
接線圖


#include <Wire.h>

void setup()
{
  Serial.begin (115200);  
  Wire.begin (21, 22);   // sda= GPIO_21 /scl= GPIO_22
}

void Scanner ()
{
  Serial.println ();
  Serial.println ("I2C scanner. Scanning ...");
  byte count = 0;

  Wire.begin();
  for (byte i = 8; i < 120; i++)
  {
    Wire.beginTransmission (i); // Begin I2C transmission Address (i)
    if (Wire.endTransmission () == 0) //0=success(ACK response) 
    {
      Serial.print ("Found address: ");
      Serial.print (i, DEC);
      Serial.print (" (0x");
      Serial.print (i, HEX);     // PCF8574 7 bit address
      Serial.println (")");
      count++;
    }
  }
  Serial.print ("Found ");      
  Serial.print (count, DEC);        // numbers of devices
  Serial.println (" device(s).");
}

void loop()
{
  Scanner ();
  delay (5000);
}


程式上傳後,若接線正確沒問題的話,就會出現下方的內容,其中
I2C device found at address 0x27
代表在ESP32上有找到一組I2C裝置位址在0x27,除了0x27之外,1602LCD也會有0x30或其他數值,這個數值很重要,請先把數值寫下來,等等就會用到。
 image
I2C 掃描結果
接下來我們需要安裝LCD的程式庫才能在上面顯示文字,利用上方功能表/草稿碼/匯入程式庫/管理程式庫,打開程式庫管理員之後,在上方空白處輸入關鍵字:「LiquidCrystal I2C」,並找到作者為Frank de Brabander的程式庫後(大約在中間的位置),點選右側的安裝即可。
 image
安裝液晶螢幕程式庫
完成安裝後,我們可以開啟下面的HelloWorld程式,裡面的關鍵語法包括:
1.指定LCD位址與規格:
LiquidCrystal_I2C lcd(0x27,16,2);
其中0x27代表我們LCD的I2C位址,此處讀者應填入上方i2c scan時所獲得的位址,而16代表我們的LCD是一行16個字,2代表是2排字。
2.LCD初始化:
lcd.init();
代表lcd初始化,LCD使用前必須要執行一次初始化。
3.開啟背光:
lcd.backlight();
代表開啟LCD背光,若缺少這句LCD無背光顯示。
4.移動游標
lcd.setCursor(3,0);
代表將游標移至第0行,第3個字(下圖○A的位置),顯示文字前要先利用這個指令指定從何處開始顯示文字。
5.印出文字
lcd.print("Hello, world!");
則是在步驟4指定的游標處印出文字,這裡要注意若印出的文字超過螢幕寬度,並不會自動換行,會直接被隱藏,因此顯示時讀者須自行計算游標與文字數量。
6.清除內容
lcd.clear();//清除所有內容
清除LCD內的內容,等候顯示更新後的資料。
 image
LCD游標位置



#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2);//設定LCD位址與大小

void setup()
{
  lcd.init();   //初始化LCD
  lcd.backlight(); //開啟LCD背光
}

void loop(){
  lcd.setCursor(3,0);//設定游標
  lcd.print("Hello, world!");//印出文字
  lcd.setCursor(2,1);//設定游標
  lcd.print("ESP32 LCD Test!"); //印出文字
  delay(1000);
  lcd.clear();//清除所有內容
  delay(1000);

}


若您的LCD並沒有出現Hello World字樣,那請您依序本節一開始時所說明的LCD使用注意4個事項進行檢查,排除問題。
當顯示沒問題的話,就可以將兩隻範例程式合在一起,也就是把DHT11溫濕度的DHT11default程式碼及LCD的HelloWorld結合在一起,以本例而言,我們將較為簡單的LCD HelloWorld程式的setup()、loop()、以及最上方宣告區都搬到DHT11default中,整合後的程式如下。

 



#include <SimpleDHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
int pinDHT11 = 14;
SimpleDHT11 dht11(pinDHT11);
LiquidCrystal_I2C lcd(0x27, 16, 2);
void setup() {
  Serial.begin(115200);
  lcd.init();
  lcd.backlight();
}

void loop() {
 Serial.println("=================================");
  Serial.println("Sample DHT11...");
  byte temperature = 0;
  byte humidity = 0;
  int err = SimpleDHTErrSuccess;
  if ((err = dht11.read(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess) {
    Serial.print("Read DHT11 failed, err="); Serial.println(err); delay(1000);
    return;
  }

  Serial.print("Sample OK: ");
  Serial.print((int)temperature); Serial.print(" *C, ");
  Serial.print((int)humidity); Serial.println(" H");
  lcd.clear();
  lcd.setCursor(0, 0); //先設定游標
  lcd.print("Temperature: ");//顯示溫度
  lcd.print((int)temperature);
  lcd.print("c");
  lcd.setCursor(0, 1); //顯示溼度
  lcd.print("Humidity:    ");
  lcd.print((int)humidity);
  lcd.print("%");
  delay(1500);
}


image

arrow
arrow

    夜市 小霸王 發表在 痞客邦 留言(4) 人氣()