Tài liệu này hướng dẫn chi tiết các bước để cấu hình, viết mã, biên dịch và nạp chương trình cho board Nucleo-F411RE sử dụng phần mềm STM32CubeMX và Keil C.
Giới thiệu Board Phát Triển
Bài hướng dẫn này được thực hiện trên board phát triển XNUCLEO-F411RE. Đây là một board có layout tương tự các board Nucleo của ST, với đầy đủ các chân cắm mở rộng theo chuẩn Arduino. Sơ đồ chân (pinout) của board được minh họa trong hình dưới đây, giúp bạn dễ dàng xác định vị trí các đèn LED và nút nhấn mà chúng ta sẽ sử dụng.
Trong hướng dẫn này, chúng ta sẽ tập trung vào:
- USER_BUTTON (BTN): Nối với chân PC13.
- USER_LED1: Nối với chân PA5 (Thường là LED có sẵn trên các board Nucleo).
- USER_LED2, LED3, LED4: Nối với các chân PC9, PC8, và PC5.
Lưu ý: Mặc dù hình ảnh có thể ghi model khác (F103RB), sơ đồ vị trí các LED và nút nhấn này tương thích với cấu hình cho F411RE mà chúng ta đang sử dụng.
Kết nối mạch nạp
Phần 1: Cấu hình chi tiết trong STM32CubeMX
Bước 1: Pinout & Configuration
Đây là bước cấu hình các chân và các ngoại vi cơ bản.
- Cấu hình Debug: Để có thể nạp code và gỡ lỗi, bạn cần kích hoạt giao thức Serial Wire Debug (SWD).
- Trong mục
Categories
bên trái, chọnSystem Core
>SYS
. - Trong phần
Debug
, chọnSerial Wire
. Thao tác này sẽ dành riêng chân PA13 và PA14 cho việc debug.
- Trong mục
- Cấu hình chân GPIO:
- Nút nhấn (BTN): Tìm chân
PC13
, click vào và chọnGPIO_Input
. Sau đó, click chuột phải vào chân PC13, chọnEnter User Label
và đặt tên làBTN
. Trong bảng cấu hình bên dưới (GPIO Mode and Configuration), đảm bảo chế độ làInternal Pull-up
. - Các đèn LED: Lần lượt tìm các chân
PA5
,PC9
,PC8
,PC5
. Click vào từng chân và chọnGPIO_Output
. Đặt User Label tương ứng làLED1
,LED2
,LED3
, vàLED4
.
- Nút nhấn (BTN): Tìm chân
Sau khi hoàn tất, giao diện của bạn sẽ trông giống như hình dưới đây:
Bước 2: Clock Configuration
Đây là nơi bạn thiết lập tốc độ hoạt động cho vi điều khiển.
- Chuyển sang tab
Clock Configuration
. - Board Nucleo-F411RE sử dụng thạch anh tần số cao bên ngoài (HSE) được cung cấp bởi mạch ST-LINK. Chúng ta sẽ cấu hình hệ thống để chạy ở tốc độ tối đa là 100 MHz.
- Trong sơ đồ cây xung nhịp, tìm đến ô
HCLK (MHz)
, nhập giá trị100
và nhấn Enter. STM32CubeMX sẽ tự động tính toán và đề xuất một cấu hình hợp lệ. Bạn chỉ cần nhấn OK để chấp nhận.
Bước 3: Project Manager & Code Generation
Đây là bước cuối cùng để thiết lập thông tin project và tạo mã nguồn.
- Chuyển sang tab
Project Manager
. - Trong mục Project:
- Project Name: Đặt tên cho project (ví dụ:
XNUCLEO_STM32F411RE
). - Project Location: Nhấn
Browse
và chọn thư mục bạn muốn lưu project. - Toolchain / IDE: Chọn
MDK-ARM
từ danh sách thả xuống.
- Project Name: Đặt tên cho project (ví dụ:
- Trong mục Code Generator:
- Đảm bảo bạn đã chọn "Copy all used libraries into the project folder".
- Nên chọn "Generate peripheral initialization as a pair of '.c/.h' files per peripheral" để cấu trúc code gọn gàng hơn.
Cuối cùng, nhấn vào nút GENERATE CODE
ở góc trên bên phải. STM32CubeMX sẽ tạo ra toàn bộ cấu trúc project cho Keil C. Sau khi tạo xong, một hộp thoại sẽ hiện ra, nhấn vào Open Project
để mở project trong Keil C.
Phần 2: Viết mã, Biên dịch và Nạp chương trình
Bước 1: Viết mã điều khiển trong Keil C
Sau khi project được mở trong Keil C, bạn cần tìm đến file main.c
. File này nằm trong cây thư mục bên trái, thường là trong Application/User/Core
. Chúng ta sẽ thêm code vào 2 vị trí: khai báo biến trước vòng lặp while(1)
và logic xử lý bên trong vòng lặp đó.
Logic chương trình mới sẽ như sau: mỗi lần nhấn nút, chương trình sẽ chuyển trạng thái để bật lần lượt từng đèn LED, theo chu kỳ: Tắt hết -> LED1 sáng -> LED2 sáng -> LED3 sáng -> LED4 sáng -> Tắt hết.
Đầu tiên, thêm đoạn code sau vào giữa /* USER CODE BEGIN 2 */
và /* USER CODE END 2 */
để khai báo các biến cần thiết.
/* USER CODE BEGIN 2 */
uint8_t ledState = 0; // 0:Tat, 1:LED1, 2:LED2, 3:LED3, 4:LED4
/* USER CODE END 2 */
Tiếp theo, thay thế toàn bộ code trong vòng lặp while(1)
(giữa /* USER CODE BEGIN 3 */
và /* USER CODE END 3 */
) bằng đoạn code logic mới dưới đây.
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
// 1. Kiểm tra xem nút BTN có được nhấn không (dùng Label)
if (HAL_GPIO_ReadPin(BTN_GPIO_Port, BTN_Pin) == GPIO_PIN_RESET)
{
// 2. Chống dội phím đơn giản bằng delay
HAL_Delay(20);
// 3. Tăng biến trạng thái để chuyển LED
ledState++;
// 4. Nếu trạng thái vượt quá 4, quay về 0 để lặp lại chu trình
if (ledState > 4)
{
ledState = 0;
}
// 5. Tắt tất cả các LED trước khi bật LED mới (dùng Label)
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LED4_GPIO_Port, LED4_Pin, GPIO_PIN_RESET);
// 6. Dùng switch-case để bật LED tương ứng với trạng thái (dùng Label)
switch (ledState)
{
case 1: // Sáng LED1
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);
break;
case 2: // Sáng LED2
HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET);
break;
case 3: // Sáng LED3
HAL_GPIO_WritePin(LED3_GPIO_Port, LED3_Pin, GPIO_PIN_SET);
break;
case 4: // Sáng LED4
HAL_GPIO_WritePin(LED4_GPIO_Port, LED4_Pin, GPIO_PIN_SET);
break;
case 0: // Tắt tất cả
// Không cần làm gì vì đã tắt hết ở trên
break;
}
// 7. Chờ cho đến khi nút được nhả ra hoàn toàn
// Điều này ngăn chương trình chạy lặp lại khi bạn nhấn giữ nút
while (HAL_GPIO_ReadPin(BTN_GPIO_Port, BTN_Pin) == GPIO_PIN_RESET);
HAL_Delay(50); // Thêm một khoảng delay nhỏ sau khi nhả nút
}
/* USER CODE END 3 */
}
BTN_GPIO_Port
, BTN_Pin
, LED1_GPIO_Port
, v.v. được STM32CubeMX tự động định nghĩa trong file main.h
dựa trên User Label bạn đã đặt.
Bước 2: Biên dịch (Build) và Nạp code (Download)
Sau khi đã thêm code, bạn cần thực hiện các bước sau để nạp chương trình xuống board.
-
Cấu hình Debugger:
- Nhấn vào nút "Options for Target" (biểu tượng cây đũa thần màu đỏ).
- Trong hộp thoại hiện ra, chuyển sang tab "Debug".
- Ở menu thả xuống bên phải, chọn
ST-Link Debugger
. - Nhấn vào nút "Settings" bên cạnh. Chuyển sang tab "Flash Download". Đảm bảo rằng tùy chọn
Reset and Run
đã được tích. Điều này sẽ giúp board tự động chạy chương trình ngay sau khi nạp xong. Nhấn OK để đóng các hộp thoại.
-
Biên dịch (Build):
- Nhấn vào nút "Build" (phím tắt F7) hoặc "Rebuild all target files".
- Quan sát cửa sổ "Build Output" ở phía dưới. Nếu không có lỗi (0 Errors), bạn đã sẵn sàng để nạp code.
-
Nạp Code (Download):
- Kết nối board Nucleo với máy tính qua cổng USB.
- Nhấn vào nút "Download" (phím tắt F8). Keil C sẽ nạp file đã biên dịch (.hex) vào bộ nhớ Flash của vi điều khiển.
- Cửa sổ "Build Output" sẽ hiển thị tiến trình nạp và thông báo "Flash download finished" khi hoàn tất.
Phần 3: Kết quả
Sau khi nạp code thành công, chương trình sẽ bắt đầu chạy.
- Khi bạn chưa nhấn nút
BTN
(nút màu xanh trên board), tất cả các đèn LED (LED1, LED2, LED3, LED4) sẽ tắt. - Khi bạn nhấn nút
BTN
, thì LED sẽ được sáng lần lượt từ LED1 -> LED4. Mỗi lần nhấn sẽ chuyển sang LED kế tiếp.
Chúc mừng! Bạn đã nạp thành công chương trình đầu tiên của mình lên board STM32 Nucleo.
Mô phỏng
// Khi nhấn nút...
ledState++;
if (ledState > 4) { ledState = 0; }
// Tắt hết LED
HAL_GPIO_WritePin(..., GPIO_PIN_RESET);
// Bật LED tương ứng
switch (ledState)
{
case 1: HAL_GPIO_WritePin(LED1, GPIO_PIN_SET); break;
case 2: HAL_GPIO_WritePin(LED2, GPIO_PIN_SET); break;
case 3: HAL_GPIO_WritePin(LED3, GPIO_PIN_SET); break;
case 4: HAL_GPIO_WritePin(LED4, GPIO_PIN_SET); break;
}
Nhận xét