Qua bài này, bạn sẽ hiểu được cách sử dụng ESP-NOW để trao đổi dữ liệu giữa các Board Node Wifi32 (ESP32) được lập trình trên Arduino IDE. ESP-NOW là một giao thức truyền thông không dây, được phát triển bởi Espressif có tính năng truyền gửi tín hiệu. Giao thức này cho phép nhiều thiết bị giao tiếp với nhau một cách dễ dàng.
>> Xem thêm: [PDF] Lập trình Arduino là gì? Tài liệu học Arduino miễn phí 2021
Mục lục
GIỚI THIỆU ESP-NOW
Trang web Espressif có nói rõ, ESP-NOW là một “giao thức được phát triển bới Espressif, cho phép nhiều thiết bị giao tiếp với nhau mà không cần dùng Wifi. Giao thức tương tự như kết nối không dây 2.4GHz công suất thấp(…). Việc ghép nối giữa các thiết bị là rất cần thiết trước khi giao tiếp. Kết nối an toàn và không cần dùng tay.”
Điều này có nghĩa là sau khi kết nối giữa các thiết bị với nhau, kết nối sẽ ổn định. Nói cách khác, nếu đột nhiên một trong các board mạch của bạn bị mất nguồn hoặc Reset, khi khởi động lại, nó sẽ tự động kết nối với nhau để tiếp tục giao tiếp.
Ưu điểm của ESP NOW
ESP-NOW hỗ trợ các tính năng sau:
- Giao tiếp Unicast đã được mã hóa và không được mã hóa;
- Các thiết bị ngang hàng được mã hóa và không được mã hóa một cách hỗn hợp;
- Có thể ghi nhớ lên đến 250 byte
- Có chức năng gọi lại để thông báo về sự thành công hay thất bại trong quá trình truyền.
Hạn chế của ESP NOW
Tuy nhiên, công nghệ ESP-NOW cũng có những mặt hạn chế sau:
- Nhiều ứng dụng ngang hàng không được hỗ trợ mã hóa. Tuy nhiên, tổng số của chúng phải nhỏ hơn 20, bao gồm cả các đối tượng được mã hóa;
- Bộ nhớ giới hạn ở 250 byte .
Nói một cách dễ hiểu, ESP-NOW là một giao thức truyền thông nhanh có thể được sử dụng để trao đổi các tin nhắn nhỏ (lên đến 250 byte) giữa các board mạch ESP32
ESP-NOW rất linh hoạt và bạn có thể giao tiếp một chiều hoặc hai chiều khác nhau.
GIAO TIẾP MỘT CHIỀU ESP-NOW
Ví dụ: Trong giao tiếp một chiều, bạn có thể có các tình huống như sau:
Một board Node Wifi32 gửi dữ liệu đến một board Node Wifi32 khác
Cấu hình này rất dễ thực hiện và thật tuyệt khi gửi dữ liệu từ board Node Wifi 32 (ESP32) này sang board khác như các chỉ số cảm biến hoặc lệnh ON và OFF để điều khiển GPIO.
Một board Node Wifi32 “chính” gửi dữ liệu đến nhiều board Node Wifi32 “phụ”
Một board Node Wifi32 (ESP32) gửi các lệnh giống nhau hoặc khác nhau đến các board Node Wifi32 khác nhau. Cấu hình này là cấu hình lý tưởng để xây dựng một cái gì đó giống như một thiết bị điều khiển từ xa. Bạn có thể có một số board Node Wifi32 xung quanh ngôi nhà của bạn và được điều khiển bởi một board Node Wifi32 chính.
Một board Node Wifi32 “phụ” nhận dữ liệu từ nhiều “chủ”
Cấu hình này là một cấu hình lý tưởng nếu bạn muốn thu thập dữ liệu từ một số cảm biến vào một board Node Wifi32. Ví dụ, điều này có thể được cấu hình như một máy chủ web để hiển thị dữ liệu từ tất cả các board mạch khác.
GIAO TIẾP HAI CHIỀU ESP-NOW
Với ESP-NOW, mỗi board có thể là thiết bị gửi hoặc thiết bị nhận cùng một lúc. Vì vậy, bạn có thể thiết lập giao tiếp hai chiều giữa các board mạch.
Ví dụ, bạn có thể có hai board giao tiếp với nhau.
Bạn có thể thêm nhiều board mạch vào cấu hình như trên và sẽ thấy có một cái gì đó giống như một lưới mạng (tất cả các board Node Wifi32 giao tiếp với nhau).
Tóm lại, ESP-NOW là một phương án lý tưởng để xây dựng một mạng lưới mạng, trong đó bạn có thể có một số board Node Wifi32 trao đổi dữ liệu với nhau.
NODE WIFI32: Lấy Địa Chỉ MAC Của Board
Để giao tiếp qua ESP-NOW, bạn cần biết đến địa chỉ MAC của bộ thu Node Wifi32 (ESP32). Đó là cách bạn biết mình sẽ gửi thông tin đến thiết bị nào.
Mỗi Node Wifi32 sẽ có một địa chỉ MAC duy nhất. Đây là cách chúng tôi xác định từng board riêng biệt để gửi dữ liệu đến nó bằng ESP-NOW.
Để có được địa chỉ MAC trên board, bạn hãy sử dụng đoạn code sau:
// Complete Instructions to Get and Change ESP MAC Address: https://RandomNerdTutorials.com/get-change-esp32-esp8266-mac-address-arduino/ #include "WiFi.h" void setup(){ Serial.begin(115200); WiFi.mode(WIFI_MODE_STA); Serial.println(WiFi.macAddress()); } void loop(){ }
Sau khi nạp code thành công, mở Serial Monitor ở tốc độ truyền 115200 và nhấn nút Reset trên board Node Wifi 32 (ESP32) . Địa chỉ MAC sẽ được hiển thị như sau:
Lưu lại địa chỉ MAC, vì để gửi dữ liệu qua ESP-NOW phải cần MAC.
GIAO TIẾP MỘT CHIỀU CỦA ESP-NOW
Để giúp bạn bắt đầu với giao tiếp không dây ESP-NOW, chúng tôi sẽ xây dựng một dự án đơn giản minh họa cho bạn. Chúng tôi sẽ chỉ ra cách gửi tin nhắn từ board Node Wifi32 này sang board Node Wifi32 khác. Một board Node Wifi32 sẽ là “thiết bị gửi” và board Node Wifi32 kia sẽ là “thiết bị nhận”.
Ta sẽ gửi một cấu trúc có chứa một biến có kiểu dữ liệu char, int, float, string, và boolean. Sau đó, ta có thể sửa đổi cấu trúc để gửi bất kỳ loại biến nào phù hợp với bài học đang áp dụng (như đọc tín hiệu từ cảm biến hoặc sử dụng kiểu dữ liệu boolean để bật hoặc tắt thứ gì đó).
Để hiểu rõ hơn, ta sẽ gọi “thiết bị gửi” là Node Wifi32 #1 và “thiết bị nhận” là Node Wifi32 #2.
Vai trò của thiết bị gửi
Dưới vai trò là “thiết bị gửi”, sau đây là những bước cơ bản nên đưa vào:
- Khởi tạo ESP-NOW
- Đăng ký chức năng phản hồi lại khi gửi dữ liệu – OnDataSent chức năng này sẽ được thực hiện khi một tin nhắn được gửi đi. Điều này có thể cho ta biết dữ liệu được gửi có thành công hay không.
- Thêm thiết bị ngang hàng (máy thu). Đối với điều này, bạn cần biết địa chỉ MAC của “thiết bị nhận”.
- Gửi tin nhắn đến thiết bị ngang hàng.
Vai trò của thiết bị nhận
Về phía “thiết bị nhận”, những bước cơ bản như sau:
- Khởi tạo ESP-NOW
- Đăng ký chức năng nhận lại phản hồi khi nhận dữ liệu (OnDataRecv). Đây là một hàm sẽ được thực hiện khi nhận được phản hồi.
- Bên trong hàm OnDataRecv đó, lưu thông báo vào một biến để thực hiện bất kỳ nhiệm vụ nào khi nhận thông tin đó.
CÁC CHỨC NĂNG HỮU ÍCH CỦA ESP-NOW
Bên dưới là những tóm tắt về chức năng của ESP-NOW cần thiết nhất:
- esp_now_init (): Khởi tạo ESP-NOW. Bạn phải khởi tạo Wi-Fi trước khi khởi chạy ESP-NOW.
- esp_now_add_peer (): Hàm này được dùng để ghép nối một thiết bị và chuyển làm đối số là địa chỉ MAC ngang hàng.
- esp_now_send (): Gửi dữ liệu với ESP-NOW.
- esp_now_register_send_cb () : Đăng ký một chức năng gọi lại được kích hoạt khi gửi dữ liệu. Khi một tin nhắn được gửi đi, một hàm được gọi – hàm này trả về việc gửi có thành công hay không.
- esp_now_register_rcv_cb () : Đăng ký một chức năng gọi lại được kích hoạt khi nhận dữ liệu. Khi dữ liệu được nhận qua ESP-NOW, một hàm được gọi.
TÓM LƯỢC VAI TRÒ “THIẾT BỊ GỬI” NODE WIFI 32 (ESP-NOW)
Đây là đoạn code cho board Node Wifi32 với vai trò là “thiết bị gửi”. Copy đoạn code bên dưới và cho vào Arduino IDE, tải chương trình xuống. Ta cần thực hiện một vài sửa đổi để làm cho nó phù hợp khi sử dụng.
/* Rui Santos Complete project details at https://RandomNerdTutorials.com/esp-now-esp32-arduino-ide/ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. */ #include #include // REPLACE WITH YOUR RECEIVER MAC Address uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // Structure example to send data // Must match the receiver structure typedef struct struct_message { char a[32]; int b; float c; String d; bool e; } struct_message; // Create a struct_message called myData struct_message myData; // callback when data is sent void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) { Serial.print("\r\nLast Packet Send Status:\t"); Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail"); } void setup() { // Init Serial Monitor Serial.begin(115200); // Set device as a Wi-Fi Station WiFi.mode(WIFI_STA); // Init ESP-NOW if (esp_now_init() != ESP_OK) { Serial.println("Error initializing ESP-NOW"); return; } // Once ESPNow is successfully Init, we will register for Send CB to // get the status of Trasnmitted packet esp_now_register_send_cb(OnDataSent); // Register peer esp_now_peer_info_t peerInfo; memcpy(peerInfo.peer_addr, broadcastAddress, 6); peerInfo.channel = 0; peerInfo.encrypt = false; // Add peer if (esp_now_add_peer(&peerInfo) != ESP_OK){ Serial.println("Failed to add peer"); return; } } void loop() { // 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_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData)); if (result == ESP_OK) { Serial.println("Sent with success"); } else { Serial.println("Error sending the data"); } delay(2000); }
GIẢI THÍCH CODE:
Đầu tiên, hãy add các thư viện esp_now.h , WiFi.h như dưới:
#include #include
Trong hàng tiếp theo, ta nên chèn địa chỉ MAC của bộ thu Node Wifi32
uint8_t broadcastAddress[] = {0x30, 0xAE, 0xA4, 0x07, 0x0D, 0x64};
Trong trường hợp của chúng tôi, địa chỉ MAC của người nhận sẽ là: 30: AE: A4: 07: 0D: 64, nhưng ta cần thay thế những biến đó bằng địa chỉ MAC.
Sau đó, tạo một cấu trúc có chứa loại dữ liệu mà chúng ta gửi. Chúng ta gọi cấu trúc này là struct_message và nó chứa 5 loại biến khác nhau. Bạn có thể thay đổi điều này để gửi bất kỳ loại biến nào bạn muốn.
typedef struct struct_message { char a[32]; int b; float c; String d; bool e; } struct_message;
Sau đó, tạo một biến mới kiểu struct_message cái đó được gọi là dữ liệu của tôi sẽ lưu các giá trị biến.
struct_message myData;
Tiếp theo, xác định OnDataSent () chức năng. Đây là một hàm gọi lại sẽ được thực thi khi một tin nhắn được gửi đi. Trong trường hợp này, chức năng này chỉ in ra nếu tin nhắn đã được gửi thành công hay chưa.
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) { Serial.print("\r\nLast Packet Send Status:\t"); Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail"); }
bên trong setup(), khởi tạo màn hình nối tiếp cho mục đích gỡ lỗi:
Serial.begin(115200);
Đặt thiết bị làm trạm Wi-Fi:
WiFi.mode(WIFI_STA);
Khởi tạo ESP-NOW:
if (esp_now_init() != ESP_OK) { Serial.println("Error initializing ESP-NOW"); return; }
Sau khi khởi tạo thành công ESP-NOW, hãy đăng ký chức năng gọi lại sẽ được gọi khi có tin nhắn được gửi đi. Trong trường hợp này, chúng tôi đăng ký OnDataSent () chức năng đã tạo trước đó.
esp_now_register_send_cb(OnDataSent);
Sau đó, chúng ta cần ghép nối với một thiết bị ESP-NOW khác để gửi dữ liệu. Đó là những gì chúng tôi làm trong những dòng tiếp theo:
//Register peer esp_now_peer_info_t peerInfo; memcpy(peerInfo.peer_addr, broadcastAddress, 6); peerInfo.channel = 0; peerInfo.encrypt = false; //Add peer if (esp_now_add_peer(&peerInfo) != ESP_OK){ Serial.println("Failed to add peer"); return; }
Bên trong loop(), chúng tôi sẽ gửi tin nhắn qua ESP-NOW cứ sau 2 giây (bạn có thể thay đổi thời gian trễ này).
Đầu tiên, chúng tôi đặt các giá trị biến như sau:
strcpy(myData.a, "THIS IS A CHAR"); myData.b = random(1,20); myData.c = 1.2; myData.d = "Hello"; myData.e = false;
Nhớ lấy My data là một cấu trúc. Ở đây chúng tôi gán các giá trị mà chúng tôi muốn gửi bên trong cấu trúc. Ví dụ: dòng đầu tiên gán một ký tự, dòng thứ hai gán một số Int ngẫu nhiên, một Float, một Chuỗi và một biến Boolean.
Chúng tôi tạo loại cấu trúc này để chỉ cho bạn cách gửi các loại biến phổ biến nhất. Bạn có thể thay đổi cấu trúc để gửi bất kỳ loại dữ liệu nào khác.
Cuối cùng, gửi tin nhắn như sau:
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
Kiểm tra xem tin nhắn đã được gửi thành công chưa:
if (result == ESP_OK) { Serial.println("Sent with success"); } else { Serial.println("Error sending the data"); }
Các loop() được thực thi cứ sau 2000 mili giây (2 giây).’
delay(2000);
TÓM LƯỢC VAI TRÒ “THIẾT BỊ NHẬN” NODE WIFI32 (ESP-NOW)
Sử dụng đoạn code bên dưới và tải về Board Node Wifi32
/* Rui Santos Complete project details at https://RandomNerdTutorials.com/esp-now-esp32-arduino-ide/ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. */ #include #include // Structure example to receive data // Must match the sender structure typedef struct struct_message { char a[32]; int b; float c; String d; bool e; } struct_message; // Create a struct_message called myData struct_message myData; // callback function that will be executed when data is received 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("String: "); Serial.println(myData.d); Serial.print("Bool: "); Serial.println(myData.e); Serial.println(); } void setup() { // Initialize Serial Monitor Serial.begin(115200); // Set device as a Wi-Fi Station WiFi.mode(WIFI_STA); // Init ESP-NOW if (esp_now_init() != ESP_OK) { Serial.println("Error initializing ESP-NOW"); return; } // Once ESPNow is successfully Init, we will register for recv CB to // get recv packer info esp_now_register_recv_cb(OnDataRecv); } void loop() { }
CODE HOẠT ĐỘNG
Tương tự với “thiết bị gửi”, hãy bắt đầu bằng cách bao gồm các thư viện:
#include #include
Tạo cấu trúc để nhận dữ liệu. Cấu trúc này phải được xác định giống nhau trong bản phác thảo của người gửi.
typedef struct struct_message { char a[32]; int b; float c; String d; bool e; } struct_message;
Tạo một struct_message biến được gọi là myData.
struct_message myData;
Tạo một hàm gọi lại sẽ được gọi khi Node Wifi32 nhận dữ liệu qua ESP-NOW. Hàm được gọi là onDataRecv () và nên chấp nhận một số tham số như sau:
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
Chúng tôi sao chép nội dung của incomingData biến dữ liệu thành myData Biến đổi.
memcpy(&myData, incomingData, sizeof(myData));
Bây giờ, myData cấu trúc chứa một số biến bên trong với các giá trị được gửi bởi “thiết bị gửi”. Để truy cập biến a, ví dụ, chúng tôi chỉ cần gọi myData.a.
Trong ví dụ này, chúng tôi chỉ cần in dữ liệu đã nhận, nhưng trong một ứng dụng thực tế, bạn có thể in dữ liệu trên màn hình chẳng hạn.
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(); }
bên trong setup(), mở rộng màn hình nối tiếp.
Serial.begin(115200);
Đặt thiết bị làm Trạm Wi-Fi.
WiFi.mode(WIFI_STA);
Khởi tạo ESP-NOW:
if (esp_now_init() != ESP_OK) { Serial.println("Error initializing ESP-NOW"); return; }
Đăng ký một hàm gọi lại sẽ được gọi khi dữ liệu được nhận. Trong trường hợp này, chúng tôi đăng ký OnDataRecv () chức năng đã được tạo trước đó.
esp_now_register_recv_cb(OnDataRecv);
KIỂM TRA GIAO TIẾP ESP-NOW
Tải bản tóm tắt “thiết bị gửi” lên board Node Wifi32 của thiết bị gửi và tải bản tóm tắt “thiết bị nhận” lên board Node Wifi32 của thiết bị nhận.
Bây giờ, hãy mở hai cửa sổ Arduino IDE. Một cho người nhận và một cho người gửi. Mở Serial Monitor cho mỗi bảng. Nó phải là một cổng COM khác nhau cho mỗi bảng.
Đây là những gì bạn sẽ nhận được ở phía thiết bị gửi.
Và đây là những gì bạn sẽ nhận được ở phía thiết bị nhận. Lưu ý rằng biến Int thay đổi giữa mỗi lần đọc nhận được (vì chúng tôi đặt nó thành một số ngẫu nhiên ở phía người gửi).
Chúng tôi đã kiểm tra phạm vi giao tiếp giữa hai board và chúng tôi có thể có được kết nối ổn định lên đến 220 mét (khoảng 722 feet) trong môi trường mở. Trong thử nghiệm này, cả hai ăng-ten trên bo mạch của ESP32 đều hướng vào nhau.
TỔNG KẾT
Chúng tôi đã cố gắng giữ cho các ví dụ của chúng tôi đơn giản nhất có thể để bạn hiểu rõ hơn về cách mọi thứ hoạt động. Hiện có nhiều ESP-NOW chức năng liên quan có thể hữu ích trong các dự án của bạn. Đối với một ví dụ hoàn chỉnh, trong Arduino IDE của bạn, bạn có thể vào file > bài học > Node Wifi32 > ESP-Now và chọn một trong các bản phác thảo ví dụ.
Chúng tôi hy vọng bạn thấy hữu ích với phần giới thiệu này về ESP-NOW. Bằng những ví dụ đơn giản, chúng tôi đã chỉ cho bạn cách gửi dữ liệu dưới dạng cấu trúc aa từ Node Wifi32 này sang Node Wifi32 khác. Bạn có thể xây dựng ý tưởng mới khác, ví dụ như thay thế các giá trị cấu trúc bằng các giá trị đọc của cảm biến hoặc trạng thái GPIO chẳng hạn.
Ngoài ra, với ESP-NOW, mỗi bảng có thể là người gửi và người nhận cùng một lúc, và một bảng có thể gửi dữ liệu đến nhiều bảng và cũng nhận dữ liệu từ nhiều bảng. Những chủ đề này sẽ được đề cập trong các hướng dẫn trong tương lai, vì vậy bạn hãy theo dõi chúng tôi nhé. Bạn có thể để lại thông tin email phía dưới để nhận được những thông tin hướng dẫn mới nhất từ chúng tôi.
Nếu bạn có bất kỳ thắc mắc hoặc ý kiến đóng góp gì, bạn có thể để lại comment phía dưới hoặc liên lạc với chúng tôi qua Fanpage tại đây để được hỗ trợ nhé!