Trong hệ thống Mạng cảm biến không dây IoTLabs, mỗi node cảm biến sẽ đọc dữ liệu (nhiệt độ, độ ẩm, …) và gửi về Gateway ESP32 qua sóng NRF24L01, sau đó Gateway đẩy lên MQTT / IoTLabs Cloud.
Bài này tập trung vào node Transmitter dùng ESP32-S3 Zero + NRF24L01, kèm LED tích hợp nháy báo trạng thái gửi thành công/thất bại.
1. Phần cứng sử dụng
- 1x ESP32-S3 Zero (Waveshare hoặc tương đương)
- 1x Module NRF24L01 (bản thường hoặc có anten ngoài)
- Tụ lọc nguồn 10–47µF (nên hàn sát VCC–GND của NRF)
- Dây nối (jumper)
Lưu ý: NRF24L01 chỉ chạy 3.3V, tuyệt đối không cấp 5V.
2. Sơ đồ nối chân ESP32-S3 Zero ↔ NRF24L01
Sử dụng SPI của ESP32-S3 với cấu hình như sau:
NRF24L01 → ESP32-S3 Zero
| NRF24L01 | ESP32-S3 Zero | Ghi chú |
|---|---|---|
| VCC | 3V3 | Nguồn 3.3V |
| GND | GND | GND chung |
| CE | GPIO1 | Chân điều khiển CE |
| CSN/CS | GPIO10 | SS (Chip Select SPI) |
| SCK | GPIO12 | Clock SPI |
| MOSI | GPIO11 | Data từ MCU → NRF |
| MISO | GPIO13 | Data từ NRF → MCU |
| IRQ | (để trống) | Chưa dùng trong ví dụ này |
Thêm 1 tụ 10–47µF giữa VCC–GND gần module NRF để tăng ổn định nguồn.
3. Cấu trúc gói tin SensorPacket
Để Gateway dễ xử lý, ta chuẩn hoá gói tin theo dạng struct:
struct SensorPacket {
uint32_t nodeId; // ID node cảm biến
float temperature; // Nhiệt độ (°C)
float humidity; // Độ ẩm (%RH)
uint32_t counter; // Bộ đếm gói tin gửi đi
};
Node Transmitter sẽ gán nodeId cố định (ví dụ 2), các giá trị temperature, humidity có thể là dữ liệu giả lập hoặc đọc từ cảm biến thật (DHT22, BME280, …) trong các bài tiếp theo.
4. Code hoàn chỉnh cho ESP32-S3 Zero Transmitter
Dưới đây là code .ino hoàn chỉnh:
- Gửi gói
SensorPacketmỗi 1 giây qua NRF24L01. - LED tích hợp nháy 1 lần nếu gửi thành công, 2 lần nếu thất bại.
#include <Arduino.h>
#include <SPI.h>
#include <RF24.h>
// Nếu core chưa define LED_BUILTIN thì tự gán
#ifndef LED_BUILTIN
#define LED_BUILTIN 15 // Đổi lại đúng chân LED trên board ESP32-S3 Zero của bạn nếu khác
#endif
// ----------------------
// Pin NRF24L01 với ESP32-S3 Zero
// ----------------------
#define NRF_CE_PIN 1
#define NRF_CSN_PIN 10 // SS
#define NRF_SCK_PIN 12 // SCK
#define NRF_MISO_PIN 13 // MISO
#define NRF_MOSI_PIN 11 // MOSI
// ----------------------
// Định nghĩa packet dữ liệu
// ----------------------
struct SensorPacket {
uint32_t nodeId; // ID node cảm biến
float temperature; // Nhiệt độ (°C)
float humidity; // Độ ẩm (%RH)
uint32_t counter; // Bộ đếm gói tin
};
// RF24(CE, CSN)
RF24 radio(NRF_CE_PIN, NRF_CSN_PIN);
// Địa chỉ RF – phải trùng với Gateway
const byte address[6] = "NODE1";
SensorPacket packet;
// Hàm blink LED tích hợp
void blinkBuiltinLed(uint8_t times, uint16_t onMs = 100, uint16_t offMs = 100) {
for (uint8_t i = 0; i < times; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(onMs);
digitalWrite(LED_BUILTIN, LOW);
delay(offMs);
}
}
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println();
Serial.println(F("IoTLabs NRF TX - ESP32-S3 Zero"));
// Khởi tạo LED tích hợp
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
// ESP32-S3: khởi tạo SPI với chân custom
SPI.begin(NRF_SCK_PIN, NRF_MISO_PIN, NRF_MOSI_PIN, NRF_CSN_PIN);
if (!radio.begin()) {
Serial.println(F("NRF24 init FAILED - kiểm tra dây & nguồn!"));
// Blink nhanh liên tục để báo lỗi
while (true) {
blinkBuiltinLed(1, 100, 100);
}
}
// Cấu hình RF
radio.setPALevel(RF24_PA_LOW); // LOW cho lab, sau có thể tăng nếu cần
radio.setDataRate(RF24_1MBPS);
radio.setChannel(108); // Tránh trùng WiFi 2.4GHz
radio.setRetries(5, 15); // (delay, count)
// Transmitter: mở pipe GỬI
radio.openWritingPipe(address);
radio.stopListening(); // TX mode
// Gán thông tin node
packet.nodeId = 2; // ID riêng cho node này
packet.counter = 0;
Serial.println(F("NRF24 TX ready, sending packets..."));
// Blink 3 cái chậm báo đã sẵn sàng
blinkBuiltinLed(3, 150, 150);
}
void loop() {
// Demo: sinh dữ liệu giả
// Sau này có thể thay bằng giá trị đọc từ cảm biến thực tế
packet.temperature = 25.0 + (random(-50, 51) / 10.0); // 20–30°C
packet.humidity = 60.0 + (random(-100, 101) / 10.0); // 50–70%
packet.counter++;
bool ok = radio.write(&packet, sizeof(packet));
// Blink 1 lần nếu gửi OK, 2 lần nếu FAILED
if (ok) {
blinkBuiltinLed(1, 50, 50);
} else {
blinkBuiltinLed(2, 80, 80);
}
Serial.print(F("Send #"));
Serial.print(packet.counter);
Serial.print(F(" | Node "));
Serial.print(packet.nodeId);
Serial.print(F(" | T="));
Serial.print(packet.temperature, 1);
Serial.print(F("C H="));
Serial.print(packet.humidity, 1);
Serial.print(F("% -> "));
Serial.println(ok ? F("OK") : F("FAILED"));
delay(1000); // gửi mỗi 1s
}
5. Cấu hình Arduino IDE
- Board: chọn đúng profile cho ESP32-S3 (ví dụ
ESP32S3 Dev Modulehoặc board Waveshare tương ứng). - Cổng COM: chọn đúng cổng thiết bị.
- Thư viện:
- Cài thư viện RF24 (tác giả TMRh20) từ Library Manager.
- Upload:
- Tuỳ board ESP32-S3 Zero, thường cần:
- Giữ nút BOOT, bấm RESET một lần rồi thả RESET.
- Giữ BOOT ~1–2 giây để vào chế độ download.
- Sau đó nhấn Upload trong Arduino IDE.
- Tuỳ board ESP32-S3 Zero, thường cần:
6. Kiểm tra với Gateway IoTLabs NRF
- Bật Gateway ESP32 DevKit + NRF24L01 (code nhận
SensorPackettừaddress = "NODE1"). - Bật ESP32-S3 Zero Transmitter với code ở trên.
- Mở Serial Monitor ở Gateway:
- Bạn sẽ thấy log dạng:
Recv from node 2 | Temp: 24.8 C | Hum: 63.2 % | Counter: 1
Recv from node 2 | Temp: 25.3 C | Hum: 61.7 % | Counter: 2
...
Trên node Transmitter:
- LED tích hợp nháy mỗi lần gửi gói tin:
- 1 nháy nhanh → gửi thành công.
- 2 nháy → gửi thất bại (cần kiểm tra lại nguồn/anten/khoảng cách).
7. Hướng mở rộng
Tiếp theo, bạn có thể:
- Thay phần dữ liệu giả bằng cảm biến thực tế (DHT22, BME280, MQ-2, …).
- Chuẩn hoá
nodeIdcho từng loại node (node khí gas, node nhiệt độ, node mực nước,…). - Kết nối Gateway với MQTT / IoTLabs Cloud, đẩy
SensorPacketlên server và hiển thị trên Dashboard.
Bài sau, chúng ta sẽ mở rộng phần Gateway ESP32 + NRF24L01 + MQTT để hoàn thiện luồng:
Nhiều node cảm biến NRF → ESP32 Gateway → MQTT / IoTLabs Cloud → Dashboard / Mobile App.


Leave a Reply