從零開始學 ESP-NOW(第二章):用 DHT11 傳輸溫濕度資料到接收端

在第一章中,我們已經成功讓兩台 ESP32 透過 ESP-NOW 實現基本的資料傳輸。”從零開始學 ESP-NOW:ESP32與Arduino IDE 裝置之間的點對點資料交換教學“。那麼,這一章我們要更進一步——讓 ESP32 傳送真實感測資料(例如溫度與濕度)給另一台接收板!

我們將使用 DHT11 溫濕度感測器 來讀取環境數據,並透過 ESP-NOW 傳給接收端,再即時顯示在 Serial Monitor 上。
這是你邁向 無線感測網 實作的重要一步!

本章目標

✅ 了解 DHT11 與 ESP32 的接線方式
✅ 編寫傳送端程式:讀取 DHT11 並透過 ESP-NOW 傳輸資料
✅ 編寫接收端程式:接收資料並在序列監控器上顯示
✅ 驗證通訊結果

實測所需材料

  • ESP32 x 2  (一台作為「傳送端」,另一台作為「接收端」)
  • DHT11溫濕度感測器 x 1
  • SSD1306顯示器 x 1
  • 杜邦線 x 若干

優良商家推薦:

聯盟行銷揭露: AIoT Brian參與了聯盟行銷計劃,該計劃旨在透過連結到蝦皮 和其他網站來賺取佣金。我們可能會因向這些公司推薦流量和業務而獲得報酬。

DHT11 & SSD1306與 ESP32 接線圖

  • 一般ESP32的SDA & SCK(SCL),位在Pin 21 &  23腳
ESP-NOW_Temperature-Circuit Diagram

撰寫傳送端程式(帶 DHT11 感測與SSD1306顯示功能)

從第一章程式延用,我保留了原本的程式,把它註解,讓你可以對照,增加的部份。

注意:記得把程式中的"MAC Address"換成自己的接收板的MAC Address!

在編輯SSD1306 OLED顯示時,Arduino線上版本的U8G2中文字非常少,會有缺字,台灣MAKER群協力製作(主要由益師傅創建)的u8g2程式庫可支援七千字,無私分享給大家,下載連結如下。請使用IDE上頭”Sketch->程式庫->加入.zip程式庫”即可安裝這u8g2程式庫。

U8G2程式庫下載:twgo.io/vygya

				
					#include <esp_now.h>
#include <WiFi.h>
#include <SimpleDHT.h>
#include "Wire.h"
#include "U8g2lib.h"  //OLED 螢幕解析度為128*64
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE);

// 填入接收者的MAC Address
uint8_t broadcastAddress[] = { 0x44, 0x17, 0x93, 0xec, 0xb6, 0x0c };

// 建立一個矩陣資料,做為傳輸資料
typedef struct struct_message {
  // char a[32];
  int b;
  // float c;
  // bool d;
  int e;
  int f;
} struct_message;

// 建立矩陣資料為"mydata"
struct_message myData;

esp_now_peer_info_t peerInfo;

int pinDHT11 = 16;
SimpleDHT11 dht11(pinDHT11);

// 當資料傳輸後回應訊息是否"成功"或"失敗"
void OnDataSent(const wifi_tx_info_t *tx_info, esp_now_send_status_t status) {
  Serial.print("Last Packet Send Status: ");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "傳輸成功" : "傳輸失敗");
}


void setup() {
  // 序列埠鮑率
  Serial.begin(115200);

  // 將裝置設定為 Wi-Fi站
  WiFi.mode(WIFI_STA);

  // 切始化ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  // 成功初始化 ESP-NOW 後,註冊傳送訊息時呼叫的回呼函數
  esp_now_register_send_cb(OnDataSent);

  // 與另一個 ESP-NOW 裝置配對以發送資料
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.channel = 0;
  peerInfo.encrypt = false;

  // 加入接收端訊息
  if (esp_now_add_peer(&peerInfo) != ESP_OK) {
    Serial.println("連結端失敗");
    return;
  }
  u8g2.begin();                                //初始化
  u8g2.enableUTF8Print();                      //啟用 UTF8字集
  u8g2.setFont(u8g2_font_unifont_t_chinese1);  //設定使用中文字形
  u8g2.setDrawColor(1);                        //設定顏色,我們是單色只有1
  u8g2.setFontPosTop();                        //座標從上開始
  u8g2.setFontDirection(0);                    //0不旋轉、1->90、2->180、3->270
  pinMode(36, OUTPUT);
}
long i = 0;

void loop() {
  byte temperature = 0;
  byte humidity = 0;
  int err = SimpleDHTErrSuccess;
  if ((err = dht11.read(&temperature, &humidity, NULL)) != SimpleDHTErrSuccess) {
    Serial.print("Read DHT11 failed, err=");
    Serial.print(SimpleDHTErrCode(err));
    Serial.print(",");
    Serial.println(SimpleDHTErrDuration(err));
    delay(1000);
    return;
  }
  // 每2秒傳輸一條訊息
  // strcpy(myData.a, "這是字元");
  myData.b = random(1, 50);
  // myData.c = 1.2;
  // myData.d = false;
  myData.e = ((int)temperature);
  myData.f = ((int)humidity);

  // 透過ESP-NOW傳輸訊息
  esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *)&myData, sizeof(myData));

  //檢查訊息是否發送成功
  if (result == ESP_OK) {
    Serial.println("傳送訊息成功");
  } else {
    Serial.println("傳送訊息失敗");
  }

  int light = analogRead(36);
  i = i + 1;
  u8g2.clearBuffer();     //顯示前清除螢幕
  u8g2.setCursor(0, 20);  //移動游標
  u8g2.print("溫度:");
  u8g2.print((int)temperature + String("*C"));
  // u8g2.print("/");
  u8g2.setCursor(0, 40);  //移動游標
  u8g2.print("濕度:");
  u8g2.print((int)humidity + String("%"));  //寫入文字

  // u8g2.setCursor(0, 40);  //移動游標
  // u8g2.print("亮度:");   //寫入文字
  // u8g2.print(light);      //寫入文字

  u8g2.drawLine(0, 8, 128, 8);  //劃線從0,11->30,11
  //u8g2.drawLine(0, 60, 128, 60);

  u8g2.sendBuffer();  //送到螢幕顯示

  delay(2000);
}
				
			

撰寫接收端程式(顯示在 Serial Monitor)

				
					#include <esp_now.h>
#include <WiFi.h>

// 接收傳送方的矩陣資料,這對應格式必須相同
typedef struct struct_message {
    // char a[32];
    int b;
    // float c;
    // bool d;
    int e;
    int f;
} struct_message;

// 矩陣資料稱為"myData"
struct_message myData;

// 收到資料時會執行的回呼函數
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
  memcpy(&myData, incomingData, sizeof(myData));
  Serial.print("Bytes received: ");
  Serial.println(len);
  // Serial.print("Char: ");
  // Serial.println(myData.a);
  Serial.print("Int: ");
  Serial.println(myData.b);
  // Serial.print("Float: ");
  // Serial.println(myData.c);
  // Serial.print("Bool: ");
  // Serial.println(myData.d);
  Serial.print("Temperture: ");
  Serial.print(myData.e);
  Serial.println("°C");
  Serial.print("Humidity: ");
  Serial.print(myData.f);
  Serial.println("H");
  Serial.println();
}

void setup() {
  // 序列埠鮑率
  Serial.begin(115200);

  // 將裝置設定為Wi-Fi站
  WiFi.mode(WIFI_STA);

  // 與另一個 ESP-NOW 裝置配對
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  // 接收到訊息時呼叫的回呼函數
  esp_now_register_recv_cb(esp_now_recv_cb_t(OnDataRecv));
}

void loop() {

}
				
			

測試與結果

  1. 先上傳接收端程式 → 打開序列監控器(115200 bps)

  2. 再上傳傳送端程式 → 等待 DHT11 資料傳出

你應該會看到如下輸出:

ESP-NOW_Temperature

結語

本章實作示範了如何利用 ESP-NOW + DHT11 讓兩台 ESP32 無線交換真實世界的感測資料。
不需要 Wi-Fi、不需要網路,資料依然能即時同步!
這項技術對於 智慧農業、倉儲監測、環境感測 都非常實用。

常見問答 (FAQ)

Q1:DHT11 是否可以換成 DHT22?
可以,DHT22 精度更高,只需更改程式中的 DHTTYPE 定義即可。

Q2:讀取時為什麼出現 “NaN”?
可能是接線不良,或電源不足導致 DHT11 無法正常輸出資料。

Q3:是否可以同時傳送多組資料?
可以,只要在結構體中新增更多欄位即可(例如光照度、壓力等)。

Q4:ESP-NOW 傳輸速率夠快嗎?
對於感測應用完全足夠,每秒數十筆資料不是問題。

Q5:接收端能否存資料?
能,接收端可將資料存入 SD 卡或上傳雲端,視應用需求調整。

參考資料

夜市小霸王ESP32教學之”ESP32感測器接收與顯示” https://www.youtube.com/live/3F-cDeqYrbo?si=8NBG-Ie5UiKtqeaf

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

返回頂端