STM32 LibOpenCM3:GPIO 輸入

系列:簡單入門 LibOpenCM3 STM32 嵌入式系統開發 Posted on 2022-09-18

前言

在上一篇中我們介紹了基本的 STM32 GPIO 輸出,並寫了一個簡單的 LED 閃爍程式,還教了 PIO 的多環境設定。

這一篇要接續介紹 LibOpenCM3 的基本 GPIO 輸入寫法,功能爲當按下按鈕時 LED 會亮起。

正文

首先一樣以 Nucleo-F446RE 做示範。

首先建立一個 PIO 的專案,選擇 Framework 爲「libopencm3」,並在 src/ 資料夾中新增並開啓 main.c 檔案。

完整程式

一樣先打出完整程式:

 1/**
 2 * @file   main.c
 3 * @brief  Polling button 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
14/* User button (B1) connected to PC13. */
15#define RCC_BUTTON_GPIO (RCC_GPIOC)
16#define GPIO_BUTTON_PORT (GPIOC)
17#define GPIO_BUTTON_PIN (GPIO13)
18
19int main(void)
20{
21  /* Enable clock. */
22  rcc_periph_clock_enable(RCC_LED_GPIO);
23  rcc_periph_clock_enable(RCC_BUTTON_GPIO);
24
25  /*
26   * Set LED pin to output push-pull,
27   * and set button pin to input floating.
28   */
29  gpio_mode_setup(GPIO_LED_PORT,
30                  GPIO_MODE_OUTPUT,
31                  GPIO_PUPD_NONE,
32                  GPIO_LED_PIN);
33  gpio_set_output_options(GPIO_LED_PORT,
34                          GPIO_OTYPE_PP,
35                          GPIO_OSPEED_2MHZ,
36                          GPIO_LED_PIN);
37
38  gpio_mode_setup(GPIO_BUTTON_PORT,
39                  GPIO_MODE_INPUT,
40                  GPIO_PUPD_NONE,
41                  GPIO_BUTTON_PIN);
42
43  while (1)
44  {
45    /* Read input value. */
46    bool pressed = gpio_get(GPIO_BUTTON_PORT, GPIO_BUTTON_PIN) == 0;
47
48    if (pressed)
49    {
50      gpio_set(GPIO_LED_PORT, GPIO_LED_PIN); /* LED on. */
51    }
52    else
53    {
54      gpio_clear(GPIO_LED_PORT, GPIO_LED_PIN); /* LED off. */
55    }
56  }
57
58  return 0;
59}

分段說明

Include

1#include <libopencm3/stm32/rcc.h>
2#include <libopencm3/stm32/gpio.h>

Include 的部分和 GPIO 輸入時一樣,引入 rcc.hgpio.h

定義腳位

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)
5
6/* User button (B1) connected to PC13. */
7#define RCC_BUTTON_GPIO (RCC_GPIOC)
8#define GPIO_BUTTON_PORT (GPIOC)
9#define GPIO_BUTTON_PIN (GPIO13)

根據 Datasheet (UM1724),我們得知按鈕 User Button (B1) 在 PC13 腳。一樣使用
#define 定義好接腳和 RCC,方便使用與修改。而 LED 一樣是 PA5。

主程式

 1int main(void)
 2{
 3  /* Enable clock. */
 4  rcc_periph_clock_enable(RCC_LED_GPIO);
 5  rcc_periph_clock_enable(RCC_BUTTON_GPIO);
 6
 7  /*
 8   * Set LED pin to output push-pull,
 9   * and set button pin to input floating.
10   */
11  gpio_mode_setup(GPIO_LED_PORT,
12                  GPIO_MODE_OUTPUT,
13                  GPIO_PUPD_NONE,
14                  GPIO_LED_PIN);
15  gpio_set_output_options(GPIO_LED_PORT,
16                          GPIO_OTYPE_PP,
17                          GPIO_OSPEED_2MHZ,
18                          GPIO_LED_PIN);
19
20  gpio_mode_setup(GPIO_BUTTON_PORT,
21                  GPIO_MODE_INPUT,
22                  GPIO_PUPD_NONE,
23                  GPIO_BUTTON_PIN);
24
25  while (1)
26  {
27    /* Read input value. */
28    bool pressed = gpio_get(GPIO_BUTTON_PORT, GPIO_BUTTON_PIN) == 0;
29
30    if (pressed)
31    {
32      gpio_set(GPIO_LED_PORT, GPIO_LED_PIN); /* LED on. */
33    }
34    else
35    {
36      gpio_clear(GPIO_LED_PORT, GPIO_LED_PIN); /* LED off. */
37    }
38  }
39
40  return 0;
41}

和 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

 1int main(void)
 2{
 3  /* 省略部分程式 */
 4
 5  /*
 6   * Set LED pin to output push-pull,
 7   * and set button pin to input floating.
 8   */
 9#if defined(STM32F1)
10  gpio_set_mode(GPIO_LED_PORT,
11                GPIO_MODE_OUTPUT_2_MHZ,
12                GPIO_CNF_OUTPUT_PUSHPULL,
13                GPIO_LED_PIN);
14
15  gpio_set_mode(GPIO_BUTTON_PORT,
16                GPIO_MODE_INPUT,
17                GPIO_CNF_INPUT_FLOAT,
18                GPIO_BUTTON_PIN);
19#else
20  gpio_mode_setup(GPIO_LED_PORT,
21                  GPIO_MODE_OUTPUT,
22                  GPIO_PUPD_NONE,
23                  GPIO_LED_PIN);
24  gpio_set_output_options(GPIO_LED_PORT,
25                          GPIO_OTYPE_PP,
26                          GPIO_OSPEED_2MHZ,
27                          GPIO_LED_PIN);
28
29  gpio_mode_setup(GPIO_BUTTON_PORT,
30                  GPIO_MODE_INPUT,
31                  GPIO_PUPD_NONE,
32                  GPIO_BUTTON_PIN);
33#endif
34
35  /* 省略部分程式 */
36}

成果

小結

這次介紹了最簡單的 GPIO 輸入寫法。說實話,這種用法比較少會實際應用到,因爲大多數情況輪詢是一件很沒效率也不夠聰明的方法。通常要使用按鈕輸入時,我都會優先考慮使用外部中斷(EXTI)的方式達成,因此下一篇要介紹的就是外部中斷。

參考資料

本文的程式也有放在 GitHub 上。
本文同步發表於 iT 邦幫忙-2022 iThome 鐵人賽



留言可能不會立即顯示。若過了幾天仍未出現,請 Email 聯繫:)

comments powered by Disqus