前言 在上一篇中我們介紹了基本的 STM32 GPIO 輸出,並寫了一個簡單的 LED 閃爍程式,還教了 PIO 的多環境設定。
這一篇要接續介紹 LibOpenCM3 的基本 GPIO 輸入寫法,功能為當按下按鈕時 LED 會亮起。
正文 首先一樣以 Nucleo-F446RE 做示範。
首先建立一個 PIO 的專案 ,選擇 Framework 為「libopencm3」,並在 src/
資料夾中新增並開啓 main.c
檔案。
完整程式 一樣先打出完整程式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 #include <libopencm3/stm32/rcc.h> #include <libopencm3/stm32/gpio.h> #define RCC_LED_GPIO (RCC_GPIOA) #define GPIO_LED_PORT (GPIOA) #define GPIO_LED_PIN (GPIO5) #define RCC_BUTTON_GPIO (RCC_GPIOC) #define GPIO_BUTTON_PORT (GPIOC) #define GPIO_BUTTON_PIN (GPIO13) int main (void ) { rcc_periph_clock_enable(RCC_LED_GPIO); rcc_periph_clock_enable(RCC_BUTTON_GPIO); gpio_mode_setup(GPIO_LED_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_LED_PIN); gpio_set_output_options(GPIO_LED_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO_LED_PIN); gpio_mode_setup(GPIO_BUTTON_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_BUTTON_PIN); while (1 ) { bool pressed = gpio_get(GPIO_BUTTON_PORT, GPIO_BUTTON_PIN) == 0 ; if (pressed) { gpio_set(GPIO_LED_PORT, GPIO_LED_PIN); } else { gpio_clear(GPIO_LED_PORT, GPIO_LED_PIN); } } return 0 ; }
分段說明 Include 1 2 #include <libopencm3/stm32/rcc.h> #include <libopencm3/stm32/gpio.h>
Include 的部分和 GPIO 輸入 時一樣,引入 rcc.h
與 gpio.h
。
定義腳位 1 2 3 4 5 6 7 8 9 #define RCC_LED_GPIO (RCC_GPIOA) #define GPIO_LED_PORT (GPIOA) #define GPIO_LED_PIN (GPIO5) #define RCC_BUTTON_GPIO (RCC_GPIOC) #define GPIO_BUTTON_PORT (GPIOC) #define GPIO_BUTTON_PIN (GPIO13)
根據 Datasheet (UM1724),我們得知按鈕 User Button (B1) 在 PC13 腳。一樣使用#define
定義好接腳和 RCC,方便使用與修改。而 LED 一樣是 PA5。
主程式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 int main (void ) { rcc_periph_clock_enable(RCC_LED_GPIO); rcc_periph_clock_enable(RCC_BUTTON_GPIO); gpio_mode_setup(GPIO_LED_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_LED_PIN); gpio_set_output_options(GPIO_LED_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO_LED_PIN); gpio_mode_setup(GPIO_BUTTON_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_BUTTON_PIN); while (1 ) { bool pressed = gpio_get(GPIO_BUTTON_PORT, GPIO_BUTTON_PIN) == 0 ; if (pressed) { gpio_set(GPIO_LED_PORT, GPIO_LED_PIN); } else { gpio_clear(GPIO_LED_PORT, GPIO_LED_PIN); } } return 0 ; }
和 GPIO 輸入的時候一樣,先啓用 RCC,然後再設定 GPIO。
由於 Nucleo MB1136 開發板(參考 UM1724 )的 User Button 已經有 4.7kΩ 的上拉電阻(平常是 High
,按下時為 Low
),因此輸入模式選擇 Floating (不用上/下拉電阻,GPIO_PUPD_NONE
)就好了。
我們使用最簡單的輪詢(Polling)方式來取得按鈕的輸入值,再依其值改變 LED 的明滅。使用 gpio_get()
來讀取指定的 GPIO 的值。
多環境程式(F446RE + F103RB) 由於 STM32F1 系列的部分函式不同,因此 F103RB 不能直接使用上面那個程式。
以下列出主要的差異部分。完整的程式請看 GitHub repo 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 int main (void ) { #if defined(STM32F1) gpio_set_mode(GPIO_LED_PORT, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO_LED_PIN); gpio_set_mode(GPIO_BUTTON_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_BUTTON_PIN);#else gpio_mode_setup(GPIO_LED_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_LED_PIN); gpio_set_output_options(GPIO_LED_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ, GPIO_LED_PIN); gpio_mode_setup(GPIO_BUTTON_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, GPIO_BUTTON_PIN);#endif }
成果
小結 這次介紹了最簡單的 GPIO 輸入寫法。說實話,這種用法比較少會實際應用到,因為大多數情況輪詢是一件很沒效率也不夠聰明的方法。通常要使用按鈕輸入時,我都會優先考慮使用外部中斷(EXTI)的方式達成,因此下一篇要介紹的就是外部中斷。
參考資料
本文的程式也有放在 GitHub 上。 本文同步發表於 iT 邦幫忙-2022 iThome 鐵人賽 。