Bài này hướng dẫn nạp và chạy chương trình thử nghiệm LAN/WiFi trên Mạch ESP32 RS485 Modbus RTU TCP/IP Ethernet ZenoLAN0105: mạch kết nối MQTT qua cổng LAN, và tự chuyển sang WiFi khi rút dây mạng.
ZenoLAN0105 dùng vi điều khiển ESP32 (WiFi + Bluetooth) và chip Ethernet W5500 giao tiếp SPI. Mạch có 1 cổng RS485 cách ly, 1 cổng LAN RJ45, 1 cổng USB Type-C để nạp và cấu hình, nguồn cấp 10–30 VDC, vỏ ABS gắn ray DIN 35 mm.
Chương trình thử nghiệm giúp bạn kiểm tra nhanh ba việc trước khi phát triển ứng dụng riêng:
- Chip W5500 nhận IP từ router qua cổng LAN.
- ESP32 kết nối WiFi làm đường truyền dự phòng.
- Mạch gửi và nhận bản tin MQTT qua đường mạng đang hoạt động.
Chuẩn bị
Bạn cần mạch ZenoLAN0105, nguồn 12 hoặc 24 VDC, dây LAN nối vào router có DHCP và Internet, cùng Arduino IDE với lõi ESP32 phiên bản 3.x.
Phần cứng
| Thiết bị | Ghi chú |
|---|---|
| Mạch ZenoLAN0105 | Đã gắn anten WiFi (nếu có) |
| Nguồn DC 10–30 V | Khuyên dùng 12 V hoặc 24 V, tối thiểu 500 mA |
| Cáp USB Type-C | Loại có truyền dữ liệu, không chỉ sạc |
| Dây LAN RJ45 | Cắm vào router hoặc switch có cấp IP tự động (DHCP) |
| Mạng WiFi 2.4 GHz | ESP32 không hỗ trợ băng tần 5 GHz |
Phần mềm
- Cài Arduino IDE 2.x.
- Vào File → Preferences, thêm vào ô Additional boards manager URLs:
https://espressif.github.io/arduino-esp32/package_esp32_index.json - Vào Tools → Board → Boards Manager, tìm
esp32và cài gói esp32 by Espressif Systems phiên bản 3.0.0 trở lên. Phiên bản 2.x không hỗ trợ hàmETH.begin()cho W5500 qua SPI, code sẽ báo lỗi khi biên dịch. - Vào Sketch → Include Library → Manage Libraries, tìm và cài PubSubClient của Nick O'Leary.
- Nếu máy tính không nhận cổng COM khi cắm mạch, cài driver USB-UART tương ứng với chip trên mạch.
- Cài một phần mềm MQTT client để kiểm tra, ví dụ MQTTX (miễn phí, có bản Windows, macOS, Linux).
Cấu hình code
Trước khi nạp, bạn chỉ cần sửa 3 dòng ở đầu chương trình: tên WiFi, mật khẩu WiFi và topic MQTT. Các thông số chân W5500 đã khớp với phần cứng ZenoLAN0105, không cần thay đổi.
| Hằng số | Giá trị mặc định | Cần sửa? | Ý nghĩa |
|---|---|---|---|
WIFI_SSID | TEN_WIFI_CUA_BAN | Có | Tên mạng WiFi 2.4 GHz |
WIFI_PASS | MAT_KHAU_WIFI | Có | Mật khẩu WiFi |
MQTT_TOPIC | zenopcb/zenolan0105/test | Nên sửa | Topic gửi và nhận bản tin; đặt tên riêng để không trùng với người khác trên broker công cộng |
MQTT_SERVER | test.mosquitto.org | Tùy chọn | Broker MQTT công cộng để thử nghiệm; đổi sang broker của bạn khi triển khai thật |
MQTT_PORT | 1883 | Tùy chọn | Cổng MQTT không mã hóa |
ETH_PHY_CS | 32 | Không | Chân Chip Select của W5500 |
ETH_PHY_RST | 33 | Không | Chân Reset của W5500 |
ETH_PHY_IRQ | -1 | Không | Không dùng ngắt, ESP32 đọc W5500 theo chu kỳ |
ETH_SPI_SCK / MISO / MOSI | SCK / MISO / MOSI | Không | Chân SPI mặc định của ESP32: GPIO18 / 19 / 23 |
LED1 / LED2 / LED3 | 5 / 12 / 13 | Không | 3 LED trạng thái, sáng ở mức LOW |
Broker test.mosquitto.org là máy chủ công khai: ai biết topic đều đọc được bản tin. Chỉ dùng nó để thử nghiệm, không gửi dữ liệu thật của nhà máy lên đây.
Nạp code và kiểm tra hoạt động
Sau khi nạp, mở Serial Monitor ở tốc độ 115200: bạn sẽ thấy mạch nhận IP qua LAN, kết nối MQTT và gửi bản tin mỗi 3 giây.
Nạp code
- Cắm cáp USB Type-C vào mạch và máy tính.
- Trong Arduino IDE chọn Tools → Board → esp32 → ESP32 Dev Module.
- Chọn đúng cổng COM tại Tools → Port.
- Nhấn Upload và chờ dòng
Hard resetting via RTS pin...hiện ra. - Cấp nguồn 10–30 VDC và cắm dây LAN vào mạch.
- Mở Tools → Serial Monitor, chọn tốc độ 115200 baud.
Kết quả trên Serial Monitor
Khi hoạt động đúng, 3 LED nháy cùng lúc một lần khi khởi động, sau đó Serial Monitor hiện nội dung tương tự:
=== ZenoLAN0105 - Thu nghiem LAN/WiFi + MQTT ===
[WiFi] Dang ket noi: TEN_WIFI_CUA_BAN
[ETH] Da cam day LAN
[ETH] Nhan IP thanh cong
IP address : 192.168.1.50
Gateway : 192.168.1.1
Subnet mask: 255.255.255.0
DNS server : 192.168.1.1
MAC address: 08:3A:F2:xx:xx:xx
Link speed : 100 Mbps
[NET] Duong truyen chinh: Ethernet
[MQTT] Ket noi qua Ethernet... thanh cong
[MQTT] Da gui: Hello from ZenoLAN0105 via Ethernet -> 437Đèn LED trạng thái
| LED | GPIO | Sáng khi |
|---|---|---|
| LED1 | 5 | Ethernet đã có IP |
| LED2 | 12 | WiFi đã có IP |
| LED3 | 13 | Đang kết nối với broker MQTT |
Kiểm tra bằng MQTTX
- Tạo kết nối mới: Host
test.mosquitto.org, Port1883, để trống username và password. - Nhấn New Subscription, nhập đúng
MQTT_TOPICtrong code (ví dụzenopcb/zenolan0105/test). - Bạn sẽ thấy bản tin từ mạch về mỗi 3 giây.
- Gửi thử một bản tin bất kỳ vào cùng topic; Serial Monitor sẽ in ra nội dung vừa nhận.
Kiểm tra chuyển đổi LAN sang WiFi
- Rút dây LAN khỏi mạch: Serial Monitor báo mất Ethernet, LED1 tắt, MQTT kết nối lại qua WiFi, bản tin đổi thành
via WiFi. - Cắm lại dây LAN: mạch nhận IP mới, MQTT tự quay về Ethernet, bản tin đổi thành
via Ethernet.
#include <WiFi.h>
#include <SPI.h>
#include <ETH.h>
#include <PubSubClient.h>
// LED GPIO (mức LOW là bật)
#define LED1 5
#define LED2 12
#define LED3 13
// WiFi cấu hình
const char* WIFI_SSID = "iMTrongThan1";
const char* WIFI_PASS = "imaker12345";
// MQTT cấu hình
const char* MQTT_SERVER = "test.mosquitto.org";
const int MQTT_PORT = 1883;
WiFiClient wifiClient;
WiFiClient ethClient;
PubSubClient mqttClient(wifiClient); // Khởi tạo mặc định với WiFiClient
// Ethernet W5500 cấu hình
#define ETH_PHY_TYPE ETH_PHY_W5500
#define ETH_PHY_ADDR 1
#define ETH_PHY_CS 32
#define ETH_PHY_IRQ -1
#define ETH_PHY_RST 33
#define ETH_SPI_SCK SCK // ESP32-S3: GPIO12, ESP32: GPIO18
#define ETH_SPI_MISO MISO // ESP32-S3: GPIO13, ESP32: GPIO19
#define ETH_SPI_MOSI MOSI // ESP32-S3: GPIO11, ESP32: GPIO23
bool ethConnected = false;
volatile bool shouldSwitchToEthernet = false;
void WiFiEvent(WiFiEvent_t event) {
if (event == ARDUINO_EVENT_ETH_GOT_IP) {
ethConnected = true;
Serial.print("🟢 Ethernet IP: ");
Serial.println(ETH.localIP());
shouldSwitchToEthernet = true; // Cờ xử lý sau trong loop
}
else if (event == ARDUINO_EVENT_ETH_DISCONNECTED || event == ARDUINO_EVENT_ETH_LOST_IP) {
ethConnected = false;
Serial.println("🔴 Ethernet Disconnected. Switching to WiFi...");
mqttClient.setClient(wifiClient); // Đổi lại WiFiClient nếu Ethernet mất
}
}
void mqttCallback(char* topic, byte* payload, unsigned int length) {
Serial.print("📩 Topic: ");
Serial.println(topic);
Serial.print("📄 Message: ");
for (unsigned int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
}
void reconnectMQTT() {
while (!mqttClient.connected()) {
Serial.print("🔄 Kết nối MQTT...");
String clientId = "ZenoPCB-" + String(random(0xffff), HEX);
if (mqttClient.connect(clientId.c_str())) {
Serial.println("✅ Thành công!");
mqttClient.subscribe("esp32/trongthan210");
delay(1000);
} else {
Serial.print("❌ Thất bại, lỗi: ");
Serial.println(mqttClient.state());
delay(1000);
}
}
}
void setup() {
Serial.begin(115200);
WiFi.onEvent(WiFiEvent);
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
pinMode(LED3, OUTPUT);
// Nhấp nháy LED
delay(500);
digitalWrite(LED1, LOW);
digitalWrite(LED2, LOW);
digitalWrite(LED3, LOW);
delay(500);
digitalWrite(LED1, HIGH);
digitalWrite(LED2, HIGH);
digitalWrite(LED3, HIGH);
delay(500);
digitalWrite(LED1, LOW);
digitalWrite(LED2, LOW);
digitalWrite(LED3, LOW);
// // Kết nối WiFi
// WiFi.begin(WIFI_SSID, WIFI_PASS);
// if (WiFi.status() != WL_CONNECTED) {
// Serial.print(".");
// delay(500);
// }
Serial.print("\n📡 WiFi Connected. IP: ");
Serial.println(WiFi.localIP());
mqttClient.setServer(MQTT_SERVER, MQTT_PORT);
mqttClient.setCallback(mqttCallback);
// Khởi động Ethernet
SPI.begin(ETH_SPI_SCK, ETH_SPI_MISO, ETH_SPI_MOSI, ETH_PHY_CS);
ETH.begin(ETH_PHY_TYPE, ETH_PHY_ADDR, ETH_PHY_CS, ETH_PHY_IRQ, ETH_PHY_RST, SPI);
}
void loop() {
Serial.println("Ethernet connected!");
Serial.print("IP address: ");
Serial.println(ETH.localIP());
Serial.print("Link speed: ");
Serial.print(ETH.linkSpeed());
Serial.println(" Mbps");
Serial.print("MAC address: ");
Serial.println(ETH.macAddress());
Serial.print("Gateway: ");
Serial.println(ETH.gatewayIP());
Serial.print("Subnet Mask: ");
Serial.println(ETH.subnetMask());
Serial.print("DNS Server: ");
Serial.println(ETH.dnsIP());
if (shouldSwitchToEthernet) {
shouldSwitchToEthernet = false;
mqttClient.setClient(ethClient); // Đổi sang Ethernet an toàn trong loop
mqttClient.setServer(MQTT_SERVER, MQTT_PORT);
reconnectMQTT(); // Kết nối lại MQTT
}
if (!mqttClient.connected()) {
reconnectMQTT();
} else {
static unsigned long lastSend = 0;
if (millis() - lastSend > 3000) {
String message = "Hello from ESP32! Using " + String(ethConnected ? "Ethernet" : "WiFi") + " -> " + String(random(100, 900));
mqttClient.publish("esp32/trongthan210", message.c_str());
Serial.println("📤 Đã gửi: " + message);
lastSend = millis();
}
}
mqttClient.loop();
}
Giải thích các phần chính
| Phần code | Nhiệm vụ |
|---|---|
onNetworkEvent() | Nhận sự kiện từ WiFi và Ethernet (cắm/rút LAN, có/mất IP) và chỉ đặt cờ, việc xử lý nặng để dành cho loop() |
SPI.begin() + ETH.begin() | Khởi động W5500 qua SPI với chân CS = 32, RST = 33 |
ETH.setDefault() / WiFi.STA.setDefault() | Chọn giao diện mạng mặc định, để gói tin MQTT đi đúng đường LAN hoặc WiFi khi cả hai cùng có IP |
mqttClient.setClient() | Gắn thư viện PubSubClient vào client của đường truyền đang dùng |
tryConnectMQTT() | Thử kết nối broker mỗi 3 giây, không dùng vòng lặp while nên chương trình không bị treo khi mất mạng |
printEthInfo() | In IP, gateway, subnet, DNS, MAC và tốc độ link một lần khi LAN có IP |
mqttCallback() | In ra Serial mọi bản tin nhận được trên MQTT_TOPIC |
Khối publish trong loop() | Gửi bản tin kèm tên đường truyền đang dùng mỗi 3 giây |
Để phát triển tiếp, bạn thay nội dung bản tin trong khối publish bằng dữ liệu thật, ví dụ giá trị thanh ghi Modbus RTU đọc từ cổng RS485 của mạch.
Xử lý sự cố thường gặp
Phần lớn lỗi đến từ phiên bản lõi ESP32, dây LAN hoặc router không cấp IP; bảng dưới giúp bạn khoanh vùng nhanh.
| Hiện tượng | Nguyên nhân thường gặp | Cách xử lý |
|---|---|---|
Lỗi biên dịch ở ETH.begin hoặc ETH_PHY_W5500 | Lõi ESP32 phiên bản 2.x | Nâng gói esp32 by Espressif lên 3.0.0 trở lên |
| Không thấy cổng COM | Cáp chỉ sạc hoặc thiếu driver | Đổi cáp Type-C có dữ liệu, cài driver USB-UART |
| Serial Monitor hiện ký tự lạ | Sai tốc độ baud | Chọn 115200 baud |
Không có dòng [ETH] Da cam day LAN | Dây LAN hỏng hoặc chưa cắm chặt | Thay dây, kiểm tra đèn link trên cổng RJ45 |
Có Da cam day LAN nhưng không nhận IP | Router không bật DHCP | Bật DHCP trên router, hoặc cấu hình IP tĩnh bằng ETH.config() |
| WiFi không kết nối | Sai SSID/mật khẩu hoặc mạng 5 GHz | Kiểm tra lại thông tin, dùng mạng 2.4 GHz |
[MQTT] ... that bai, ma loi: -2 | Không ra được Internet hoặc bị tường lửa chặn cổng 1883 | Kiểm tra Internet của router, mở cổng 1883 |
| MQTTX không nhận bản tin | Sai topic | Topic trong MQTTX phải trùng chính xác MQTT_TOPIC trong code |
Mã lỗi mqttClient.state() hay gặp: -4 hết thời gian chờ, -2 kết nối TCP thất bại, 4 sai tài khoản, 5 không được phép kết nối.
Liên hệ hỗ trợ
CÔNG TY TNHH CÔNG NGHỆ ĐIỆN TỬ ZENOPCB
- Địa chỉ: 350/2 đường Chiến Lược, Phường Bình Trị Đông A, Quận Bình Tân, TP. Hồ Chí Minh
- Hotline: 097.111.3732
- Website: zenopcb.vn
- Sản phẩm: Mạch ESP32 RS485 Modbus RTU TCP/IP Ethernet ZenoLAN0105

