前言
終於要開始實際寫程式了,接續上一篇的內容,這次要教最基本的 LibOpenCM3 的 GPIO 輸出用法,會控制一個 LED 燈使其閃爍。
正文
先以 Nucleo-F446RE 做示範。
首先建立一個 PIO 的專案,選擇 Framework 爲「libopencm3」,並在 src/
資料夾中新增並開啓 main.c
檔案。
完整程式
先把完整的程式打出來:
1/**
2 * @file main.c
3 * @brief Blinking LED example for STM32 Nucleo-F446RE.
4 */
5
6#include <libopencm3/stm32/rcc.h>
7#include <libopencm3/stm32/gpio.h>
8
9/* User LED (LD2) connected to Arduino-D13 pin. */
10#define RCC_LED_GPIO (RCC_GPIOA)
11#define GPIO_LED_PORT (GPIOA)
12#define GPIO_LED_PIN (GPIO5)
13
14static void delay(uint32_t value)
15{
16 for (uint32_t i = 0; i < value; i++)
17 {
18 __asm__("nop"); /* Do nothing. */
19 }
20}
21
22int main(void)
23{
24 /* Enable clock. */
25 rcc_periph_clock_enable(RCC_LED_GPIO);
26
27 /* Set LED pin to output push-pull. */
28 gpio_mode_setup(GPIO_LED_PORT,
29 GPIO_MODE_OUTPUT,
30 GPIO_PUPD_NONE,
31 GPIO_LED_PIN);
32
33 gpio_set_output_options(GPIO_LED_PORT,
34 GPIO_OTYPE_PP,
35 GPIO_OSPEED_2MHZ,
36 GPIO_LED_PIN);
37
38 /* Start blinking. */
39 while (1)
40 {
41 gpio_toggle(GPIO_LED_PORT, GPIO_LED_PIN); /* LED on/off. */
42 delay(500000);
43 }
44
45 return 0;
46}
分段說明
Include
1#include <libopencm3/stm32/rcc.h>
2#include <libopencm3/stm32/gpio.h>
如同其它的程式,首先要將需要用到的功能 Include 進來。本例中有兩個檔案要引入:
rcc.h
:RCC 是 Reset and Clock Controller 的意思,由於基本上所有的 STM32 功能都需要 Clock,因此 RCC 通常是一定會用到的。gpio.h
:如如同它的名字,這就是包含了 GPIO 的各種功能。
LibOpenCM3 的這些檔案 PIO 都會幫我們處理好,所以不用另外下載或設定路徑,直接
#include
就可以了。
定義腳位
1/* User LED (LD2) connected to Arduino-D13 pin. */
2#define RCC_LED_GPIO (RCC_GPIOA)
3#define GPIO_LED_PORT (GPIOA)
4#define GPIO_LED_PIN (GPIO5)
因爲每個 STM32 Nucleo 開發板的 LED 腳位可能不同,因此使用 #define
來定義腳位比較方便程式的撰寫與修改。
根據資料手冊 UM1724,Nucleo-F446RE 的板載 LED(LD2)所在的腳位是 PA5(對應 Arduino 的 D13 腳位),也就是 GPIO Port-A 的 5 號腳,因此我們定義 GPIO_LED_PORT
爲 GPIOA
,GPIO_LED_PIN
爲 GPIO5
。
此外 RCC 也會需要依照 GPIO Port 進行設定,所以也定義一個 RCC_LED_GPIO
爲 RCC_GPIOA
。
Delay 函式
1static void delay(uint32_t value)
2{
3 for (uint32_t i = 0; i < value; i++)
4 {
5 __asm__("nop"); /* Do nothing. */
6 }
7}
這是一個最簡單暴力的 Delay 寫法,幾乎無精度可言,但目前我們只要這樣就夠了。
其中的 __asm__("nop")
代表嵌入組合語言的「nop」指令,也就是無操作(No operation)。
主程式
1int main(void)
2{
3 /* Enable clock. */
4 rcc_periph_clock_enable(RCC_LED_GPIO);
5
6 /* Set LED pin to output push-pull. */
7 gpio_mode_setup(GPIO_LED_PORT,
8 GPIO_MODE_OUTPUT,
9 GPIO_PUPD_NONE,
10 GPIO_LED_PIN);
11
12 gpio_set_output_options(GPIO_LED_PORT,
13 GPIO_OTYPE_PP,
14 GPIO_OSPEED_2MHZ,
15 GPIO_LED_PIN);
16
17 /* Start blinking. */
18 while (1)
19 {
20 gpio_toggle(GPIO_LED_PORT, GPIO_LED_PIN); /* LED on/off. */
21 delay(500000);
22 }
23
24 return 0;
25}
rcc_periph_clock_enable()
:這個函式會致能指定功能的 Clock。在這裡我們要啓用 LED 所在的 GPIO Port 的 Clock。gpio_mode_setup()
:爲指定的 GPIO 設定模式。GPIO_LED_PORT
:要設定的 GPIO Port。GPIO_MODE_OUTPUT
:設定爲「General Purpose Output」 模式。GPIO_PUPD_NONE
:設定爲不使用上下拉電阻。GPIO_LED_PIN
:要設定的 GPIO Pin,若要在同一個 Port 中設定多個 Pin,各個 Pin 可以用|
來複選。
gpio_set_output_options()
:爲指定的 GPIO 設定輸出選項。GPIO_LED_PORT
:要設定的 GPIO Port。GPIO_OTYPE_PP
:設定輸出電路組態爲「Push-Pull(推挽)」 。GPIO_OSPEED_2MHZ
:設定速度。GPIO_LED_PIN
:要設定的 GPIO Pin,若要在同一個 Port 中設定多個 Pin,各個 Pin 可以用|
來複選。
gpio_toggle()
:反轉該 GPIO 的輸出值。如果目前是輸出High
,那就變成輸出Low
,反之亦然。
編譯與燒錄/上傳
打完程式後,可以在 VS Code 左下方找到編譯(Build)和燒錄(Upload)的按鈕。也可以用快捷鍵「Ctrl
+Alt
+B
」、「Ctrl
+Alt
+U
」。
編譯完成後 PIO 會顯示佔用的資源:
1RAM: 0.0% (used 0 bytes from 131072 bytes)
2Flash: 0.1% (used 764 bytes from 524288 bytes)
記得燒錄前要用 USB 線接上 Nucleo,並安裝 ST-Link 的驅動程式,否則會報錯。
F103RB
STM32F1 系列的部分程式寫法不一樣,所以在此也提供 Nucleo-F103RB 的程式範例。主要差異只有 GPIO 的設定函式不同,STM32F1 用的是 gpio_set_mode()
,而非 gpio_mode_setup()
與 gpio_set_output_options()
。
1/**
2 * @file main.c
3 * @brief Blinking LED example for STM32 Nucleo-F103RB.
4 */
5
6#include <libopencm3/stm32/rcc.h>
7#include <libopencm3/stm32/gpio.h>
8
9/* User LED (LD2) connected to Arduino-D13 pin. */
10#define RCC_LED_GPIO (RCC_GPIOA)
11#define GPIO_LED_PORT (GPIOA)
12#define GPIO_LED_PIN (GPIO5)
13
14static void delay(uint32_t value)
15{
16 for (uint32_t i = 0; i < value; i++)
17 {
18 __asm__("nop"); /* Do nothing. */
19 }
20}
21
22int main(void)
23{
24 /* Enable clock. */
25 rcc_periph_clock_enable(RCC_LED_GPIO);
26
27 /* Set LED pin to output push-pull. */
28 gpio_set_mode(GPIO_LED_PORT,
29 GPIO_MODE_OUTPUT_2_MHZ,
30 GPIO_CNF_OUTPUT_PUSHPULL,
31 GPIO_LED_PIN);
32
33 /* Start blinking. */
34 while (1)
35 {
36 gpio_toggle(GPIO_LED_PORT, GPIO_LED_PIN); /* LED on/off. */
37 delay(500000);
38 }
39
40 return 0;
41}
PIO 環境
如果你的程式會需要在 F1 或 F4 等其它 STM32 系列上運作,那每次用 F1 時 GPIO 的寫法不同,或是有 Pin 腳不同的情況會很麻煩,所以這裡簡單介紹如何用 PIO 設定多個專案環境,方便切換。
主程式
1/**
2 * @file main.c
3 * @brief Blinking LED example for STM32 based on LibOpenCM3.
4 */
5
6#include <libopencm3/stm32/rcc.h>
7#include <libopencm3/stm32/gpio.h>
8
9/* User LED (LD2) connected to Arduino-D13 pin. */
10#if defined(NUCLEO_F103RB) || defined(NUCLEO_F446RE)
11 #define RCC_LED_GPIO (RCC_GPIOA)
12 #define GPIO_LED_PORT (GPIOA)
13 #define GPIO_LED_PIN (GPIO5)
14#else
15 #error "STM32 board not defined."
16#endif
17
18static void delay(uint32_t value)
19{
20 for (uint32_t i = 0; i < value; i++)
21 {
22 __asm__("nop"); /* Do nothing. */
23 }
24}
25
26int main(void)
27{
28 /* Enable clock. */
29 rcc_periph_clock_enable(RCC_LED_GPIO);
30
31 /* Set LED pin to output push-pull. */
32#if defined(STM32F1)
33 gpio_set_mode(GPIO_LED_PORT,
34 GPIO_MODE_OUTPUT_2_MHZ,
35 GPIO_CNF_OUTPUT_PUSHPULL,
36 GPIO_LED_PIN);
37#else
38 gpio_mode_setup(GPIO_LED_PORT,
39 GPIO_MODE_OUTPUT,
40 GPIO_PUPD_NONE,
41 GPIO_LED_PIN);
42
43 gpio_set_output_options(GPIO_LED_PORT,
44 GPIO_OTYPE_PP,
45 GPIO_OSPEED_2MHZ,
46 GPIO_LED_PIN);
47#endif
48
49 /* Start blinking. */
50 while (1)
51 {
52 gpio_toggle(GPIO_LED_PORT, GPIO_LED_PIN); /* LED on/off. */
53 delay(500000);
54 }
55
56 return 0;
57}
PIO 專案設定檔 platformio.ini
:
1[platformio]
2default_envs = nucleo_f103rb
3
4; Set/Override default options for each [env:XXX]
5[env]
6platform = ststm32
7framework = libopencm3
8
9[env:nucleo_f103rb]
10board = nucleo_f103rb
11build_flags = -D NUCLEO_F103RB
12
13[env:nucleo_f446re]
14board = nucleo_f446re
15build_flags = -D NUCLEO_F446RE
小結
這次簡單介紹了 LibOpenCM3 的 GPIO 輸出用法,這部分只要有搞懂 STM32 的 GPIO 模式應該不會太難。
參考資料
- libopencm3/libopencm3-examples
- platformio/platform-ststm32
- STM32F446RE datasheet (DS10693)
- STM32F103RB datasheet (DS5319)
- STM32 Nucleo-64 board user manual (UM1724)
本文的程式也都放在 GitHub 上。
本文同步發表於 iT 邦幫忙-2022 iThome 鐵人賽。
留言可能不會立即顯示。若過了幾天仍未出現,請 Email 聯繫:)
comments powered by Disqus