Hôm nay chúng ta sẽ bắt đầu bài nhập môn, đối với lập trình các ngôn ngữ khác ví dụ đầu tiên thông thường là “Hello World”, còn với lập trình nhúng đó là nháy Led.
Để bắt đầu viết những dòng code đầu tiên, chúng ta cần tìm hiểu qua về Kit STM32F103C8T6 Blue Pill. Dưới đây là hình ảnh mặt trên và mặt dưới của Kit

Qua mỗi bài viết, chúng ta sẽ cùng nhau nghiên cứu kỹ về từng chức năng cũng như là cách sử dụng vi điều khiển vào bài toán thực tế, còn bây giờ là những thông số chính của Kit Blue Pill.
| Vi điều khiển sử dụng | STM32F103C8T6, lõi ARM Cotrex M3, họ vi điều khiển 32 bit |
| Tốc độ xử lý tối đa của CPU | 72Mhz |
| Bộ nhớ Flash | 64KB |
| Bộ nhớ RAM | 20KB |
| Số lượng chân đầu ra/vào | 37 |
| ADC | 2 |
| Timer | 7 |
| UART | 3 |
| I2C | 2 |
| SPI | 2 |
| USB | 1 |
| Module thời gian thực (RTC) | Có |
| Module tính CRC | Có |
| Nguồn cấp vi điều khiển | 2…3,6V |
| Nguồn cấp cho Kit | 5V |
| Dòng tiêu thụ | tới 50Ma |
| Kích thước của Kit | 53×22,5mm |
Các chân vi điều khiển được nối trực tiếp tới các đầu ra mạch PCB của Kit, hình vẽ bên dưới minh họa rất chi tiết và rõ ràng

Một số lưu ý:
- Vi điều khiển được cấp bằng nguốn 3V và điện áp mức cao (HIGH) đầu ra cũng như đầu vào của tín hiệu số là 3V. Nhưng có một số chân được ký hiệu là 5V tolerant cho phép kết nối với các tín hiệu đầu vào có điện áp mức cao là 5, ví dụ như là các chân từ 25 đến 28 chẳng hạn. Các chân còn lại chịu được điện áp không lớn hơn điện áp cấp, thường là 3V, nếu tăng điện áp này trên 4V thì bạn sẽ làm hỏng vi điều khiển.
- Các chân của vi điều khiển cho phép dòng điện ra vào tối đa là 20mA, khuyến cáo không nên vượt quá 8mA, những chân có dấu chấm than chỉ có thể sử dụng với dòng đi vào không quá 3mA (ví dụ như chân PC13-PC15)
- Trên mạch có một đèn LED được kết nối với chân PC13, đèn sẽ sáng khi tín hiệu trên chân này ở mức thấp (LOW) và đèn tắt khi tín hiệu ở mức cao (HIGH)
Dưới đây là sơ đồ mạch nguyên lý của Kit Blue Pill

Đến đây chúng ta đã tìm hiểu rõ về phần cứng và mạch nguyên lý của Kit Blue Pill. Một tài liệu hết sức quan trọng nữa mà chúng ta cần phải có đó là STM32F103C8T6 Reference manual: https://www.st.com/resource/en/reference_manual/cd00171190-stm32f101xx-stm32f102xx-stm32f103xx-stm32f105xx-and-stm32f107xx-advanced-arm-based-32-bit-mcus-stmicroelectronics.pdf
, tài liệu mô tả chi tiết cấu trúc của vi điều khiển STM32F103C8T6.
Và bây giờ là thời điểm để tiến hành code bài nhập môn “Nháy đèn LED”. Đầu tiên chúng ta mở phần mềm STM32CubeMX để tạo project. Sau khi giao diện hiện ra, các bạn đi tới mục New Project sau đó di chuyển tới ACCESS TO MCU SELECTOR và kích chuột để chọn dòng vi điều khiển cần thiết

Tiếp theo phần mềm sẽ hiện ra cửa sổ mới, các bạn gõ vào ô Commercial Part Number mã dòng vi điều khiển mà chúng ta muốn xây dựng phần mềm

Sau đó các bạn chọn STM32F103C8T6x và nháy đúp chuột hoặc bấm vào NÚT Start Project để bắt đầu tạo ứng dụng.

Phần mềm sẽ hiện ra một giao diện mới như sau

Tại đây phần mềm cho phép thiết lập cấu hình, các chân ra/vào và các ngoại vi cần thiết để thực hiện ứng dụng. Đầu tiên, chúng ta cần phải thiết lập tần số hoạt động của CPU, hay nói cách khác cần phải thiết lập xung nhịp (clock) cho vi điều khiển. Tần số xung nhịp của chip phản ánh tốc độ xử lý của CPU, nếu tần số càng cao thì CPU xử lý càng nhanh và ngược lại. Hiện tại thì STM đã có những dòng đạt tới tốc độ xử lý trên 600MHz nghĩa là trong 1s thì có hơn 600000000 phép xử lý. Đối với STM32F103C8T6 tần số Max là 72MHz. Như vậy, tùy vào yêu cầu của bài toán mà các bạn có thể chọn chip có tốc độ phù hợp.
Các bạn vào System Core ->RCC, trong mục RCC Mode and Configuration sẽ hiện ra 2 option đó là High Speed Clock (HSE) và Low Speed Clock (LSE).

Low Speed Clock (LSE) – đây là nguồn xung nhịp có tần số thấp, được dùng khi mà bài toán cần sử dụng module RTC (thời gian) của vi điều khiển. Đối với nội dung này chúng ta sẽ cùng nhau tìm hiểu ở các bài viết sau
High Speed Clock (HSE) – đây là nguồn xung nhịp có tần số cao, bắt buộc chúng ta phải thiết lập cho mỗi ứng dụng. Có 3 options cần làm rõ:
- Disable : mặc định sử dụng thạch anh sẵn có bên trong vi điều khiển với tần số 8MHz
- BYPASS Clock Source và Crystal/Ceramic Resonator: sử dụng nguồn xung nhịp bên ngoài để cấp cho vi điều khiển, đối với Crystal/Ceramic Resonator sử dụng thạch anh ngoài, còn BYPASS Clock Source là nguồn xung nhịp ngoài có thể là từ các thiết bị khác (ví dụ, trên nhiều Kit của STM người ta lấy xung nhịp để cấp cho vi điều khiển từ chân đầu ra Master Clock Output – MCO của một vi điều khiển khác trong mạch nạp STLink).
Đối với Kit Blue Pill, chúng ta có thể thấy là trên mạch đã hàn sẵn một thạch anh ngoài có giá trị là 8MHz.

Chúng ta nên sử dụng các thạch anh hay nguồn xung nhịp bên ngoài để vi điều khiển có thể đạt được tần số tối đa và hoạt động ổn định hơn.
Như vậy với trường hợp Kit Blue Pill, chúng ta sẽ chọn Crystal/Ceramic Resonator. Sau khi chọn, ngay lập tức trên vi điều khiển sẽ xuất hiện hai chân RCC_OSC_IN (PD0) và RCC_OSC_OUT (PD1) được tô màu xanh lá cây. Đây cũng là hai chân đầu vào của thạch anh ngoài, trên mạch Kit Blue Pill đã được hàn sẵn nên chúng ta chỉ cần sử dụng mà thôi.

Tiếp theo, cần phải thiết lập xung nhịp cho vi điều khiển. Các bạn đi tới Clock Configuration như hình vẽ

Tại cửa sổ này, cho phép chúng ta thiết lập tần số hoạt động của vi điều khiển. Tại ô HCLK (MHz) các bạn nhập vào tần số mong muốn (đương nhiên là không quá tần số Max rồi) và nhấn Enter thì phần mềm sẽ tự động tạo một configuration thích hợp. Ở đây tôi nhập giá trị là 72, nghĩa là tôi chọn tần số hoạt động Max 72MHz cho ứng dụng này.
Trong hình chúng ta có thể thấy rằng, Input Frequency của chúng ta có giá trị là 8MHz, đúng như giá trị của thạch anh được hàn sẵn trên mạch, nếu như giá trị của thạch anh là một số khác, thì các bạn cần phải nhập đúng giá trị vào ô Input frequency này, sau đó mới nhập tiếp vào ô HCLK, nếu không thì vi điều khiển sẽ hoạt động không đúng theo yêu cầu.

Sau khi phần mềm tự động cấu hình Clock xong, chúng ta sẽ quay trở lại cửa sổ Pinout & Configuration để tiếp tục chọn cấu hình chân cho ứng dụng. Theo mạch nguyên lý thì trên PCB chân PC13 của vi điều khiển có nối với LED, như tôi đã đề cập đèn sẽ sáng khi tín hiệu trên chân này ở mức thấp (LOW) và đèn tắt khi tín hiệu ở mức cao (HIGH). Như vậy để đèn sáng thì đầu ra của chân PC13 phải xuất điện áp mức 0, và để đèn tắt thì xuất điện áp mức 1.
Các bạn chuột trái vào chân PC13 trên sơ đồ chân của vi điều khiển và chọn GPIO_Output.

Để đặt tên chân đầu ra theo cách của mình, các bạn chuột phải lên chân PC13 sau đó chọn Enter User Label và điền tên gọi mới. Tôi đặt tên là LED1


Để cấu hình chân output PC13, các bạn chọn System Core->GPIO, mục configuration sẽ hiện ra như hình vẽ. Ở đây cần hiểu rõ các chức năng cấu hình chân output, trong Reference manual trang 164 có trình bày chi tiết như sau:

– Với chế độ Output Open drain: Một giá trị bit bằng 0 ở thanh ghi Output data register sẽ làm N-MOS dẫn, P-MOS ngưng dẫn, lúc này chân vi điều khiển có mức logic 0 (được nối với GND); Một giá trị bit bằng 1 ở thanh ghi Output data register sẽ làm ngưng dẫn cả N-MOS và P-MOS, chân tương ứng sẽ ở trạng thái Hi-Z (trở kháng cao).
– Với chế độ Output Push-pull: Một giá trị bit bằng 0 ở thanh ghi Output data register sẽ làm N-MOS dẫn và P-MOS ngưng dẫn, lúc này chân vi điều khiển có mức logic 0 (được nối với GND); Một giá trị bit bằng 1 ở thanh ghi Output data register sẽ làm N-MOS ngưng dẫn và P-MOS dẫn. Lúc này chân vi điều khiển có mức logic 1 (được nối với VDD)
Như vậy, đối với yêu cầu bài toán chúng ta sẽ chọn chế độ Output Push-pull. Tiếp theo:
- GPIO output level: giá trị khởi tạo cho đầu ra của chân output, có hai lựa chọn: LOW và HIGH. Chúng ta chọn LOW
- GPIO Pull-up/Pull-down: chọn No pull-up and no pull-down (kiểu pull-up và pull-down nếu các bạn nào chưa hiểu mong các bạn tự tìm hiểu nhé, cũng rất đơn giản và có rất nhiều tài liệu đã đề cập)
- Maximum output speed: với ứng dụng của chúng ta chưa cần phải xử lý ở tốc độ cao nên các bạn chọn Low.

Tiếp theo để có thể nạp phần mềm vào vi điều khiển qua mạch nạp STLink, chúng ta cần phải thiết lập chân của vi điều khiển. Trong System Core ->SYS-> Debug các bạn chọn Serial Wire để cấu hình chân nạp code từ mạch nạp (một số tài liệu trên mạng có đề cập bắt buộc phải cấu hình chân nạp nếu không quá trình nạp sẽ không thành công, với tôi thì tôi không thấy sự khác biệt giữa cấu hình và không cấu hình). Kết quả như sau:

Đến đây chúng ta đã kết thúc phần cấu hình cho vi điều khiển. Chuyển sang phần tiếp theo Project Manage

Tại mục Project các bạn đặt tên cho Project, tôi đặt tên là LED. Project Location – thư mục lưu project. Tiếp đến tại Toolchain/IDE các bạn chọn STM32CubeIDE và chọn Generate Under Root.
Tại phần Code Generator các bạn thiết lập như hình

Tiếp đến Advanced Settings. Như trong hình, cấu hình mặc định sẽ sử dụng thư viện HAL cho lập trình

Thư viện HAL là một trong những thư viện phổ biến được phần lớn lập trình viên sử dụng để viết code cho dòng vi điều khiển STM. Bên cạnh thư viện HAL, còn có nhiều thư viện khác như: LL, SPL, … có rất nhiều bài viết so sánh giữa ưu và nhược điểm của các thư viện này và dường như là thư viện HAL vẫn ưu thế hơn do nó hỗ trợ toàn bộ các dòng vi điều khiển của STM, thường xuyên được nâng cấp và cập nhật, cộng đồng sử dụng đông đảo, đặc biệt là giúp lập trình viên hoàn thiện project của mình một cách nhanh nhất.
Sau khi đã hoàn thành các bước trên, các bạn nhấn vào GENERATE CODE để tạo project.

Nếu như đây là lần đầu tiên bạn sử dụng dòng STM32F1 thì phần mềm sẽ yêu cầu bạn tải gói Firmware Package. Nhấn OK.

Tiếp theo nếu bạn chưa đăng nhập tài khoản thì STM sẽ yêu cầu đăng nhập rồi mới tải được Firmware Package, còn nếu bạn chưa có tài khoản thì buộc phải đăng ký mới (xem hướng dẫn tại bài viết trước)
Sau khi phần mềm Generate code xong sẽ xuất hiện cửa sổ và cho phép chúng ta lựa chọn mở STM32CubeIDE

Nhấn Open Project để mở Project vừa tạo trên STM32CubeIDE

Project được tạo thành công và mặc định sử dụng ngôn ngữ C, các bạn cũng có thể chuyển qua C++ bằng cách: kích chuột phải vào biểu tượng của Project và chọn Convert to C++.

Trong chuỗi bài viết này chúng ta sẽ sử dụng ngôn ngữ C để lập trình. Vì lý do là tôi quen dùng C để lập trình cho các dòng chip và so với C++ thì C sẽ được ưu tiên lựa chọn hơn trong lĩnh vực lập trình nhúng vi điều khiển, đơn giản là vì không gian bộ nhớ của vi điều khiển có giới hạn, nên ưu tiên ngôn ngữ càng đơn giản càng tối ưu được bộ nhớ.
Trong file main.c. Các bạn kéo chuột xuống dưới đến hàm while

Trong hàm này chúng ta sẽ nháy LED, cụ thể là chu kỳ 1s đèn LED sẽ sáng và tắt.
Chân PC13 được thiết lập là chân output, để xuất tín hiệu LOW HIGH tại đầu ra của chân vi điều khiển, thư viện HAL cung cấp cho người dùng hàm HAL_GPIO_WritePin(GPIOx, GPIO_Pin, PinState);
Với tham số đầu tiên chúng ta điền – GPIOC (tại vì chân nối led là PC13)
Tham số thứ hai GPIO_Pin: chân số 13
PinState – Trạng thái đầu ra của chân (0 hoặc 1)
Đoạn code nháy LED như sau

SET – tương ứng với 1 – HIGH
RESET – tương ứng với 0 – LOW
Hàm HAL_Delay với tham số tính bằng ms, trong ví dụ ta sử dụng 1000ms tương ứng với 1s.
Lưu ý: các bạn cần phải viết code của mình ở phía trên dòng /* USER CODE END WHILE*/ trong hàm while.
Ở những vị trí khác là không gian ở giữa /*USER CODE BEGIN*/ và /*USER CODE END*/

Nếu không lúc mà chúng ta Generate code lại từ STM32CubeMX thì những gì được viết trước đó sẽ biến mất mà không lưu lại. Các bạn cần ghi nhớ điều này!!!
Sau khi hoàn thiện code, các bạn cần phải buil chương trình để tìm lỗi. Nhấn biểu tượng cái búa để buil chương trình, nếu có lỗi thì chương trình sẽ hiển thị, còn không có lỗi sẽ báo tin nhắn là “Finished building. 0 errors, 0 warnings”

Tiếp theo chúng ta cần kết nối STLink với mạch vi điều khiển để nạp chương trình. Sơ đồ kết nối như sau:

Các bạn nên có cho riêng mình dây cắm test nhé
Sau khi kết nối thành công, các bạn cắm đầu USB của STLink vào máy tính, LED nguồn màu đỏ sẽ sáng như hình dưới.

Nếu STLink của bạn chưa cập nhật driver thì bước đầu tiên cần phải cập nhật driver cho STLink. Cách làm như sau: Help->ST-LINK Upgrade

Sau khi Update thành công driver

Đóng cửa sổ và bắt đầu nạp code. Các bạn nhấn vào biểu tượng tam giác màu xanh (ký hiệu Run) để nạp. Sau khi nạp code thành công chương trình sẽ thông báo tin nhắn “Download verified successfully”

Và bây giờ chúng ta quan sát và thấy đèn LED màu xanh sẽ nháy và tắt với chu kỳ 1s đúng theo ý yêu cầu bài toán.
Ngoài hàm HAL_GPIO_WritePin(GPIOx, GPIO_Pin, PinState);
Thư viện HAL còn có hàm HAL_GPIO_TogglePin(GPIOx, GPIO_Pin); sẽ tự động chuyển đổi xen kẽ trạng thái đầu ra của chân GPIO_pin
Đoạn code dưới là ví dụ sử dụng hàm HAL_GPIO_TogglePin(GPIOx, GPIO_Pin)
Đối với chân GPIO_Pin tôi đã thay thế bằng tên riêng mà chúng ta đã đặt trong lúc cấu hình LED_Pin.
Để sử dụng gợi ý của IDE chúng ta sử dụng tổ hợp Ctr+Space. Ví dụ các bạn muốn viết hàm HAL_GPIO_TogglePin(GPIOx, GPIO_Pin), thì các bạn chỉ cần viết HAL_GPIO_T sau đó Ctr+Space thì hàm sẽ tự động viết đầy đủ cho chúng ta. Đây là một phím tắt giúp chúng ta tìm hàm, tìm các biến một cách nhanh nhất.

Để comment các dòng code, các bạn bôi xanh đoạn code cần comment sau đó dùng tổ hợp phím Ctr+/, để bỏ comment chúng ta Ctr+/ một lần nữa
Nạp chương trình, chúng ta sẽ thấy đèn LED nháy nhanh hơn với chu kỳ là 200ms.
Như vậy, trong bài viết hôm nay chúng ta đã tìm hiểu về Kit Blue Pill và hoàn thành bài nhập môn của lập trình nhúng vi điều khiển STM32. Xin chúc mừng các bạn!

Gửi phản hồi cho ViLiTi Hủy trả lời