Table of Contents
Toggle前言:讓 ESP-NOW 傳真實世界的資料吧!
在第一章中,我們已經成功讓兩台 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 若干
優良商家推薦:
- https://s.shopee.tw/3VbjcwfK6p
- https://s.shopee.tw/1gA5RZmIpU
- https://s.shopee.tw/1qTVdslfUX
- https://s.shopee.tw/1LXF2xnZVS
聯盟行銷揭露: AIoT Brian參與了聯盟行銷計劃,該計劃旨在透過連結到蝦皮 和其他網站來賺取佣金。我們可能會因向這些公司推薦流量和業務而獲得報酬。
DHT11 & SSD1306與 ESP32 接線圖
- 一般ESP32的SDA & SCK(SCL),位在Pin 21 & 23腳

撰寫傳送端程式(帶 DHT11 感測與SSD1306顯示功能)
從第一章程式延用,我保留了原本的程式,把它註解,讓你可以對照,增加的部份。
注意:記得把程式中的"MAC Address"換成自己的接收板的MAC Address!
在編輯SSD1306 OLED顯示時,Arduino線上版本的U8G2中文字非常少,會有缺字,台灣MAKER群協力製作(主要由益師傅創建)的u8g2程式庫可支援七千字,無私分享給大家,下載連結如下。請使用IDE上頭”Sketch->程式庫->加入.zip程式庫”即可安裝這u8g2程式庫。
U8G2程式庫下載:twgo.io/vygya
#include
#include
#include
#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
#include
// 接收傳送方的矩陣資料,這對應格式必須相同
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() {
}
測試與結果
先上傳接收端程式 → 打開序列監控器(115200 bps)
再上傳傳送端程式 → 等待 DHT11 資料傳出
你應該會看到如下輸出:

結語
本章實作示範了如何利用 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
