ESP32 Beginner Guide – P3: Pinout và GPIO
Hiểu pinout ESP32, chọn GPIO đúng cho input và output, dùng pull-up, đấu LED với nút nhấn và tránh chân boot, flash, PSRAM hoặc tín hiệu 5 V.
Chia sẻ

Sau khi cài Arduino IDE và nạp code đầu tiên ở P2, bước tiếp theo thường là cắm LED, nút nhấn hoặc cảm biến. Đây cũng là lúc nhiều board không boot, LED không sáng hoặc GPIO hỏng vì ta nhìn nhầm pinout.
Mục tiêu của P3 không phải học thuộc hàng chục số chân. Mình muốn bạn biết cách đọc một sơ đồ pin, chọn GPIO ít rủi ro và hiểu vì sao cùng một đoạn code lại không thể dùng nguyên số chân trên mọi board ESP32.
Pinout của board quan trọng hơn pinout của chip

Luôn bắt đầu từ pinout và schematic đúng tên board, module, revision thay vì một hình ESP32 chung.
Một pinout tốt phải khớp đủ ba thông tin: tên board, module và revision. ESP32-S3 là chip; ESP32-S3-WROOM-1-N8R8 là module; ESP32-S3-DevKitC-1 v1.1 mới là board có hai hàng header mà tay bạn đang cắm dây.
Trên sơ đồ, đừng nhầm các tên sau:
| Nhãn | Ý nghĩa thực tế |
|---|---|
GPIO4, IO4 hoặc 4 | Số GPIO dùng trong pinMode(4, ...) |
3V3, 5V, VBUS | Chân nguồn, không phải GPIO |
GND | Mass chung của mạch |
EN, RST | Reset/enable chip, không dùng như GPIO thông thường |
TX, RX, SDA, SCL, MOSI... | Chức năng peripheral mặc định hoặc gợi ý; cần xem nó ánh xạ tới GPIO nào |
Số thứ tự header J1-4 | Vị trí vật lý trên connector, không phải GPIO4 |
ESP32 có GPIO Matrix nên nhiều tín hiệu digital có thể chuyển sang nhiều chân khác nhau. Nhưng “có thể route” không có nghĩa là chân nào cũng tương đương: analog, USB, flash tốc độ cao và một số chức năng đặc biệt vẫn có giới hạn phần cứng.
Bạn có thể mở ESP32 Pinout Diagram & Comparison Guide, chọn đúng development kit rồi click vào từng chân để xem chức năng và cảnh báo. Khi pinout từ shop mâu thuẫn với schematic của nhà sản xuất, mình tin schematic.
Năm nhóm chân cần nhận ra trước khi cắm dây
1. Chân nguồn
GPIO của ESP32 dùng logic 3,3 V. HIGH thường gần 3,3 V và LOW gần 0 V. Chân 5V hoặc VBUS có thể cấp nguồn theo thiết kế của board, nhưng điều đó không biến GPIO thành chân chịu tín hiệu 5 V.
Espressif công bố mức chịu điện áp GPIO tối đa 3,6 V. Nếu module 5 V trả tín hiệu về ESP32, hãy dùng chia áp hoặc level shifter phù hợp. Đừng thử trực tiếp chỉ vì cảm biến vẫn chạy ở lần đầu.
2. GPIO thông thường
Đây là nhóm phù hợp nhất cho LED, button và các bài thử đầu tiên. Trong Arduino, ta thường dùng:
pinMode(pin, OUTPUT);
digitalWrite(pin, HIGH);
pinMode(pin, INPUT_PULLUP);
int level = digitalRead(pin);
Một GPIO output là tín hiệu điều khiển, không phải nguồn cấp cho motor, relay, servo hay dải LED. Với tải lớn hoặc có cuộn dây, bạn cần transistor/MOSFET, diode bảo vệ và nguồn riêng phù hợp.
3. Strapping pin
Strapping pin được chip đọc vào lúc reset để chọn chế độ boot hoặc cấu hình phần cứng. Sau khi boot, nhiều chân trong nhóm này vẫn dùng được như GPIO, nhưng mạch ngoài không được kéo chúng về mức sai trong lúc khởi động.
Ví dụ, ESP32-C3 dùng GPIO2, GPIO8 và GPIO9 làm strapping pin; GPIO8 trên C3-DevKitM-1 còn điều khiển LED RGB. ESP32-S3 và ESP32-C3 có danh sách khác. Vì vậy, đừng copy một bảng “safe pins” của chip khác.
4. Chân đã bị phần cứng trên board sử dụng
Flash, PSRAM, USB, USB-to-UART, LED RGB, camera hoặc màn hình onboard có thể chiếm GPIO. Trên ESP32-DevKitC Classic, các chân D0, D1, D2, D3, CMD và CLK nối tới flash nên cần tránh. Trên một số ESP32-S3 dùng Octal flash/PSRAM, GPIO35–37 không còn dành cho ngoại vi bên ngoài.
5. Chân có giới hạn riêng
ESP32 Classic có GPIO34–39 chỉ input và không có pull-up/pull-down bằng phần mềm. Đây là đặc điểm của ESP32 đời đầu, không phải quy tắc chung cho C3 hoặc S3. Những nhãn ADC, touch, RTC hoặc USB cũng thay đổi theo từng họ chip.
Chọn hai chân cho bài thực hành
Bài này dùng một LED đỏ rời, điện trở 330 Ω và một nút nhấn. Chọn hằng số theo board:
| Board | LED_PIN | BUTTON_PIN | Ghi chú |
|---|---|---|---|
| ESP32-C3-DevKitM-1 | GPIO4 | GPIO5 | Tránh RGB GPIO8 và strapping GPIO2/8/9 |
| ESP32-S3-DevKitC-1 | GPIO4 | GPIO5 | Kiểm tra variant nếu sau này dùng GPIO35–37 |
| ESP32-DevKitC Classic WROOM | GPIO23 | GPIO22 | Tránh flash, UART0 và strapping pin cho bài đầu |
Đây là lựa chọn thuận tiện cho đúng các DevKit trong bảng, không phải lời hứa rằng GPIO đó luôn trống trên mọi board thương mại. Nếu board có màn hình, camera hoặc sensor onboard, hãy kiểm tra schematic trước.
GPIO output: đấu LED đúng cách

Rút nguồn trước khi đấu; LED cần điện trở hạn dòng và tải lớn cần mạch driver riêng.
Rút USB trước khi cắm dây:
- Nối GPIO đã chọn vào một đầu điện trở 330 Ω.
- Đầu còn lại của điện trở nối tới chân dài anode của LED.
- Chân ngắn cathode, phía cạnh phẳng của LED, nối với GND.
Điện trở có thể nằm trước hoặc sau LED, miễn là chúng nối tiếp trong cùng nhánh. Không cắm LED trực tiếp giữa GPIO và GND vì dòng không còn được giới hạn đúng cách.
Code Blink tối thiểu:
constexpr uint8_t LED_PIN = 4; // C3/S3; dùng 23 cho ESP32 Classic trong bảng
void setup() {
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
}
void loop() {
digitalWrite(LED_PIN, HIGH);
delay(500);
digitalWrite(LED_PIN, LOW);
delay(500);
}
Nếu LED không sáng, kiểm tra cực LED, hàng breadboard, GND chung và số GPIO trước khi tăng điện áp hay bỏ điện trở.
GPIO input: tránh chân floating bằng pull-up

Sau khi đấu nút giữa GPIO và GND, INPUT_PULLUP cho giá trị HIGH khi thả và LOW khi nhấn.
Một input để hở có trở kháng cao nên có thể đổi ngẫu nhiên giữa HIGH và LOW khi tay hoặc dây dẫn tới gần. INPUT_PULLUP bật điện trở kéo lên bên trong chip để tạo trạng thái mặc định ổn định.
Cách đấu nút đơn giản:
- Một phía của nút nối
BUTTON_PIN. - Phía đối diện nối GND.
- Không cần điện trở ngoài cho bài thử này vì dùng
INPUT_PULLUP.
Kết quả sẽ đảo ngược so với trực giác: thả nút = HIGH, nhấn nút = LOW. Đoạn code sau làm LED sáng khi giữ nút:
constexpr uint8_t LED_PIN = 4; // C3/S3
constexpr uint8_t BUTTON_PIN = 5; // C3/S3
bool lastPressed = false;
void setup() {
Serial.begin(115200);
pinMode(LED_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP);
}
void loop() {
const bool pressed = digitalRead(BUTTON_PIN) == LOW;
digitalWrite(LED_PIN, pressed ? HIGH : LOW);
if (pressed != lastPressed) {
Serial.println(pressed ? "Pressed" : "Released");
lastPressed = pressed;
}
delay(20); // debounce đơn giản cho bài thử
}
Nếu dùng ESP32 Classic trong bảng, đổi hai hằng số thành 23 và 22. Khi dự án cần bắt xung nhanh hoặc không muốn polling, ESP32 hỗ trợ interrupt với attachInterrupt(), nhưng ISR phải ngắn và không phải cách chữa một nút cơ bị dội.
Đo trước khi tin vào màu dây

Chọn đúng cổng và thang DC trước khi đo; tín hiệu cao hơn 3,6 V cần chia áp hoặc chuyển mức.
Màu dây Dupont không đảm bảo chức năng. Trước khi nối module lạ, mình thường làm bốn việc:
- Đo điện áp giữa VCC và GND của module.
- Kiểm tra tín hiệu output của module có lên 5 V không.
- Xác nhận ESP32 và module có GND chung.
- Tắt nguồn trước khi chuyển dây sang pin khác.
Đừng đo điện trở hoặc continuity trên một mạch đang được cấp nguồn. Khi đo điện áp, que đen cắm COM, que đỏ cắm cổng đo voltage và đồng hồ đặt đúng thang DC. Những chi tiết nhỏ này đáng tin hơn việc đoán theo màu dây hoặc ảnh listing.
Quy trình chọn GPIO mình dùng cho mỗi dự án
- Ghi chính xác chip, module, board và revision.
- Mở pinout cùng schematic đúng phiên bản.
- Gạch bỏ chân nguồn, reset, flash/PSRAM và chân không được đưa ra header.
- Đánh dấu strapping, USB, UART log và phần cứng onboard.
- Chọn GPIO thông thường còn trống, rồi ghi số đó thành hằng số có tên trong code.
- Cắm mạch khi đã tắt nguồn, kiểm tra continuity nếu cần và cấp nguồn lại.
- Test từng input/output riêng trước khi chạy cả cảm biến hoặc motor.
Cách này chậm hơn vài phút lúc đầu nhưng tiết kiệm hàng giờ debug. Quan trọng hơn, code của bạn sẽ có chủ đích: nhìn STATUS_LED_PIN dễ hiểu hơn một số 4 xuất hiện rải rác.
Checklist trước khi chuyển sang P4
- Bạn phân biệt được GPIO number với số thứ tự chân header.
- Bạn không đưa tín hiệu 5 V trực tiếp vào GPIO 3,3 V.
- LED có điện trở hạn dòng; motor và relay có driver riêng.
- Input không bị floating vì đã dùng pull-up, pull-down hoặc điện trở ngoài phù hợp.
- Bạn đã kiểm tra strapping pin, flash/PSRAM, USB và phần cứng onboard.
- Số GPIO được đặt thành hằng số có tên và khớp với schematic của board.
Ở P4, mình sẽ dùng nền tảng này để nối và đọc cảm biến thật: digital, analog và I2C, đồng thời xử lý những trường hợp cảm biến có nguồn hoặc mức logic khác ESP32.
Tham khảo
Chia sẻ
Tiếp tục khám phá
Đọc tiếp
Bài viết liên quan
ESP32 Beginner Guide – P2: Cài đặt và nạp code đầu tiên
Cài Arduino IDE, thêm Arduino-ESP32, chọn đúng board và Port, nạp sketch đầu tiên rồi xử lý lỗi Failed to connect trên ESP32, ESP32-C3 và ESP32-S3.
ESP32 IoT Project Roadmap: Lộ trình từ LED đến sản phẩm
Roadmap tương tác giúp bạn học ESP32 qua project: từ LED và nút nhấn, sensor kết nối cloud, TinyML tại edge đến OTA và bảo mật cho thiết bị thật.
18 lỗi ESP32 thường gặp – Phần 2: Các lỗi nghiêm trọng
Cách mình đọc backtrace và xử lý crash, watchdog, heap, stack, FreeRTOS, Wi-Fi, ADC, deep sleep và OTA trên ESP32 theo một checklist runtime dễ áp dụng.