Hướng dẫn sử dụng code thử nghiệm LAN/WiFi với mạch ZenoLAN0105

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 VKhuyên dùng 12 V hoặc 24 V, tối thiểu 500 mA
Cáp USB Type-CLoại có truyền dữ liệu, không chỉ sạc
Dây LAN RJ45Cắm vào router hoặc switch có cấp IP tự động (DHCP)
Mạng WiFi 2.4 GHzESP32 không hỗ trợ băng tần 5 GHz

Phần mềm

  1. Cài Arduino IDE 2.x.
  2. Vào File → Preferences, thêm vào ô Additional boards manager URLs: https://espressif.github.io/arduino-esp32/package_esp32_index.json
  3. Vào Tools → Board → Boards Manager, tìm esp32 và 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àm ETH.begin() cho W5500 qua SPI, code sẽ báo lỗi khi biên dịch.
  4. Vào Sketch → Include Library → Manage Libraries, tìm và cài PubSubClient của Nick O'Leary.
  5. 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.
  6. 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 địnhCần sửa?Ý nghĩa
WIFI_SSIDTEN_WIFI_CUA_BANCóTên mạng WiFi 2.4 GHz
WIFI_PASSMAT_KHAU_WIFICóMật khẩu WiFi
MQTT_TOPICzenopcb/zenolan0105/testNên sửaTopic 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_SERVERtest.mosquitto.orgTùy chọnBroker MQTT công cộng để thử nghiệm; đổi sang broker của bạn khi triển khai thật
MQTT_PORT1883Tùy chọnCổng MQTT không mã hóa
ETH_PHY_CS32KhôngChân Chip Select của W5500
ETH_PHY_RST33KhôngChân Reset của W5500
ETH_PHY_IRQ-1KhôngKhông dùng ngắt, ESP32 đọc W5500 theo chu kỳ
ETH_SPI_SCK / MISO / MOSISCK / MISO / MOSIKhôngChân SPI mặc định của ESP32: GPIO18 / 19 / 23
LED1 / LED2 / LED35 / 12 / 13Không3 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

  1. Cắm cáp USB Type-C vào mạch và máy tính.
  2. Trong Arduino IDE chọn Tools → Board → esp32 → ESP32 Dev Module.
  3. Chọn đúng cổng COM tại Tools → Port.
  4. Nhấn Upload và chờ dòng Hard resetting via RTS pin... hiện ra.
  5. Cấp nguồn 10–30 VDC và cắm dây LAN vào mạch.
  6. 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

LEDGPIOSáng khi
LED15Ethernet đã có IP
LED212WiFi đã có IP
LED313Đang kết nối với broker MQTT

Kiểm tra bằng MQTTX

  1. Tạo kết nối mới: Host test.mosquitto.org, Port 1883, để trống username và password.
  2. Nhấn New Subscription, nhập đúng MQTT_TOPIC trong code (ví dụ zenopcb/zenolan0105/test).
  3. Bạn sẽ thấy bản tin từ mạch về mỗi 3 giây.
  4. 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

  1. 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.
  2. 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 codeNhiệ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ượngNguyên nhân thường gặpCách xử lý
Lỗi biên dịch ở ETH.begin hoặc ETH_PHY_W5500Lõi ESP32 phiên bản 2.xNâng gói esp32 by Espressif lên 3.0.0 trở lên
Không thấy cổng COMCá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 độ baudChọn 115200 baud
Không có dòng [ETH] Da cam day LANDây LAN hỏng hoặc chưa cắm chặtThay dây, kiểm tra đèn link trên cổng RJ45
Có Da cam day LAN nhưng không nhận IPRouter không bật DHCPBật DHCP trên router, hoặc cấu hình IP tĩnh bằng ETH.config()
WiFi không kết nốiSai SSID/mật khẩu hoặc mạng 5 GHzKiểm tra lại thông tin, dùng mạng 2.4 GHz
[MQTT] ... that bai, ma loi: -2Không ra được Internet hoặc bị tường lửa chặn cổng 1883Kiểm tra Internet của router, mở cổng 1883
MQTTX không nhận bản tinSai topicTopic 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

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *