GPIO là gì? Chân đa năng quan trọng nhất trên mọi vi điều khiển
Atlasbot · 20/8/2026 · 10 phút đọc
Mở bất kỳ sơ đồ chân (pinout) của STM32 hay ESP32 nào, bạn sẽ thấy phần lớn các chân đều được gọi là GPIO. Đây là loại chân cơ bản và được dùng nhiều nhất trong lập trình nhúng — hiểu đúng cách nó hoạt động là bước đầu tiên trước khi đấu bất kỳ linh kiện nào.
Hai chế độ cơ bản: INPUT và OUTPUT
GPIO (General Purpose Input/Output) là chân đa năng trên vi điều khiển, có thể lập trình để hoạt động theo 1 trong 2 chế độ:
- INPUT (đầu vào): MCU đọc trạng thái điện áp trên chân — dùng để nhận tín hiệu từ nút nhấn, công tắc, cảm biến số...
- OUTPUT (đầu ra): MCU chủ động đặt chân ở mức HIGH hoặc LOW — dùng để điều khiển LED, relay, hoặc gửi tín hiệu tới linh kiện khác.
Điểm quan trọng: cùng một chân vật lý, bạn có thể cấu hình là INPUT hoặc OUTPUT tuỳ nhu cầu, thay đổi được ngay trong code — đó là lý do gọi là "đa năng" (general purpose), khác với các chân chuyên dụng cố định chức năng.
Tóm lại: GPIO là 1 chân, nhiều vai trò — đọc (INPUT) hoặc ghi (OUTPUT) đều do code quyết định, không phải cố định sẵn trong phần cứng.
Chân GPIO thường "đa năng" hơn cả INPUT/OUTPUT số
Trên hầu hết vi điều khiển hiện đại, một chân được đánh dấu GPIO thực chất có thể chuyển sang nhiều chức năng thay thế (alternate function) khác ngoài INPUT/OUTPUT số thông thường — được chọn qua cấu hình phần mềm (thường gọi là pin multiplexing/mux):
- Đọc analog qua ADC (xem bài Digital vs Analog).
- Xuất PWM để điều khiển tốc độ động cơ/độ sáng LED.
- Đóng vai trò chân giao tiếp UART/I2C/SPI với cảm biến/module khác.
Đây là lý do một chip chỉ có ~30-50 chân vật lý nhưng lại hỗ trợ hàng chục ngoại vi khác nhau — không phải mỗi ngoại vi có chân riêng, mà nhiều ngoại vi "chia nhau" cùng một tập chân GPIO, chọn chức năng nào tại một thời điểm qua cấu hình phần mềm.
Kiến thức kỹ thuật
Thông số
Số chân GPIO khả dụng và dòng tối đa mỗi chân trên các board phổ biến:
| Board/Chip | Số GPIO khả dụng | Dòng tối đa mỗi chân |
|---|---|---|
| Arduino Uno (ATmega328P) | ~20 chân | ~40mA |
| STM32F103C8T6 ("Blue Pill") | ~37 chân | ~20-25mA |
| ESP32 | ~34 chân (một số chỉ input) | ~40mA |
Register / Bit / Byte
Hàm pinMode()/digitalWrite() mà Arduino cung cấp thực chất chỉ là lớp bao (wrapper) cho việc set/clear bit trong các thanh ghi phần cứng thật. Trên STM32, 3 thanh ghi chính điều khiển GPIO của mỗi port:
GPIOx_MODER— thanh ghi chế độ, dùng 2 bit cho mỗi chân:00= input,01= output,10= chức năng thay thế (alternate function),11= analog.GPIOx_ODR(Output Data Register) — mỗi bit tương ứng 1 chân, set bit = xuất HIGH, clear bit = xuất LOW.GPIOx_IDR(Input Data Register) — đọc mức điện áp hiện tại trên từng chân, đã nhắc ở bài Bit/Byte.
VD: đặt chân PA5 (LED trên board Nucleo) làm OUTPUT
GPIOA_MODER bit 10-11 (ứng với chân 5) = 01
→ GPIOA->MODER |= (0b01 << (5 * 2)); // set 2 bit ở vị trí chân 5
Ứng dụng thực tế
Trong mạch điều khiển robot, GPIO OUTPUT thường dùng để bật/tắt chân ENABLE của driver động cơ (L298N, TB6612) — MCU chỉ cần đưa 1 chân lên HIGH/LOW để cho phép hoặc ngắt hoàn toàn động cơ, tách biệt với tín hiệu PWM điều tốc. Ở chiều ngược lại, nhiều chân GPIO INPUT thường được dùng đồng thời để đọc các công tắc hành trình (limit switch) ở 2 đầu hành trình của cơ cấu nâng hạ — mỗi công tắc 1 chân riêng, đọc song song để biết chính xác cơ cấu đã chạm giới hạn nào.
Ví dụ thực tế: đọc nút nhấn, điều khiển LED
// Arduino
void setup() {
pinMode(13, OUTPUT); // chân 13 làm OUTPUT, điều khiển LED
pinMode(2, INPUT_PULLUP); // chân 2 làm INPUT, có điện trở kéo lên sẵn (xem bài Pull-up/Pull-down)
}
void loop() {
int buttonState = digitalRead(2);
if (buttonState == LOW) { // nút nhấn kéo chân xuống LOW khi bấm
digitalWrite(13, HIGH); // bật LED
} else {
digitalWrite(13, LOW); // tắt LED
}
}
// STM32 HAL — cùng logic, viết ở tầng thấp hơn
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET); // OUTPUT: bật LED
GPIO_PinState state = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0); // INPUT: đọc nút nhấn
Hai đoạn code trên làm cùng một việc — Arduino trừu tượng hoá cao hơn (1 dòng digitalWrite), STM32 HAL chi tiết hơn (chỉ định rõ port GPIOA/GPIOB và số chân GPIO_PIN_x) — nhưng bản chất phần cứng bên dưới giống hệt nhau: đọc/ghi mức điện áp trên 1 chân.
Lỗi thường gặp
- Quên
pinMode()/cấu hình chân trước khi dùng — trên nhiều nền tảng, chân GPIO mặc định ở trạng thái không xác định hoặc INPUT — quên khai báoOUTPUTkhiếndigitalWrite()không có tác dụng như mong đợi. - Đọc chân INPUT chưa nối gì (floating) — chân INPUT không nối vào đâu (không HIGH, không LOW rõ ràng) sẽ đọc ra giá trị ngẫu nhiên do nhiễu điện từ môi trường xung quanh — luôn cần điện trở pull-up/pull-down khi đọc nút nhấn/công tắc (xem bài tiếp theo trong chuyên mục).
- Vượt quá dòng tối đa cho phép mỗi chân — mỗi chân GPIO chỉ chịu được dòng giới hạn (thường 20-40mA tuỳ chip, xem datasheet) — cắm trực tiếp LED công suất cao hoặc động cơ nhỏ vào chân OUTPUT có thể làm cháy chân, xem thêm bài Điện áp/Dòng điện/Công suất.
- Nhầm lẫn giữa output kiểu push-pull và open-drain — chế độ push-pull (mặc định phổ biến) chủ động kéo chân lên HIGH hoặc xuống LOW; chế độ open-drain chỉ chủ động kéo xuống LOW, còn HIGH phải nhờ điện trở pull-up ngoài — nhầm chế độ khiến mạch không hoạt động dù code đúng logic.
Kết luận
GPIO là nền tảng của gần như mọi tương tác phần cứng trong lập trình nhúng — hiểu rõ 2 chế độ INPUT/OUTPUT, cùng khả năng "đa năng" chuyển sang các chức năng thay thế khác, là điều kiện để đọc hiểu bất kỳ sơ đồ đấu nối nào. Bài tiếp theo trong chuyên mục đi sâu vào điện trở pull-up/pull-down — giải pháp cho vấn đề "chân floating" vừa nhắc ở trên.