STM32學習筆記——GPIO


單片機型號STM32F407VET6。

概述

GPIO的分類:

  • 可接受5V輸入的(FT),絕大多數引腳都是;

  • 只能接受3.3V輸入的(TTa),只有PA4PA5,就是DAC輸出的兩個引腳;

  • 其他,包括BOOT0NRST這兩個特殊功能的引腳。

GPIO不僅可以用作GPIO,每個GPIO都有復用功能(alternate function,AF)和附加功能(additional function),AF用GPIOx_AFR來配置,附加功能用外設中的寄存器。

一組GPIO為16個,從Px0Px15xAI,有些封裝上有些引腳不存在。

GPIO的功能主要有4類:

  • 輸出,推挽(push-pull,PP)或開漏(open-drain,OD),可選上拉(pull-up,PU)或下拉(pull-down,PD),4檔速度;

  • AF,細節同上;

  • 輸入,可選上拉或下拉;

  • 模擬,用於ADC和DAC。

HAL

HAL把外部中斷也歸到了GPIO中,這里暫且不涉及外部中斷。

初始化這種事情我都交給STM32CubeMX來完成(STM32CubeIDE內置)。我已經初步領略到HAL的設計思想,以后專門開一篇寫。

GPIO有以下函數:

  • HAL_GPIO_Init():初始化一組GPIO中的一個或多個;

  • HAL_GPIO_DeInit():把一組GPIO中的一個或多個還原為復位狀態;

  • HAL_GPIO_ReadPin():讀引腳電平,返回GPIO_PinState枚舉類型,可能值為GPIO_PIN_RESET = 0GPIO_PIN_SET = 1

  • HAL_GPIO_WritePin():寫引腳電平,是原子操作,允許中斷發生;

  • HAL_GPIO_TogglePin():翻轉引腳電平;

  • HAL_GPIO_LockPin():鎖定引腳配置,在復位前不可修改,引腳電平還可以寫。

#include "main.h"
#include <stdbool.h>
int main(void)
{
  bool prev = true;
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  while (1)
  {
    if (HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin) == GPIO_PIN_RESET)
      HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_RESET);
    else
      HAL_GPIO_WritePin(LED0_GPIO_Port, LED0_Pin, GPIO_PIN_SET);
    bool now = HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_RESET;
    if (!prev && now)
      HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
    prev = now;
    HAL_Delay(1);
  }
}

(STM32CubeMX生成的代碼是兩格縮進的,這讓我非常不爽!)

LED0LED1分別連接到PA6PA7,低電平亮;KEY0KEY1分別連接到PE4PE3,上拉。程序的功能為:KEY0按下時LED0亮,松開熄滅;KEY1按下時切換LED1的亮暗狀態。

寄存器

每一組GPIO都有10個寄存器:

  • GPIOx_MODER,32位,2位MODERy[1:0]一組(y015,下同),設置GPIO模式;

  • GPIOx_OTYPER,16位,1位OTy一組,設置GPIO輸出類型;

  • GPIOx_OSPEEDR,32位OSPEEDRy[1:0],設置GPIO輸出速度;

  • GPIOx_PUPDR,32位PUPDRy[1:0],設置上拉下拉;

  • GPIOx_IDR,16位IDRy,讀取輸入電平;

  • GPIOx_ODR,16位ODRy,設置輸出電平;

  • GPIOx_BSRR,低16位BSy,寫1GPIOx_ODR中對應位置1;高16位BRy,寫1GPIOx_ODR中對應位清0;同時寫1BSy優先;

  • GPIOx_LCKR:低16為LCKy,第16位LCKK,需要一個特定的寫入過程(參考datasheet或HAL_GPIO_LockPin實現),可以鎖定GPIOx_MODERGPIOx_OTYPERGPIOx_OSPEEDRGPIOx_PUPDRGPIOx_AFRLGPIOx_AFRH這6個控制寄存器中的對應位;

  • GPIOx_AFRLGPIOx_AFRH,4位AFRHy[3:0]為一組,設置復用輸出。

GPIO的輸出級有一個NMOS和一個PMOS:

  • 在推挽輸出模式下,ODRx0,NMOS導通;ODRx1,PMOS導通;

  • 在開漏輸出模式下,ODRx0,NMOS導通;ODRx1,高阻態;PMOS都不會導通。

開漏輸出的應用有矩陣鍵盤和I²C等,需要上拉電阻,通常用內置的即可。

用寄存器重寫上面的程序:

#include "main.h"
#include <stdbool.h>

#define LED0_Bit 6
#define LED1_Bit 7
#define KEY0_Bit 4
#define KEY1_Bit 3

int main(void)
{
  bool prev = true;
  HAL_Init();
  SystemClock_Config();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  LED0_GPIO_Port->ODR |= 1 << LED0_Bit;
  LED0_GPIO_Port->MODER |= 0b01 << (LED0_Bit * 2);
  LED1_GPIO_Port->ODR |= 1 << LED1_Bit;
  LED1_GPIO_Port->MODER |= 0b01 << (LED1_Bit * 2);
  __HAL_RCC_GPIOE_CLK_ENABLE();
  KEY0_GPIO_Port->PUPDR |= 0b01 << (KEY0_Bit * 2);
  KEY1_GPIO_Port->PUPDR |= 0b01 << (KEY1_Bit * 2);
  while (1)
  {
    if (!(KEY0_GPIO_Port->IDR & 1 << KEY0_Bit))
      LED0_GPIO_Port->BSRR = 1 << (16 + LED0_Bit);
    else
      LED0_GPIO_Port->BSRR = 1 << LED0_Bit;
    bool now = !(KEY1_GPIO_Port->IDR & 1 << KEY1_Bit);
    if (!prev && now)
      LED1_GPIO_Port->ODR ^= 1 << LED1_Bit;
    prev = now;
    HAL_Delay(1);
  }
}

只把GPIO相關的改成了寄存器操作,時鍾之類的還是用的HAL。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM