Mục Lục Bài Học
1. Giới Thiệu ESP32
ESP32 là vi điều khiển mạnh mẽ của Espressif Systems, tích hợp sẵn WiFi và Bluetooth, phù hợp cho các ứng dụng IoT.
Thông số kỹ thuật ESP32 DevKit V1
| Thông Số | Giá Trị |
|---|---|
| Vi xử lý | Dual-core Xtensa 32-bit LX6 |
| Tốc độ xung nhịp | Lên đến 240MHz |
| RAM | 520KB SRAM |
| Flash | 4MB (thường) |
| Chân GPIO | 34 chân (một số có chức năng đặc biệt) |
| ADC | 18 kênh 12-bit |
| DAC | 2 kênh 8-bit |
| PWM | 16 kênh |
| WiFi | 802.11 b/g/n (2.4GHz) |
| Bluetooth | Classic & BLE 4.2 |
| Điện áp | 3.3V (quan trọng!) |
⚠️ Cảnh báo: ESP32 hoạt động ở 3.3V, không phải 5V như Arduino Uno. Đừng cấp nguồn 5V trực tiếp vào các chân GPIO!
Sơ đồ chân ESP32 DevKit V1 (30 pin)
Chân cần lưu ý:
- Input only: GPIO 34, 35, 36, 39 - chỉ đọc, không ghi được
- Strapping pins: GPIO 0, 2, 5, 12, 15 - có chức năng đặc biệt khi boot
- ADC2: Không dùng được khi WiFi hoạt động
- Touch pins: GPIO 0, 2, 4, 12-15, 27, 32, 33 - cảm ứng điện dung
2. Cài Đặt ESP32 Trên Arduino IDE
Bước 1: Thêm Board Manager URL
- Mở Arduino IDE
- Vào File → Preferences
- Trong mục "Additional Board Manager URLs", thêm:
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
- Click OK
Bước 2: Cài đặt ESP32 Board
- Vào Tools → Board → Boards Manager
- Tìm "esp32" trong ô tìm kiếm
- Chọn "esp32 by Espressif Systems" và click Install
- Đợi cài đặt hoàn tất (có thể mất vài phút)
Bước 3: Cấu hình Board
- Kết nối ESP32 với máy tính qua USB
- Chọn Tools → Board → ESP32 Arduino → ESP32 Dev Module
- Chọn Tools → Port → COM... (cổng tương ứng)
- Cấu hình khác (để mặc định hoặc theo bảng dưới):
| Tham số | Giá trị khuyến nghị |
|---|---|
| Upload Speed | 921600 |
| CPU Frequency | 240MHz |
| Flash Frequency | 80MHz |
| Flash Mode | QIO |
| Flash Size | 4MB |
| Partition Scheme | Default 4MB |
Bước 4: Test Blink LED
ESP32 Blink Test
#define LED_PIN 2 // LED built-in trên ESP32 thường ở GPIO 2 void setup() { pinMode(LED_PIN, OUTPUT); } void loop() { digitalWrite(LED_PIN, HIGH); delay(1000); digitalWrite(LED_PIN, LOW); delay(1000); }
💡 Lỗi upload thường gặp: Nếu gặp lỗi "A fatal error occurred: Failed to connect", nhấn giữ nút BOOT trên ESP32 khi bắt đầu upload.
3. GPIO - Digital & Analog
Digital Output - LED đơn giản
Điều khiển nhiều LED
const int LED1 = 23; const int LED2 = 22; const int LED3 = 21; void setup() { pinMode(LED1, OUTPUT); pinMode(LED2, OUTPUT); pinMode(LED3, OUTPUT); } void loop() { // Hiệu ứng chạy dọc digitalWrite(LED1, HIGH); delay(200); digitalWrite(LED1, LOW); digitalWrite(LED2, HIGH); delay(200); digitalWrite(LED2, LOW); digitalWrite(LED3, HIGH); delay(200); digitalWrite(LED3, LOW); }
PWM - Điều chỉnh độ sáng (LEDC)
ESP32 có 16 kênh PWM độc lập (gọi là LEDC - LED Control).
PWM trên ESP32
const int LED_PIN = 23; const int FREQ = 5000; // Tần số PWM 5kHz const int LED_CHANNEL = 0; // Kênh PWM 0-15 const int RESOLUTION = 8; // Độ phân giải 8-bit (0-255) void setup() { // Cấu hình kênh PWM ledcSetup(LED_CHANNEL, FREQ, RESOLUTION); // Gắn chân với kênh ledcAttachPin(LED_PIN, LED_CHANNEL); } void loop() { // Tăng độ sáng for (int brightness = 0; brightness <= 255; brightness++) { ledcWrite(LED_CHANNEL, brightness); delay(10); } // Giảm độ sáng for (int brightness = 255; brightness >= 0; brightness--) { ledcWrite(LED_CHANNEL, brightness); delay(10); } }
Analog Input (ADC)
Đọc giá trị Analog
const int POT_PIN = 34; // GPIO 34 là ADC1_CH6 void setup() { Serial.begin(115200); // Cấu hình độ phân giải ADC (9-12 bit) analogReadResolution(12); // 0-4095 // Cấu hình attenuation (phạm vi điện áp) analogSetAttenuation(ADC_11db); // 0-3.3V } void loop() { int value = analogRead(POT_PIN); // Chuyển đổi sang điện áp float voltage = value * (3.3 / 4095.0); Serial.print("Giá trị: "); Serial.print(value); Serial.print(" - Điện áp: "); Serial.print(voltage); Serial.println("V"); delay(500); }
⚠️ Lưu ý ADC:
- ADC2 (GPIO 0, 2, 4, 12-15, 25-27) không hoạt động khi WiFi bật
- Chỉ dùng ADC1 (GPIO 32-39) cho độ tin cậy cao
4. Kết Nối WiFi
ESP32 có thể hoạt động ở 3 chế độ WiFi: Station (STA), Access Point (AP), hoặc cả hai (AP+STA).
Chế độ Station - Kết nối WiFi có sẵn
Kết nối WiFi cơ bản
#include <WiFi.h> const char* ssid = "TenWiFi"; // Thay bằng tên WiFi của bạn const char* password = "MatKhau"; // Thay bằng mật khẩu WiFi void setup() { Serial.begin(115200); Serial.println(); Serial.print("Đang kết nối WiFi"); // Bắt đầu kết nối WiFi.begin(ssid, password); // Chờ kết nối while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("\nĐã kết nối WiFi!"); Serial.print("Địa chỉ IP: "); Serial.println(WiFi.localIP()); Serial.print("Cường độ tín hiệu: "); Serial.print(WiFi.RSSI()); Serial.println(" dBm"); } void loop() { // Kiểm tra kết nối if (WiFi.status() == WL_CONNECTED) { Serial.println("WiFi vẫn kết nối"); } else { Serial.println("Mất kết nối WiFi!"); } delay(5000); }
Chế độ Access Point - Tạo WiFi riêng
ESP32 làm Access Point
#include <WiFi.h> const char* ap_ssid = "ESP32-AP"; const char* ap_password = "12345678"; // Tối thiểu 8 ký tự void setup() { Serial.begin(115200); // Tạo Access Point WiFi.softAP(ap_ssid, ap_password); // Lấy IP của AP (mặc định: 192.168.4.1) IPAddress IP = WiFi.softAPIP(); Serial.print("AP đã khởi động!"); Serial.print("Địa chỉ IP: "); Serial.println(IP); Serial.println("Kết nối WiFi: " + String(ap_ssid)); } void loop() { // Hiển thị số thiết bị đang kết nối Serial.print("Số thiết bị kết nối: "); Serial.println(WiFi.softAPgetStationNum()); delay(5000); }
WiFi Scanner - Quét mạng WiFi
Quét các WiFi xung quanh
#include <WiFi.h> void setup() { Serial.begin(115200); WiFi.mode(WIFI_STA); WiFi.disconnect(); delay(100); } void loop() { Serial.println("Bắt đầu quét WiFi..."); int n = WiFi.scanNetworks(); if (n == 0) { Serial.println("Không tìm thấy mạng WiFi nào"); } else { Serial.print(n); Serial.println(" mạng WiFi được tìm thấy:"); for (int i = 0; i < n; i++) { // In thông tin mỗi mạng Serial.print(i + 1); Serial.print(": "); Serial.print(WiFi.SSID(i)); Serial.print(" ("); Serial.print(WiFi.RSSI(i)); Serial.print(" dBm) "); Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? "Mở" : "Có bảo mật"); } } Serial.println(); delay(10000); // Quét lại sau 10 giây }
5. Web Server Cơ Bản
Tạo web server trên ESP32 để điều khiển thiết bị qua trình duyệt.
Web Server điều khiển LED
#include <WiFi.h> #include <WebServer.h> const char* ssid = "TenWiFi"; const char* password = "MatKhau"; const int LED_PIN = 2; bool ledState = false; WebServer server(80); // Server trên cổng 80 // Hàm xử lý trang chủ void handleRoot() { String html = "<!DOCTYPE html><html>"; html += "<head><meta charset='UTF-8'>"; html += "<title>ESP32 Web Server</title>"; html += "<style>body{font-family:Arial;text-align:center;margin-top:50px;}"; html += "button{padding:20px 40px;font-size:20px;margin:10px;cursor:pointer;}</style>"; html += "</head><body>"; html += "<h1>ESP32 Web Server</h1>"; html += "<p>Trạng thái LED: <b>" + String(ledState ? "BẬT" : "TẮT") + "</b></p>"; html += "<button onclick=\"location.href='/on'\">BẬT LED</button>"; html += "<button onclick=\"location.href='/off'\">TẮT LED</button>"; html += "</body></html>"; server.send(200, "text/html", html); } // Hàm bật LED void handleLedOn() { ledState = true; digitalWrite(LED_PIN, HIGH); server.sendHeader("Location", "/"); server.send(303); } // Hàm tắt LED void handleLedOff() { ledState = false; digitalWrite(LED_PIN, LOW); server.sendHeader("Location", "/"); server.send(303); } void setup() { Serial.begin(115200); pinMode(LED_PIN, OUTPUT); // Kết nối WiFi WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("\nĐã kết nối WiFi!"); Serial.print("IP: "); Serial.println(WiFi.localIP()); // Cấu hình các route server.on("/", handleRoot); server.on("/on", handleLedOn); server.on("/off", handleLedOff); // Khởi động server server.begin(); Serial.println("Web server đã khởi động!"); } void loop() { server.handleClient(); }
✅ Cách sử dụng: Sau khi upload code, mở Serial Monitor để xem địa chỉ IP. Truy cập IP đó trên trình duyệt (ví dụ: 192.168.1.100) để điều khiển LED.
6. HTTP Client - Gọi API
ESP32 có thể gửi request HTTP để lấy dữ liệu từ API hoặc gửi dữ liệu lên server.
GET Request - Lấy dữ liệu thời tiết
HTTP GET Request
#include <WiFi.h> #include <HTTPClient.h> const char* ssid = "TenWiFi"; const char* password = "MatKhau"; void setup() { Serial.begin(115200); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("\nĐã kết nối WiFi!"); } void loop() { if (WiFi.status() == WL_CONNECTED) { HTTPClient http; // URL API (ví dụ: JSONPlaceholder) http.begin("https://jsonplaceholder.typicode.com/posts/1"); // Gửi GET request int httpCode = http.GET(); if (httpCode > 0) { Serial.printf("HTTP Code: %d\n", httpCode); if (httpCode == HTTP_CODE_OK) { String payload = http.getString(); Serial.println("Response:"); Serial.println(payload); } } else { Serial.printf("Lỗi: %s\n", http.errorToString(httpCode).c_str()); } http.end(); } delay(10000); // Gọi API mỗi 10 giây }
POST Request - Gửi dữ liệu cảm biến
HTTP POST Request với JSON
#include <WiFi.h> #include <HTTPClient.h> #include <ArduinoJson.h> const char* ssid = "TenWiFi"; const char* password = "MatKhau"; const char* serverUrl = "http://your-server.com/api/data"; void setup() { Serial.begin(115200); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("\nĐã kết nối!"); } void loop() { if (WiFi.status() == WL_CONNECTED) { HTTPClient http; http.begin(serverUrl); http.addHeader("Content-Type", "application/json"); // Tạo JSON data StaticJsonDocument<200> doc; doc["device"] = "ESP32"; doc["temperature"] = 25.5; doc["humidity"] = 60.2; String jsonData; serializeJson(doc, jsonData); // Gửi POST request int httpCode = http.POST(jsonData); if (httpCode > 0) { Serial.printf("HTTP Code: %d\n", httpCode); String response = http.getString(); Serial.println(response); } else { Serial.println("Lỗi gửi dữ liệu"); } http.end(); } delay(30000); // Gửi mỗi 30 giây }
7. Bluetooth Classic - Serial
ESP32 hỗ trợ Bluetooth Classic (SPP - Serial Port Profile) để giao tiếp với điện thoại/máy tính.
Bluetooth Serial cơ bản
#include <BluetoothSerial.h> BluetoothSerial SerialBT; const int LED_PIN = 2; void setup() { Serial.begin(115200); pinMode(LED_PIN, OUTPUT); // Khởi động Bluetooth với tên "ESP32-BT" SerialBT.begin("ESP32-BT"); Serial.println("Bluetooth đã sẵn sàng!"); Serial.println("Kết nối từ điện thoại: ESP32-BT"); } void loop() { // Nhận dữ liệu từ Bluetooth if (SerialBT.available()) { char command = SerialBT.read(); Serial.print("Nhận lệnh: "); Serial.println(command); if (command == '1') { digitalWrite(LED_PIN, HIGH); SerialBT.println("LED đã BẬT"); } else if (command == '0') { digitalWrite(LED_PIN, LOW); SerialBT.println("LED đã TẮT"); } } // Gửi dữ liệu từ Serial lên Bluetooth if (Serial.available()) { SerialBT.write(Serial.read()); } }
💡 Cách test: Tải app "Serial Bluetooth Terminal" trên Android hoặc "LightBlue" trên iOS để kết nối và gửi/nhận dữ liệu.
Bài Tập Thực Hành
- Điều khiển đèn qua Web: Tạo web server điều khiển nhiều LED với slider điều chỉnh độ sáng.
- Trạm thời tiết IoT: Đọc DHT11 và gửi dữ liệu lên ThingSpeak/Blynk.
- Notification Telegram: Gửi thông báo lên Telegram khi có sự kiện (nút nhấn, cảm biến chuyển động).
- RC Car qua Bluetooth: Điều khiển robot xe qua Bluetooth bằng app điện thoại.