Bài viết 4 thuộc series STM32F103C8T6 tập trung theo hướng “học để làm được việc”. Với chủ đề GPIO trên STM32F103C8T6: điều khiển LED và đọc nút nhấn, bạn sẽ đi từ lý thuyết cốt lõi đến quy trình triển khai thực tế trong phòng lab. Nội dung được thiết kế để sinh viên, kỹ thuật viên bảo trì và người mới chuyển từ PLC sang Embedded đều có thể áp dụng ngay vào project mẫu.

GPIO là kỹ năng đầu tiên nhưng ảnh hưởng trực tiếp đến độ tin cậy của mọi project. Sai một bit cấu hình chân có thể làm toàn bộ hệ thống phản ứng sai hoặc nhiễu ngẫu nhiên.

Mạch LED và nút nhấn với STM32
Minh họa cho bài 4: GPIO trên STM32F103C8T6: điều khiển LED và đọc nút nhấn.

1. Mục tiêu bài học

Bài giúp bạn nắm nguyên lý điện và cấu hình phần mềm để điều khiển LED, đọc nút nhấn ổn định và chuẩn hóa thành module input/output dùng lại.

  • Hiểu đầy đủ các mode GPIO input/output của STM32F103C8T6.
  • Lập trình điều khiển LED và đọc nút nhấn không bị nhiễu.
  • So sánh push-pull và open-drain trong ứng dụng thực tế.
  • Xây dựng module GPIO dễ tái sử dụng cho project lớn.

Sau khi hoàn thành, bạn nên tự trả lời được ba câu hỏi: hệ thống cần đo/điều khiển đại lượng gì, vòng đời xử lý dữ liệu chạy theo chu kỳ nào, và cơ chế bảo vệ lỗi nào cần có để hệ thống ổn định khi chạy liên tục ngoài hiện trường.

2. Kiến thức nền tảng

STM32F103C8T6 dùng lõi ARM Cortex-M3, phù hợp để học đồng thời kiến trúc MCU và phương pháp lập trình thời gian thực. Khi học theo lộ trình chuẩn, bạn nên nắm đồng thời phần cứng (clock, GPIO, bus, nguồn), firmware (HAL/LL, ngắt, timer), và phương pháp test (scope, logic analyzer, UART log). Việc kết hợp đủ ba lớp kiến thức giúp quá trình debug nhanh hơn nhiều so với chỉ học code thuần.

  • Dòng điện qua LED và vai trò điện trở hạn dòng.
  • Pull-up/pull-down nội và ngoại khác nhau thế nào.
  • Tư duy active-high và active-low trên từng board.
  • Kiểm thử logic bằng oscilloscope hoặc logic analyzer.

Trong quá trình thực hành, bạn nên duy trì checklist kiểm thử ở từng vòng: xác nhận wiring, xác nhận xung clock, xác nhận trạng thái ngoại vi, sau đó mới kiểm tra thuật toán. Cách làm này giảm đáng kể lỗi dây chuyền và giúp nhóm dự án phối hợp hiệu quả giữa phần cứng và phần mềm.

3. Phân tích kỹ thuật

Cấu hình output an toàn cho LED và relay

Output push-pull phù hợp điều khiển LED trực tiếp, còn open-drain phù hợp bus cần kéo mức chung hoặc điều khiển transistor ngoài. Chọn sai mode có thể gây xung đột mức logic và nóng chân MCU.

  • Đặt tốc độ GPIO vừa đủ, không cần cao cho tín hiệu chậm.
  • Không cấp tải vượt quá khả năng dòng của chân MCU.
  • Khi điều khiển relay cần thêm transistor và diode dập xung.

Đọc nút nhấn ổn định và chống dội

Nút nhấn cơ khí tạo nhiều cạnh giả trong vài mili giây. Nếu không debounce, hệ thống sẽ nhận nhiều lần nhấn dù người dùng chỉ bấm một lần. Debounce có thể xử lý bằng timer mềm hoặc bộ lọc trạng thái.

  • Dùng pull-up nội để giảm linh kiện ngoài cho bài học cơ bản.
  • Lấy mẫu trạng thái nút theo chu kỳ cố định 5-10 ms.
  • Xác nhận trạng thái ổn định N lần trước khi công nhận sự kiện.

Thiết kế module GPIO theo hướng mở rộng

Thay vì viết trực tiếp trong main, nên gom chức năng LED/button vào module riêng với API rõ ràng. Cách này giúp tái sử dụng cho nhiều project và dễ chuyển sang RTOS hoặc kiến trúc event-driven.

  • Tạo enum trạng thái nút: idle, pressed, held.
  • Tách phần đọc thô và phần lọc thành hai hàm.
  • Giữ mapping pin trong file cấu hình tập trung.

Từ góc nhìn hệ thống, chủ đề này không chỉ là “chạy được chức năng”, mà còn là bài toán tối ưu độ tin cậy, độ trễ xử lý, khả năng mở rộng khi thêm cảm biến hoặc thêm kênh truyền thông. Nếu ngay từ đầu bạn chuẩn hóa cấu trúc code theo module driver/app/service thì giai đoạn mở rộng về sau sẽ nhẹ hơn rất nhiều.

4. Các bước thực hiện

Ưu tiên kiểm tra điện áp thực bằng đồng hồ trước khi kết luận lỗi firmware; rất nhiều lỗi GPIO xuất phát từ wiring.

  1. Kết nối LED qua điện trở 220Ω và xác nhận cực anode/cathode đúng.
  2. Kết nối nút nhấn về GPIO input với pull-up nội.
  3. Cấu hình GPIO output cho LED và input cho button trong CubeMX.
  4. Viết hàm debounce theo chu kỳ timer 10 ms.
  5. Tạo logic nhấn nút đổi trạng thái LED và ghi log qua UART.
  6. Stress-test 500 lần nhấn để xác nhận không mất sự kiện.

Ở mỗi bước, bạn nên lưu log kỹ thuật (ảnh wiring, ảnh cấu hình CubeMX, thông số timer/UART/ADC, snapshot kết quả đo). Bộ log này giúp giảng viên hoặc trưởng nhóm đánh giá tiến độ nhanh và giảm thời gian trao đổi khi cần hỗ trợ từ xa.

5. Ví dụ đọc nút nhấn có debounce cơ bản

Code dưới đây là mẫu rút gọn theo HAL Library, tập trung phần cốt lõi để bạn nhìn rõ luồng xử lý. Khi đưa vào dự án thực, hãy tách code thành các module rõ ràng, thêm kiểm tra lỗi trả về và timeout cho mọi giao tiếp ngoại vi.

static uint8_t btn_state = 1, btn_last = 1, stable_cnt = 0;

void Button_Task_10ms(void)
{
    uint8_t raw = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0);
    if (raw == btn_last) {
        if (stable_cnt < 5) stable_cnt++;
    } else {
        stable_cnt = 0;
    }
    btn_last = raw;

    if (stable_cnt == 5 && raw != btn_state) {
        btn_state = raw;
        if (btn_state == GPIO_PIN_RESET) {
            HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
        }
    }
}

Nguyên tắc quan trọng: giữ hàm ngắt ngắn gọn, xử lý nặng chuyển về vòng lặp chính hoặc task nền; dùng biến trạng thái rõ ràng để tránh race condition; thêm timeout cho mọi thao tác có thể block. Đây là nền tảng để firmware ổn định khi chạy lâu dài.

6. Lỗi thường gặp

Phần lớn lỗi trong STM32F103C8T6 đến từ cấu hình chưa đồng bộ giữa clock, ngoại vi và wiring thực tế. Nếu bạn xử lý theo thứ tự “đọc triệu chứng -> khoanh vùng lớp lỗi -> test độc lập từng khối”, thời gian debug sẽ giảm rất rõ.

  • Quên điện trở hạn dòng LED làm LED quá sáng hoặc cháy.
  • Đọc button trực tiếp không debounce gây đổi trạng thái nhiều lần.
  • Nhầm active-low với active-high khi test LED trên PC13.
  • Cấu hình sai pull-up/pull-down khiến input trôi mức.
  • Dùng delay dài trong main làm mất sự kiện nút nhấn nhanh.

Luôn tách lớp đọc nút thành hàm riêng có debounce để tránh lặp logic khắp chương trình.

7. Bài tập thực hành

Để chuyển từ mức “hiểu lý thuyết” sang “làm chủ kỹ năng”, bạn nên làm các bài tập sau theo đúng thứ tự từ dễ đến khó, sau mỗi bài đều ghi lại tiêu chí đạt/chưa đạt và thông số đo thực tế.

  1. Viết module button hỗ trợ nhấn ngắn, nhấn dài và nhấn kép.
  2. Tạo hiệu ứng LED theo state machine 3 chế độ.
  3. Dùng EXTI kết hợp debounce mềm để so sánh với polling.
  4. Đo và so sánh độ ổn định khi dùng pull-up nội và điện trở ngoài.

Khuyến nghị chấm bài theo rubric: đúng chức năng (40%), độ ổn định 30 phút chạy liên tục (30%), chất lượng cấu trúc code (20%), tài liệu kỹ thuật và báo cáo đo kiểm (10%).

Tài liệu tham khảo

  • STMicroelectronics, STM32F103x8/B Datasheet.
  • STMicroelectronics, RM0008 Reference Manual: STM32F10xxx advanced ARM-based 32-bit MCUs.
  • STMicroelectronics, UM1850 STM32CubeMX user manual và tài liệu STM32Cube liên quan.
  • ARM, Cortex-M3 Technical Reference Manual.
  • STMicroelectronics Application Notes về GPIO, ADC, Timer, UART, I2C, SPI, DMA và Watchdog.