內容目錄
ToggleESP-NOW入門(帶有Arduino IDE的ESP8266 NodeMCU)
在本文中,我們將向您展示如何使用ESP-NOW在使用Arduino IDE編程的ESP8266 NodeMCU板之間交換數據。ESP-NOW是由Espressif開發的無連接通信協議,具有短數據包傳輸功能,可與ESP8266和ESP32板一起使用。
我們還有其他有關ESP8266的ESP-NOW的教程:
- ESP8266 NodeMCU板之間的ESP-NOW雙向通信
- ESP-NOW與ESP8266:將數據發送到多個開發板(一對多)
- ESP-NOW與ESP8266:從多個開發板接收數據(多對一)
Arduino IDE
介紹ESP-NOW
這意思為只要將設備彼此配對後,連接將保持不變。換句話說,如果您的一塊板突然斷電或複位,則在重新啟動時,它將自動連接到其對等端以繼續通信。
ESP-NOW支持以下功能:
- 加密和未加密的單播通信;
- 混合加密和未加密對等設備;
- 最多可以承載250-byte有效負載;
- 發送回饋函數,可以設置為通知應用層在傳輸成功或失敗時。
ESP-NOW技術還具有以下限制:
- 有限的加密對等體。工作站模式下最多支持10個加密對等體;在SoftAP或SoftAP + Station模式下最多6個;
- 支持多個未加密的對等方,但是它們的總數應少於20,其中包括已加密的對等方;
- 有效負載限制為250個bytes。
簡而言之,ESP-NOW是一種快速通信協議,可用於在ESP8266板之間交換小消息(最大250 bytes)。
ESP-NOW具有多種用途,您可以在不同的設置中進行單向或雙向通信。
ESP-NOW單向通信
例如,在單向通信中,您可能會遇到以下情形:
- 一個ESP8266開發板向另一個ESP8266開發板發送數據
這種配置非常容易實現,並且很容易將數據從一塊板發送到另一塊板,例如感測器讀取數據或控制GPIO的ON和OFF命令。
- 一個“Master” ESP8266將數據發送到多個ESP8266“Slave”
一塊ESP8266開發板向不同的ESP8266開發板發送相同或不同的命令。此配置是建構遙控器之類的理想選擇。整個房屋中可以有幾塊ESP8266板,由一塊主ESP8266板控制。
- 一個ESP8266“Slave”從多個“Masters”接收數據
如果要將多個感測器節點的數據收集到一個ESP8266板中,則此配置非常理想。例如,可以將其配置為Web Server以顯示來自所有其他板的數據。
注意:在ESP-NOW檔案中,沒有“發送方/主方”和“接收方/從方”之類的東西。每個板都可以是發送者或接收者。只是,為讓內容架構清楚,這裡將使用“發送者”和“接收者”或“主”和“從”這類的術語說明解釋。
ESP-NOW雙向通訊
使用ESP-NOW,每個板可以同時是發送者和接收者。因此,您可以在開發板之間建立雙向通信。
例如,您可以使兩個開發板彼此通信。
也可以在此配置中增加更多開發板,並使它們看起來像一個網絡(所有ESP8266開發板都可以相互通信)。
總而言之,ESP-NOW是建置網絡的理想選擇,在該網絡中,您可以有多個ESP8266開發板相互交換數據。
ESP8266:取得開發板MAC地址
// 完成和更改ESP MAC地址的完整說明:
// http://honeststore.com.tw/blog/esp8266-esp-now/
#include <ESP8266WiFi.h>
void setup(){
Serial.begin(115200);
Serial.println();
Serial.print("ESP8266 Board MAC Address: ");
Serial.println(WiFi.macAddress());
}
void loop(){
}
上載程式碼後,以115200的鮑率打開Serial Monitor,然後按ESP8266 RESET按鈕。MAC地址應如下打印:先保存查詢到開發板的MAC地址,因為您需要它通過ESP-NOW將數據發送到正確的開發板。
ESP-NOW與ESP8266的單向點對點通訊
我們將發送一個結構,其中包含char,int,float,String和boolean類型的變數。然後,您可以修改結構以發送適合您項目的任何變數類型(例如感測器讀取數據或boolean變數以開啟或關閉某些內容)。
為了更好的理解,我們將ESP8266#1稱為“發送方”,將ESP8266#2稱為“接收方”。
這是我們應該包含在發件人草稿圖中的內容:
- 初始化ESP-NOW;
- 在發送數據時註冊回饋函數– OnDataSent發送消息時將執行功能。可以告訴我們消息是否成功發送;
- 增加對等設備(接收方)。為此,您需要知道接收者的MAC地址;
- 向對等設備發送消息。
在接收方,草稿圖應包括:
- 初始化ESP-NOW;
- 註冊接收回饋函數(OnDataRecv)。收到消息後將執行的功能。
- 在該回饋函數內部,將消息保存到變數中以執行具有該信息的任何任務。
ESP-NOW與設備接收消息或發送消息時調用的回饋函數一起使用(您可以確定消息是否已成功發送或失敗)。
ESP-NOW有用的功能
函數名稱和說明 |
esp_now_init()初始化ESP-NOW。您必須先初始化Wi-Fi,然後再初始化ESP-NOW。如果成功,則返回0。 |
esp_now_set_self_role(role) role可以是: ESP_NOW_ROLE_IDLE = 0, ESP_NOW_ROLE_CONTROLLER, ESP_NOW_ROLE_SLAVE, ESP_NOW_ROLE_COMBO, ESP_NOW_ROLE_MAX |
esp_now_add_peer(uint8 mac_addr,uint8 role,uint8 channel,uint8 key,uint8 key_len) 調用此功能以配對設備。 |
esp_now_send(uint8 mac_address,uint8 data,int len) 使用ESP-NOW發送數據。 |
esp_now_register_send_cb()註冊在發送數據時觸發的回饋函數。發送消息後,將調用一個函數–此函數返回傳遞是否成功。 |
esp_now_register_rcv_cb()註冊在接收數據時觸發的回饋函數。通過ESP-NOW接收到數據後,將調用一個函數。 |
有關這些功能的更多信息:
ESP8266 NodeMCU發送方草稿圖(ESP-NOW)
以下是ESP8266 NodeMCU Sender開發板的程式碼。將程式碼複製到您的Arduino IDE,上傳前,您需要先進行一些修改。
/*
Terry Lee
完整說明請參閱 http://honeststore.com.tw/blog/esp8266-esp-now/
*/
#include <ESP8266WiFi.h>
#include <espnow.h>
// 替換成接收方的MAC Address
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
// 結構範例發送數據必須匹配接收方結構
typedef struct struct_message {
char a[32];
int b;
float c;
String d;
bool e;
} struct_message;
// 新建一個訊息傳送結構,變數名稱叫myData
struct_message myData;
unsigned long lastTime = 0;
unsigned long timerDelay = 2000; // 發送讀數計時器
// 發送數據時的回饋函數
void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) {
Serial.print("Last Packet Send Status: ");
if (sendStatus == 0){
Serial.println("Delivery success");
}
else{
Serial.println("Delivery fail");
}
}
void setup() {
// Init Serial Monitor
Serial.begin(115200);
// 將設備設置為Wi-Fi工作站
WiFi.mode(WIFI_STA);
// Init ESP-NOW
if (esp_now_init() != 0) {
Serial.println("Error initializing ESP-NOW");
return;
}
// 一旦Espnow成功初始化,我們將註冊發送回饋函數至獲取數據包的狀態
esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
esp_now_register_send_cb(OnDataSent);
// 註冊同行
esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);
}
void loop() {
if ((millis() - lastTime) > timerDelay) {
// 設定預發送的值
strcpy(myData.a, "THIS IS A CHAR");
myData.b = random(1,20);
myData.c = 1.2;
myData.d = "Hello";
myData.e = false;
// 從ESP-NOW傳送訊息
esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
lastTime = millis();
}
}
程式碼如何工作
首先,包括 ESP8266WiFi.h 和 espnow.h 庫。
#include <ESP8266WiFi.h>
#include <espnow.h>
在下一行中,應插入ESP8266接收器MAC地址。
uint8_t broadcastAddress[] = {0x5C, 0xCF, 0x7F, 0x99, 0x9A, 0xEA};
在我們的例子中,接收者的MAC地址是: 5C:CF:7F:99:9A:EA,但您需要用自己的MAC地址替換該變量。 然後,建立一個包含我們要發送的數據類型的結構。我們稱這種結構struct_message它包含5種不同的變數類型。您可以更改它以發送所需的任何變量類型。
typedef struct struct_message {
char a[32];
int b;
float c;
String d;
bool e;
} struct_message;
建一個新的類型變數 struct_message 它被稱作 myData 將存儲變數值。
struct_message myData;
接下來,定義 OnDataSent()功能。這是一個回饋函數,將在發送消息時執行。在這種情況下,無論是否成功發送此消息,都只會印出該消息。
void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) {
Serial.print("Last Packet Send Status: ");
if (sendStatus == 0){
Serial.println("Delivery success");
}
else{
Serial.println("Delivery fail");
}
}
在setup()裡,初始化序列監視器以進行調試:
Serial.begin(115200);
將設備設置為Wi-Fi工作站點:
WiFi.mode(WIFI_STA);
初始化ESP:
if (esp_now_init() != 0) {
Serial.println("Error initializing ESP-NOW");
return;
}
設置ESP8266角色:
esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
它接受以下角色: ESP_NOW_ROLE_CONTROLLER, ESP_NOW_ROLE_SLAVE, ESP_NOW_ROLE_COMBO, ESP_NOW_ROLE_MAX。
成功初始化ESP-NOW之後,註冊將在發送消息時調用的回饋函數。在這種情況下,我們註冊OnDataSent() 先前建置的功能。
esp_now_register_send_cb(OnDataSent);
然後,與另一個ESP-NOW設備配對以發送數據:
esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);
esp_now_add_peer 按此順序接受以下參數:mac address,role,Wi-Fi channel,key和key長度。 在loop()裡,我們將每2秒通過ESP-NOW發送一條消息(您可以更改延時時間在 timerDelay 變數)。 首先,我們將變數值設置如下:
strcpy(myData.a, "THIS IS A CHAR");
myData.b = random(1,20);
myData.c = 1.2;
myData.d = "Hello";
myData.e = false;
請記住 myData是一個結構。在這裡,我們分配要在結構內部發送的值。例如,第一行分配一個char,第二行分配一個隨機的Int,一個Float,一個String和一個Boolean變數。 我們建立這種結構來向您展示如何發送最常見的變數類型。您可以更改結構以發送任何其他類型的數據。 最後,發送消息如下:
esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
loop() 函數裡,每2000毫秒(2秒)執行一次。
if ((millis() - lastTime) > timerDelay) {
// Set values to send
strcpy(myData.a, "THIS IS A CHAR");
myData.b = random(1,20);
myData.c = 1.2;
myData.d = "Hello";
myData.e = false;
// Send message via ESP-NOW
esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
lastTime = millis();
}
ESP8266 NodeMCU接收器草稿圖(ESP-NOW)
將以下程式碼上傳至ESP8266 NodeMCU接收板。
/*
Terry Lee
完整說明請參閱 http://honeststore.com.tw/blog/esp8266-esp-now/
*/
#include <ESP8266WiFi.h>
#include <espnow.h>
// 結構範例接收數據必須匹配發送方結構
typedef struct struct_message {
char a[32];
int b;
float c;
String d;
bool e;
} struct_message;
// 新建一個訊息接收結構,變數名稱叫myData
struct_message myData;
// 收到數據時將執行的回饋函數
void OnDataRecv(uint8_t * mac, uint8_t *incomingData, uint8_t 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("String: ");
Serial.println(myData.d);
Serial.print("Bool: ");
Serial.println(myData.e);
Serial.println();
}
void setup() {
// Initialize Serial Monitor
Serial.begin(115200);
// 將設備設置為Wi-Fi工作站
WiFi.mode(WIFI_STA);
// Init ESP-NOW
if (esp_now_init() != 0) {
Serial.println("Error initializing ESP-NOW");
return;
}
// 一旦Espnow成功初始化,我們將註冊發送回饋函數至獲取數據包的狀態
esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
esp_now_register_recv_cb(OnDataRecv);
}
void loop() {
}
程式碼如何工作
與發送方類似,首先包括以下庫:
#include <ESP8266WiFi.h>
#include <espnow.h>
建立一個結構以接收數據。此結構應與發件人草稿圖中定義的結構相同。
typedef struct struct_message {
char a[32];
int b;
float c;
String d;
bool e;
} struct_message;
建立一個 struct_message 變數稱為 myData。
struct_message myData;
建立一個回饋函數,當ESP8266通過ESP-NOW接收數據時將調用該函數。該函數稱為onDataRecv() 並應接受以下幾個參數:
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
我們複製內容將 incomingData 數據變數放入 myData 變數中。
memcpy(&myData, incomingData, sizeof(myData));
現在 myData結構內部包含幾個變數,以及發送方ESP8266發送的值。例如,訪問變數a,我們只需要呼叫 myData.a。 在此範例中,我們僅印出接收到的數據,但是在實際應用中,您可以在顯示器上印出數據。
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("String: ");
Serial.println(myData.d);
Serial.print("Bool: ");
Serial.println(myData.e);
Serial.println();
}
在 setup()裡,初始化序列通信以進行調試。
Serial.begin(115200);
將設備設置為Wi-Fi工作站。
WiFi.mode(WIFI_STA);
初始化ESP:
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}
設置ESP8266角色:
esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
註冊接收數據時將調用的回饋函數。在這種情況下,我們註冊OnDataRecv() 先前建置的功能。
esp_now_register_recv_cb(OnDataRecv);
測試ESP-NOW通信
現在,打開兩個Arduino IDE窗口。一個給接收者,另一個給發送者。打開每個開發板的序列監視器。每個開發板應該是不同的COM端口。
下面就是您在發送方獲得的東西。
下面是您應該在接收端得到的。請注意,Int變數會在每次接收到的讀取數據之間變化(因為我們在發送方將其設置為1-50之間的隨機數)
總結
ESP8266和ESP32板可以使用ESP-NOW通訊協議進行通訊。您只需要將適當的草稿圖上傳到每個控制板上。要了解如何將ESP-NOW與ESP32結合使用,可以閱讀ESP32的ESP-NOW入門指南。
我們希望您對本教程有所幫助。要了解有關ESP8266開發板的更多信息,請確保您了解我們的資源:
- ESP8266的家庭自動化
- 使用ESP32和ESP8266進行MicroPython編程
- 更多ESP8266資源…
謝謝閱讀。