Bài hướng dẫn này sẽ hướng dẫn bạn cách thiết lập và lập trình vi điều khiển STM32 để điều khiển một đèn LED thông qua một nút nhấn. Chúng ta sẽ sử dụng công cụ STM32CubeMX để cấu hình phần cứng và thư viện HAL để lập trình.
Mục tiêu:
- Cấu hình một chân GPIO làm đầu vào cho nút nhấn.
- Cấu hình một chân GPIO làm đầu ra cho đèn LED.
- Viết chương trình đọc trạng thái nút nhấn và điều khiển LED tương ứng.
Phần cứng cần có:
- Kit phát triển STM32 (ví dụ: STM32F103C8T6 "Blue Pill", STM32F401 "Black Pill" hoặc bất kỳ kit nào bạn đang sử dụng trong khóa học).
- Một đèn LED.
- Một điện trở giới hạn dòng cho LED (thường là 220 Ohm - 1k Ohm).
- Một nút nhấn.
- Dây nối.
- Mạch nạp/gỡ lỗi ST-Link.
Tạo dự án mới bằng STM32CubeMX
Bước 1: Tạo dự án mới trong STM32CubeMX
Mở STM32CubeMX và tạo một project mới cho bo mạch STM32 của bạn.
Click New Project or Menu -> File -> New Project. Hoặc click vào Access to MCU selector , các bạn cũng có thể chọn Access to Board Selector nếu sử dụng các KIT của hãng.
Bước 2: Chọn vi điều khiển
Gõ STM32F103C8 vào ô tìm kiếm, chọn chip và nhấn Start project
Bước 3: Cài đặt Serial wire
Cài đặt Serial wire để nạp code theo chuẩn SWDIO-SWCLK
Trong mục SYS/Debug các bạn chọn Serial Wire, để chọn 2 chân PA13 và PA14 là chân nạp, nếu ko chọn mỗi khi cần nạp bạn phải giữ nút reset và nạp mới được.
Còn lại để mặc định
Bước 4:
Trong RCC chọn HSE nếu chạy bằng thạch anh ngoài, ko chọn gì sẽ chạy bằng thạch anh nội
Bước 5: Cấu hình chân GPIO trong STM32CubeMX
Cấu hình chân LED:
Click chuột vào chân PC13 sau đó tích vào ô GPIO_Output
Cấu hình các chân GPIO như ở dưới:
- GPIO output level: “LOW” (Trạng thái ban đầu của led và sẽ được kích khi xuất mức “0” tại chân IO)
- GPIO mode: “Output push-pull”
- Maximum output speed: Đối với các dòng vi điều khiển có tốc độ xử lý nhanh từ vài chục MHz trở lên, thì chúng ta phải khai báo tốc độ dao động tại chân đó để đáp ứng với tốc độ xử lý của vi điều khiển. Hiện tại, chúng ta đang sử dụng nguồn dao động nội với tốc độ là 8MHz nên ở đây sẽ chọn “LOW”
- User Label: “LED”
Cấu hình chân nút nhấn:
- Tìm một chân GPIO trống khác cho nút nhấn của bạn (ví dụ: PA0, PB5, v.v.).
- Nhấp chuột phải vào chân đó và chọn GPIO_Input.
- Thay đổi tên nhãn (User Label) cho chân này. Ví dụ: đặt là
BTN_Pin
. - Trong cửa sổ Pinout & Configuration, chọn tab GPIO.
- Tìm chân nút nhấn của bạn, và trong cột User Label, đảm bảo tên đã được đặt đúng.
- Cài đặt quan trọng: Đối với nút nhấn, chúng ta thường sử dụng điện trở kéo lên (pull-up) hoặc kéo xuống (pull-down) bên trong vi điều khiển để đảm bảo trạng thái ổn định khi nút nhấn không được nhấn. Trong trường hợp này, vì đoạn mã của bạn kiểm tra
== 0
(nghĩa là nút nhấn được nhấn sẽ kéo chân xuống mức thấp), chúng ta sẽ cấu hình chân này là Pull-up.- Trong cột GPIO output level, chọn No Pull-up and No Pull-down hoặc Pull-up (tùy thuộc vào cách bạn đấu dây nút nhấn). Với đoạn code hiện tại, khi nút nhấn được nhấn, chân sẽ kéo xuống 0V. Nếu bạn đấu nút nhấn từ chân GPIO xuống GND, và muốn khi nhấn nút thì chân xuống 0V, bạn nên cấu hình là Pull-up.
- Lưu ý: Nếu bạn đấu nút nhấn từ chân GPIO lên VCC và muốn khi nhấn nút thì chân lên VCC, bạn có thể cấu hình là Pull-down. Với đoạn mã của bạn, cấu hình Pull-up là phù hợp khi nút nhấn được đấu từ chân GPIO xuống GND.
Bước 6: Clock config
Phần Clock config, để mặc định đó là thạch anh nội 8Mhz, phần Project Manager Gõ tên project, nơi lưu trữ, chọn tool chain là MDK-ARM V5, sau đó nhấn Generate Code
Hướng dẫn lập trình bật tắt led PC13 bằng nút nhấn sau khi đã sinh code:
Sau khi sinh code STM32CubeMX sẽ hiển thị thông báo
- Chọn open project
- Lưu ý: các bạn phải viết code trong khoảng USER CODE BEGIN và USER CODE END nhé. Vì nếu bạn thay đổi trong file Cube và Gen code lại, các code ngoài khoảng này đều bị xóa hết.
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
if(HAL_GPIO_ReadPin(BTN_GPIO_Port, BTN_Pin) == 0) // Neu nut nhan duoc nhan (vì dùng pull-up)
{
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, 0);// Bat LED
}
else
{
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, 1); // Tat LED
}
HAL_Delay(1000); // Delay ngan de tránh doc sai do nút nhan
}
/* USER CODE END 3 */
Giải thích mã:
HAL_GPIO_ReadPin(BTN_GPIO_Port, BTN_Pin)
: Hàm này đọc trạng thái của chân GPIO mà bạn đã cấu hình làBTN_Pin
.- Nếu chân này được kéo xuống mức thấp (0V) khi nút nhấn được nhấn (điều này xảy ra khi bạn đấu nút nhấn từ chân GPIO xuống GND và cấu hình chân là pull-up), hàm sẽ trả về
0
hoặcGPIO_PIN_RESET
. - Nếu chân này đang ở mức cao (VCC) khi nút nhấn không được nhấn (do điện trở pull-up kéo lên VCC), hàm sẽ trả về
1
hoặcGPIO_PIN_SET
.
- Nếu chân này được kéo xuống mức thấp (0V) khi nút nhấn được nhấn (điều này xảy ra khi bạn đấu nút nhấn từ chân GPIO xuống GND và cấu hình chân là pull-up), hàm sẽ trả về
if(HAL_GPIO_ReadPin(BTN_GPIO_Port, BTN_Pin) == 0)
: Điều kiện này kiểm tra xem nút nhấn có đang được nhấn hay không. Nếu hàmHAL_GPIO_ReadPin
trả về 0, nghĩa là nút nhấn đang được nhấn.HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET)
: Hàm này đặt trạng thái của chân LED.GPIO_PIN_RESET
(hoặc0
) sẽ đưa chân LED xuống mức thấp (0V), làm cho LED bật (nếu LED được đấu anode vào VCC và cathode qua trở xuống chân GPIO).HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET)
: Hàm này đặt trạng thái của chân LED lên mức cao (3.3V hoặc 5V tùy vào VCC của vi điều khiển). Điều này sẽ làm cho LED tắt (nếu LED được đấu anode vào VCC và cathode qua trở xuống chân GPIO).HAL_Delay(1000)
: Hàm này tạo ra một độ trễ 1000 mili giây (1 giây). Trong trường hợp điều khiển nút nhấn, độ trễ này có thể hơi dài. Một độ trễ ngắn hơn (ví dụ: 10-50ms) thường được sử dụng để chống dội phím (debounce) và đảm bảo nút nhấn được đọc chính xác mà không làm trễ quá nhiều quá trình phản hồi. Tuy nhiên, với mục đích thử nghiệm ban đầu, 1000ms cũng chấp nhận được.
Biên dịch và nạp chương trình
- Biên dịch (Compile) dự án của bạn để kiểm tra lỗi.
- Nạp (Flash) chương trình vào vi điều khiển STM32 của bạn thông qua ST-Link.
Kiểm tra hoạt động
Sau khi nạp chương trình, bạn hãy thử nhấn nút nhấn.
- Khi bạn nhấn nút nhấn, đèn LED sẽ bật.
- Khi bạn nhả nút nhấn, đèn LED sẽ tắt.
Lưu ý quan trọng về đấu nối phần cứng:
- Đấu nối LED:
- Nối chân dài hơn của LED (anode) vào VCC (ví dụ: 3.3V hoặc 5V) thông qua một điện trở giới hạn dòng (220 Ohm - 1k Ohm).
- Nối chân ngắn hơn của LED (cathode) vào chân GPIO đã cấu hình là đầu ra (ví dụ:
LED_Pin
). - Với cách đấu nối này, khi chân GPIO xuất ra
GPIO_PIN_RESET
(LOW), LED sẽ bật. Khi chân GPIO xuất raGPIO_PIN_SET
(HIGH), LED sẽ tắt.
- Đấu nối nút nhấn:
- Nối một chân của nút nhấn vào chân GPIO đã cấu hình là đầu vào (ví dụ:
BTN_Pin
). - Nối chân còn lại của nút nhấn xuống GND.
- Với cấu hình pull-up trên chân GPIO, khi nút nhấn không được nhấn, chân GPIO sẽ được kéo lên VCC (HIGH). Khi nút nhấn được nhấn, chân GPIO sẽ được kéo xuống GND (LOW).
- Nối một chân của nút nhấn vào chân GPIO đã cấu hình là đầu vào (ví dụ:
Mô phỏng nhấn PA0 → LED PC13 sáng
Các bạn nhấn thử vào nút nhấn để xem kết qua nhé

Chúc bạn thành công!
Nhận xét