Hướng dẫn kết nối Wi-Fi trên ESP32: quét mạng, tự kết nối lại, IP tĩnh và phát Wi-Fi riêng
- 1. Hai chế độ Wi-Fi của ESP32
- 2. Linh kiện cần chuẩn bị
- 3. Chương trình 1: quét các mạng Wi-Fi xung quanh
- 4. Chương trình 2: kết nối, xem thông tin mạng và theo dõi rớt mạng
- 5. Giải thích các lệnh chính
- 6. Đặt địa chỉ IP tĩnh
- 7. Chương trình 3: ESP32 tự phát Wi-Fi
- 8. Một số mẹo khi làm dự án thật
- 9. Xử lý lỗi thường gặp
Hướng dẫn các thao tác Wi-Fi cần dùng nhất trên ESP32 với Arduino IDE: quét mạng, kết nối có thời gian chờ, xem IP và cường độ sóng, tự kết nối lại, đặt IP tĩnh, phát Wi-Fi riêng.
Hầu hết dự án IoT với ESP32 đều bắt đầu bằng việc kết nối Wi-Fi, và phần lớn lỗi khó hiểu của người mới cũng nằm ở bước này. Bài viết gom những thao tác Wi-Fi cần dùng nhất trên ESP32 với Arduino IDE: quét mạng, kết nối có thời gian chờ, xem địa chỉ IP và cường độ sóng, tự kết nối lại khi rớt mạng, đặt IP tĩnh và cho ESP32 tự phát một mạng Wi-Fi riêng.
1. Hai chế độ Wi-Fi của ESP32
- Chế độ trạm (Station,
WIFI_STA): ESP32 kết nối vào mạng Wi-Fi có sẵn và được router cấp một địa chỉ IP. Đây là chế độ dùng khi cần Internet. - Chế độ điểm phát (Access Point,
WIFI_AP): ESP32 tự phát một mạng Wi-Fi để điện thoại kết nối thẳng vào. Mạng này không có Internet, phù hợp để cấu hình thiết bị hoặc điều khiển tại chỗ. - Cả hai cùng lúc (
WIFI_AP_STA): vừa kết nối router vừa phát mạng riêng.
ESP32 chỉ làm việc với Wi-Fi băng tần 2,4 GHz. Nếu router phát chung một tên cho cả 2,4 GHz và 5 GHz thì ESP32 vẫn kết nối được vào phần 2,4 GHz.
2. Linh kiện cần chuẩn bị
- ESP32 DevKit V1 30 chân (hoặc bản dùng chip CH340) và cáp USB có truyền dữ liệu. Nơi sóng yếu có thể dùng bản ESP32 DevKit V1 dùng anten rời.
- Mạng Wi-Fi 2,4 GHz và một điện thoại để thử chế độ điểm phát.
- Máy tính đã cài Arduino IDE 2.x và gói esp32 by Espressif Systems (bài dùng phiên bản 3.3.10). Không cần cài thêm thư viện.
3. Chương trình 1: quét các mạng Wi-Fi xung quanh
Quét mạng là cách nhanh nhất để biết ESP32 có "nhìn thấy" mạng nhà bạn hay không và sóng mạnh đến đâu:
/*
PYWORLD.VN - ESP32 quét các mạng Wi-Fi xung quanh
Chỉ cần mạch ESP32
Không cần cài thêm thư viện
*/
#include <WiFi.h>
const char *tenBaoMat(wifi_auth_mode_t kieu) {
switch (kieu) {
case WIFI_AUTH_OPEN: return "Mo";
case WIFI_AUTH_WEP: return "WEP";
case WIFI_AUTH_WPA_PSK: return "WPA";
case WIFI_AUTH_WPA2_PSK: return "WPA2";
case WIFI_AUTH_WPA_WPA2_PSK: return "WPA/WPA2";
case WIFI_AUTH_WPA3_PSK: return "WPA3";
case WIFI_AUTH_WPA2_WPA3_PSK: return "WPA2/WPA3";
default: return "Khac";
}
}
void setup() {
Serial.begin(115200);
delay(500);
WiFi.mode(WIFI_STA); // Chế độ trạm: ESP32 đóng vai một thiết bị Wi-Fi
WiFi.disconnect();
}
void loop() {
Serial.println("Dang quet mang WiFi...");
int soMang = WiFi.scanNetworks(); // Mất vài giây
if (soMang <= 0) {
Serial.println("Khong thay mang nao.");
} else {
Serial.printf("Thay %d mang:\n", soMang);
Serial.println(" STT RSSI Kenh Bao mat Ten mang");
for (int i = 0; i < soMang; i++) {
Serial.printf(" %3d %4d %4d %-9s %s\n", i + 1, (int)WiFi.RSSI(i), (int)WiFi.channel(i),
tenBaoMat(WiFi.encryptionType(i)), WiFi.SSID(i).c_str());
}
}
WiFi.scanDelete(); // Giải phóng bộ nhớ chứa kết quả quét
Serial.println();
delay(10000);
}
Chọn board DOIT ESP32 DEVKIT V1, nạp chương trình rồi mở Serial Monitor ở 115200 baud:
Cột RSSI cho biết cường độ sóng mà ESP32 thu được từ từng mạng:
Nếu mạng của bạn không có trong danh sách, nguyên nhân thường gặp là router chỉ phát 5 GHz, mạng bị ẩn tên, hoặc mạch đặt quá xa.
4. Chương trình 2: kết nối, xem thông tin mạng và theo dõi rớt mạng
Sửa TEN_WIFI và MAT_KHAU_WIFI rồi nạp chương trình. So với cách chờ kết nối mãi mãi, chương trình này có thời gian chờ 20 giây và in lý do khi mất kết nối:
/*
PYWORLD.VN - ESP32 kết nối Wi-Fi: có thời gian chờ, in thông tin mạng, báo khi mất kết nối
Chỉ cần mạch ESP32 và mạng Wi-Fi 2,4 GHz
Không cần cài thêm thư viện
*/
#include <WiFi.h>
const char *WIFI_SSID = "TEN_WIFI";
const char *WIFI_PASS = "MAT_KHAU_WIFI";
const unsigned long THOI_GIAN_CHO_MS = 20000;
// Muốn dùng IP tĩnh: bỏ dấu // ở bốn dòng dưới và ở dòng WiFi.config() trong hàm ketNoiWiFi()
// IPAddress IP_TINH(192, 168, 1, 150);
// IPAddress CONG_MANG(192, 168, 1, 1);
// IPAddress MAT_NA(255, 255, 255, 0);
// IPAddress DNS_1(8, 8, 8, 8);
// Hàm này được gọi mỗi khi trạng thái Wi-Fi thay đổi
void khiCoSuKienWiFi(WiFiEvent_t suKien, WiFiEventInfo_t thongTin) {
switch (suKien) {
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
Serial.println("Su kien: da ket noi va co dia chi IP.");
break;
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
Serial.printf("Su kien: mat ket noi WiFi (ma ly do %d). ESP32 se tu ket noi lai.\n",
(int)thongTin.wifi_sta_disconnected.reason);
break;
default:
break;
}
}
bool ketNoiWiFi() {
Serial.printf("Dang ket noi WiFi %s", WIFI_SSID);
WiFi.mode(WIFI_STA);
WiFi.setHostname("esp32-pyworld"); // Tên thiết bị hiện trong danh sách của router
// WiFi.config(IP_TINH, CONG_MANG, MAT_NA, DNS_1);
WiFi.begin(WIFI_SSID, WIFI_PASS);
unsigned long batDau = millis();
while (WiFi.status() != WL_CONNECTED) {
if (millis() - batDau > THOI_GIAN_CHO_MS) {
Serial.println("\nQua thoi gian cho. Kiem tra ten va mat khau WiFi.");
return false;
}
delay(500);
Serial.print(".");
}
Serial.println();
return true;
}
void inThongTinMang() {
Serial.printf("Dia chi IP : %s\n", WiFi.localIP().toString().c_str());
Serial.printf("Cong mang : %s\n", WiFi.gatewayIP().toString().c_str());
Serial.printf("Dia chi MAC : %s\n", WiFi.macAddress().c_str());
Serial.printf("Kenh : %d\n", (int)WiFi.channel());
Serial.printf("Cuong do song: %d dBm\n", (int)WiFi.RSSI());
}
void setup() {
Serial.begin(115200);
delay(500);
WiFi.onEvent(khiCoSuKienWiFi);
if (ketNoiWiFi()) {
inThongTinMang();
}
}
void loop() {
// Cứ 10 giây in cường độ sóng một lần
static unsigned long lanTruoc = 0;
if (millis() - lanTruoc >= 10000) {
lanTruoc = millis();
if (WiFi.status() == WL_CONNECTED) {
Serial.printf("Cuong do song: %d dBm\n", (int)WiFi.RSSI());
} else {
Serial.println("Chua co ket noi WiFi.");
}
}
}
Thử tắt router vài giây rồi bật lại: Serial Monitor in dòng báo mất kết nối, sau đó ESP32 tự kết nối lại và in dòng báo đã có địa chỉ IP.
5. Giải thích các lệnh chính
WiFi.mode(WIFI_STA): chọn chế độ trạm.WiFi.setHostname("esp32-pyworld"): đặt tên thiết bị để dễ tìm trong danh sách của router. Phải gọi trướcWiFi.begin().WiFi.begin(tên mạng, mật khẩu): bắt đầu kết nối. Lệnh trả về ngay; chương trình kiểm traWiFi.status()cho đến khi bằngWL_CONNECTEDhoặc hết thời gian chờ.WiFi.localIP(),WiFi.gatewayIP(),WiFi.macAddress(),WiFi.RSSI(): địa chỉ IP của ESP32, địa chỉ của router, địa chỉ MAC và cường độ sóng hiện tại.WiFi.onEvent(khiCoSuKienWiFi): đăng ký một hàm được gọi mỗi khi trạng thái Wi-Fi thay đổi. Bài dùng hai sự kiện: đã có địa chỉ IP và mất kết nối.- Tự kết nối lại: ESP32 mặc định tự thử kết nối lại khi rớt mạng, không cần viết thêm lệnh. Chương trình chính chỉ cần kiểm tra
WiFi.status()trước khi gửi dữ liệu.
6. Đặt địa chỉ IP tĩnh
Mặc định router cấp cho ESP32 một địa chỉ IP có thể thay đổi sau mỗi lần khởi động. Khi ESP32 làm web server, nên giữ địa chỉ cố định để khỏi phải dò lại. Trong chương trình 2, bỏ dấu // ở bốn dòng khai báo và ở dòng WiFi.config():
IPAddress IP_TINH(192, 168, 1, 150);
IPAddress CONG_MANG(192, 168, 1, 1);
IPAddress MAT_NA(255, 255, 255, 0);
IPAddress DNS_1(8, 8, 8, 8);
WiFi.config(IP_TINH, CONG_MANG, MAT_NA, DNS_1); // Gọi trước WiFi.begin()
- Ba số đầu của địa chỉ phải trùng với mạng của bạn. Chạy chương trình 2 một lần ở chế độ thường để xem địa chỉ IP và cổng mạng router đang cấp.
- Chọn số cuối nằm ngoài dải router tự cấp, hoặc dùng chức năng giữ địa chỉ theo MAC (DHCP reservation) của router. Cách thứ hai an toàn hơn vì không lo trùng địa chỉ.
- Phải khai báo DNS thì ESP32 mới truy cập được tên miền như
pool.ntp.org.
7. Chương trình 3: ESP32 tự phát Wi-Fi
Ở nơi không có router, ESP32 có thể tự phát một mạng Wi-Fi để điện thoại kết nối trực tiếp:
/*
PYWORLD.VN - ESP32 tự phát Wi-Fi (chế độ Access Point) và trả về một trang web nhỏ
Kết nối điện thoại vào mạng ESP32-PYWORLD rồi mở trình duyệt tại http://192.168.4.1
Không cần cài thêm thư viện
*/
#include <WiFi.h>
#include <WebServer.h>
const char *AP_SSID = "ESP32-PYWORLD";
const char *AP_PASS = "doi-mat-khau"; // Tối thiểu 8 ký tự; hãy đổi thành mật khẩu của bạn
WebServer server(80);
void trangChu() {
String html = "<!DOCTYPE html><html lang=\"vi\"><head><meta charset=\"utf-8\">"
"<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">"
"<title>ESP32</title></head><body style=\"font-family:Arial;text-align:center\">"
"<h1>Xin chào từ ESP32</h1><p>Số thiết bị đang kết nối: ";
html += WiFi.softAPgetStationNum();
html += "</p></body></html>";
server.send(200, "text/html; charset=utf-8", html);
}
void setup() {
Serial.begin(115200);
delay(500);
WiFi.mode(WIFI_AP); // Chế độ điểm phát: ESP32 tự tạo một mạng Wi-Fi
if (!WiFi.softAP(AP_SSID, AP_PASS)) {
Serial.println("Khong phat duoc WiFi! Mat khau phai dai it nhat 8 ky tu.");
while (true) delay(1000);
}
Serial.printf("Dang phat WiFi %s\n", AP_SSID);
Serial.printf("Mo trinh duyet tai dia chi: http://%s\n", WiFi.softAPIP().toString().c_str());
server.on("/", trangChu);
server.begin();
}
void loop() {
server.handleClient(); // Xử lý yêu cầu từ trình duyệt
}
- Nạp chương trình, mở phần cài đặt Wi-Fi của điện thoại và kết nối vào mạng ESP32-PYWORLD bằng mật khẩu đã đặt trong chương trình.
- Điện thoại có thể báo mạng không có Internet: chọn vẫn giữ kết nối.
- Mở trình duyệt, vào địa chỉ
http://192.168.4.1. Trang hiện dòng chào và số thiết bị đang kết nối.
Địa chỉ mặc định của ESP32 ở chế độ điểm phát là 192.168.4.1. Mật khẩu phải dài ít nhất 8 ký tự; nếu ngắn hơn, lệnh WiFi.softAP() thất bại.
8. Một số mẹo khi làm dự án thật
- Không để chương trình treo ở bước kết nối: luôn có thời gian chờ như chương trình 2. Thiết bị cần chạy cả khi mất mạng thì bỏ qua phần mạng và thử lại sau.
- Giảm độ trễ: mặc định Wi-Fi có chế độ tiết kiệm điện làm phản hồi chậm vài chục mili giây. Với web server hoặc điều khiển cần nhanh, gọi
WiFi.setSleep(false)sau khi kết nối. - Nguồn: lúc phát sóng ESP32 có thể cần dòng đỉnh vài trăm mA. Cáp USB kém hoặc nguồn yếu làm mạch tự khởi động lại đúng lúc kết nối Wi-Fi.
- Anten: không đặt phần anten của module sát kim loại hay trong hộp kim loại kín.
- Chân analog: khi bật Wi-Fi, các chân thuộc nhóm ADC2 không đọc được analog; dùng GPIO32–39.
9. Xử lý lỗi thường gặp
- Báo "Qua thoi gian cho": sai tên hoặc mật khẩu (có phân biệt chữ hoa, chữ thường), router chỉ phát 5 GHz, hoặc sóng quá yếu. Chạy chương trình quét mạng để kiểm tra.
- Kết nối được nhưng không ra Internet khi dùng IP tĩnh: sai cổng mạng hoặc thiếu DNS trong
WiFi.config(). - Hai thiết bị cùng lúc chập chờn: trùng địa chỉ IP tĩnh. Đổi số cuối của một thiết bị.
- ESP32 khởi động lại liên tục khi bật Wi-Fi, Serial Monitor có chữ "Brownout": nguồn sụt áp. Đổi cáp USB, đổi cổng USB hoặc cấp nguồn ngoài ổn định.
- Rớt mạng thường xuyên: xem cường độ sóng; dưới khoảng −75 dBm nên dời mạch lại gần router hoặc dùng bản có anten rời.
- Không vào được 192.168.4.1: điện thoại đã tự chuyển sang mạng khác vì mạng của ESP32 không có Internet. Tắt dữ liệu di động và kết nối lại vào ESP32-PYWORLD.
- Không nạp được chương trình: dùng cáp USB có truyền dữ liệu, chọn đúng cổng COM và giữ nút BOOT khi IDE dừng ở dòng Connecting...
Xem thêm: ESP32 làm web server điều khiển relay qua Wi-Fi, bắt đầu với Wemos D1 R2 (ESP8266) trên Arduino IDE và nạp file .bin vào ESP32 bằng Flash Download Tool.
Xem thêm