從零開始學 ESP-NOW:ESP32與Arduino IDE 裝置之間的點對點資料交換教學

如果你曾經使用過 ESP32,就會知道它支援 Wi-Fi 和藍牙,但你是否知道它還有一項超方便的「隱藏技能」——ESP-NOW?
這是一種由 Espressif(樂鑫) 開發的點對點無線傳輸協定,可以讓多個 ESP32 裝置彼此直接傳遞資料,不需要 Wi-Fi AP 或路由器!

想像一下,你可以讓幾台 ESP32 在沒有網路的地方彼此交換資料,例如感測器、遙控器、無線節點網路……這就是 ESP-NOW 的魅力所在。

ESP-NOW 是如何運作的?

ESP-NOW 是基於 2.4GHz 頻段 的通訊協定,使用與 Wi-Fi 相同的射頻硬體,但資料封包更簡潔輕量。
它透過裝置的 MAC Address(媒體存取控制位址) 來識別彼此,因此在網路架構上屬於「點對點(Peer-to-Peer)」。

每個節點可以:

  • 同時與多達 20 個裝置通訊
  • 不需 Wi-Fi 連線即可傳輸資料
  • 支援雙向通訊與加密模式

ESP-NOW 單向通信

首先介紹單向傳輸

  • 一塊 ESP32 開發板向另一塊 ESP32 開發板發送數據

這種配置非常容易實現,非常適合將資料從一塊板發送到另一塊板,例如感測器讀數或控制 GPIO 的開啟和關閉命令。

ESP_NOW單點傳輸

準備開始前:你需要的設備

  • 兩塊 ESP32 開發板
  • USB 傳輸線
  • Arduino IDE

優良廠商推薦:

提示:
確保你安裝了 Arduino IDE 的 ESP32 核心模組,並在「工具 → 開發板」中選擇 ESP32 Dev Module。

Arduino IDE設定教學,請參考之前教學"ESP32的創新與應用:引領未來技術趨勢

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

建立第一個 ESP-NOW 傳送端與接收端

步驟 1:取得接收端 MAC Address

提醒:上傳程式後,按ESP32控制板USB埠旁的EN鈕,它就會出現在”序列埠監控視窗”,記得先把這MAC Address抄寫下來,待會要填入程式中

				
					#include <WiFi.h>
#include <esp_wifi.h>

void readMacAddress(){
  uint8_t baseMac[6];
  esp_err_t ret = esp_wifi_get_mac(WIFI_IF_STA, baseMac);
  if (ret == ESP_OK) {
    Serial.printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
                  baseMac[0], baseMac[1], baseMac[2],
                  baseMac[3], baseMac[4], baseMac[5]);
  } else {
    Serial.println("Failed to read MAC address");
  }
}

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

  WiFi.mode(WIFI_STA);
  WiFi.STA.begin();

  Serial.print("[DEFAULT] ESP32 Board MAC Address: ");
  readMacAddress();
}
 
void loop(){

}
				
			
MAC_Address

ESP-NOW 單向點對點通信

為了幫助您開始使用 ESP-NOW 無線通信,我們將建立一個簡單的項目,示範如何從一個 ESP32 向另一個 ESP32 發送訊息。其中一個 ESP32 將作為“發送方”,另一個 ESP32 將作為“接收方”。

為了更好地理解,我們將 ESP32 #1 稱為“發送者”,將 ESP32 #2 稱為“接收者”。

ESP32 #1 發送者程式 (ESP-NOW)

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

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

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

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

esp_now_peer_info_t peerInfo;

// 當資料傳輸後回應訊息是否"成功"或"失敗"
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;
  }
}

void loop() {
  // 每2秒傳輸一條訊息
  strcpy(myData.a, "這是字元");
  myData.b = random(1, 20);
  myData.c = 1.2;
  myData.d = false;

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

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

ESP32 #2 接收者程式(ESP-NOW)

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

// 接收傳送方的矩陣資料,這對應格式必須相同
typedef struct struct_message {
    char a[32];
    int b;
    float c;
    bool d;
} 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.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() {

}
				
			

實戰應用案例:無線感測網

假設你有 5 個溫濕度節點,每個節點透過 ESP-NOW 將資料傳給一台主控 ESP32,再由主控上傳至雲端伺服器。
這種架構常見於溫室監測、智慧農業或倉儲管理中。

結語

ESP-NOW 是 ESP32 的「隱藏武器」,能讓你在無網環境下實現高效、低延遲的無線通訊。
無論是遠端感測、無線控制還是 IoT 節點網,ESP-NOW 都能讓你的專案更靈活、更節能!

常見問答 (FAQ)

Q1:ESP-NOW 可以穿牆傳輸嗎?
可以,但距離會受牆體材質影響,建議使用外接天線版本。

Q2:ESP32-S2 / S3 支援 ESP-NOW 嗎?
是的,Espressif 官方已在 SDK 中提供支援。

Q3:ESP-NOW 可以和 ESP8266 通訊嗎?
可以,但需確保韌體版本相容,並使用相同通道。

Q4:ESP-NOW 傳輸距離多遠?
在空曠環境約 150 公尺,視天線與功率而定。

Q5:能否與手機直接通訊?
不行,ESP-NOW 為 ESP 專用協定,手機不支援此模式。

參考資料

RANDOM NERD TUTORIALS教學網站之Getting Started with ESP-NOW: https://randomnerdtutorials.com/esp-now-esp32-arduino-ide/

發佈留言

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

返回頂端