STM32 基礎開發 - GPIO 基本操作

以下內容基於 STM32F103C8T6 Blue Pill 板子。

使用庫函數進行 STM32 點亮一個 LED 開發時,有以下步驟,這些也是操作某一個 GPIO 的基礎步驟

  1. 定義 GPIO_InitTypeDef:
    GPIO_InitTypeDef GPIO_InitStructure;

  2. 配置 RCC 時鐘:以 GPIOB 爲例,Ref.Manual 中可以查到 GPIO 都是掛在 APB2 總線上的,因此 GPIOB 時鐘配置如下:
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE)

  3. 配置 GPIO_InitStructure:爲了點亮 LED,我們配置 GPIOB_Pin6 爲推輓輸出,並初始化 GPIO 端口:
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_Init(GPIOB,&GPIO_InitStructure);

  4. 配置 GPIO_Pin6 爲高電平:注意在 GPIO_Pin6 的輸出電流能力,對於常見的發光二極管,一定要串上電阻!
    GPIO_SetBits(GPIOB, GPIO_Pin_6);

這樣就完成了最簡單的點亮 LED 設計了。接下來從寄存器來看一下:

  1. GPIO_InitTypeDef 相關:
    GPIO_InitTypeDef GPIO_InitStructure;
    1)後面可以發現,所有的外設都需要定義這樣一個 XXX_InitTypeDef 結構體變量,它在 stm32f10x_gpio.h 中定義。這些結構體就定義了和這個外設相關的各種配置參數
    2)GPIO_InitTypeDef 定義了與 GPIO 外設相關的三個配置:GPIO 模式、具體的 GPIO_Pin、GPIO_Speed
    3)GPIO_Speed 比較容易忽視,這個速率是 GPIO 輸出的速率,也即 GPIO 驅動電路響應速率。對於像低速的應用,比如 USART 這種,配置成低速即可;但是如果應用要求的 GPIO 輸出速率高於了配置的 GPIO 驅動電路響應速率,則會出現失真(這裏我沒有實際驗證過,也只是理論理解,有興趣的朋友可以試試~)

  2. RCC 相關:
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE)
    1)這個函數在 stm32f10x_rcc.c 中定義,是用來配置 RCC_APB2ENR(APB2 peripheral clock enable register)寄存器(參考 Ref.Manual 7.3.7)。
    2)這個寄存器 0,2-15,19-21 bits 是可配的,每個 bit 用來使能/非使能一個外設的時鐘。
    3)配置項 RCC_APB2Periph_GPIOB 在 stm32f10x_rcc.h 中定義爲 0x08,即對應 GPIOB 這個外設在 RCC_APB2ENR 中的 bit 位。

  3. GPIO_InitStructure 相關:
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
    1)GPIO_Mode 和 GPIO_Speed 配置對應 GPIOx_CRL/GPIOx_CRH (Port configuration register low/high) 寄存器(參考 Ref.Manual 9.2.1, 9.2.2)
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    1)GPIO_Pin 的配置:每個 GPIO_Pin_x 對應一個uint16_t 數,可以在 stm32f10x.h 中查到。這些 uint16_t 的數轉成二進制後,就對應是第 x 位爲 1;比如 GPIO_Pin_6 對應 0x40 = 100 0000。
    GPIO_Init(GPIOB,&GPIO_InitStructure);
    1)後面可以看到,所有的這些外設的配置都會通過 xxx_Init( ) 這個函數來根據 GPIO_InitStructure 的內容進行初始化。尤其注意的是 GPIO_Init 的參數是兩個指針變量,所以要傳入的是 GPIO_InitStructure 的地址。

  4. GPIO_SetBits 相關:
    GPIO_SetBits(GPIOB, GPIO_Pin_6);
    1)這個函數在 stm32f10x.c 中定義,是用來配置 GPIOx_BSRR(Port bit set/reset register)寄存器的(參考 Ref.Manual 9.2.5)。
    2)這個寄存器 0:15 位是用來將 0-15 個 GPIO 端口拉高的(Set bits)的,置 1有效,16:31 位是用來將 0-15 個 GPIO 端口拉低的(Reset bits),置 1有效;但是這個函數只配置 0:15 位寄存器
    3)當需要將某個 GPIO 端口拉低時,通過下面這個函數來進行
    GPIO_ResetBits(GPIOB, GPIO_Pin_6);
    1)這個函數對應在 stm32f10x.c 中定義,是用來配置 GPIOx_BRR(Port bit reset register)這個寄存器的(參考 Ref.Manual 9.2.6)。
    2)這個寄存器只有 0:15 位是有用的,對應將 0-15 個 GPIO 端口拉低(Reset bits),置 1有效。爲什麼不直接配置 GPIOx_BSRR 來拉低呢?因爲 GPIO_Pin_x 這些 uint16_t 的數對應的二進制數正好就是 0-15 第 x 位爲 1。所以如果用 GPIOx_BSRR 寄存器就要去操作 16:31 位,很麻煩,不如直接用 GPIOx_BRR 來操作。

當然除了把 GPIO 做輸出以外,還可以把 GPIO 作爲輸入,進行高低電平的檢測。當把 GPIO 作爲輸入進行高低電平檢測時,絕大部分代碼和上面都是一樣的,只是需要做以下修改:

  1. 配置 GPIO_InitStructure 時將 GPIO_Mode 上拉/下拉輸入:
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;

  2. 當需要讀取 GPIO 某一個 Pin 狀態時:這個函數會返回 uint8_t 的 0或1,表示輸入電平的低或高
    GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5);

  3. 如果是需要讀取某一個 GPIO 上多個 Pin 狀態:這個函數會返回 uint16_t 的結果,對應 GPIOx 上 0~15 個 Pin 上輸入電平。
    GPIO_ReadInputData(GPIOA);

同樣,從寄存器角度來看一下:

  1. GPIO_InitStructure 相關:
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    1) 該寄存器同樣是對應 GPIOx_CRL/GPIOx_CRH (Port configuration register low/high) 寄存器。

  2. GPIO_ReadInput 相關:
    GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5);
    GPIO_ReadInputData(GPIOA);
    1)這兩個函數都是操作 GPIO_IDR(Port input data register)寄存器。該寄存器就是存的 GPIOx 0~15 Port 的輸入電平高低。只是 ReadInputDataBit 函數還會和 GPIO_Pin_x 做與操作,來特定返回這個 GPIO_Pin_x 的輸入電平高低。

以上就是所有關於 GPIO 的基本操作了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章