天天看點

STM32F103固件庫源碼解析——GPIO配置

首先,需要熟悉下一些重要的雜散的知識。

STM32F103固件庫源碼解析——GPIO配置

上圖是一個标準的GPIO配置過程。

GPIO_InitTypeDef是一個結構體,

STM32F103固件庫源碼解析——GPIO配置
STM32F103固件庫源碼解析——GPIO配置

可以看出,CRL寄存器的每4位控制一個GPIO的工作狀态。

STM32F103固件庫源碼解析——GPIO配置

上面的枚舉類型設計得很巧妙,其用低四位代表具體輸入/輸出模式,低四位右移兩位即是對應的寄存器配置,如下:

(GPIO_Mode_AIN & 0X0F) >> 2 = 00B
(GPIO_Mode_Out_PP & 0X0F) >> 2 = 00B
           
STM32F103固件庫源碼解析——GPIO配置
(GPIO_Mode_IN_FLOATING & 0X0F) >> 2 = 01B
(GPIO_Mode_Out_OD & 0X0F) >> 2 = 01B
           
STM32F103固件庫源碼解析——GPIO配置
(GPIO_Mode_IPD & 0X0F) >> 2 = 10B
(GPIO_Mode_IPU & 0X0F) >> 2 = 10B
(GPIO_Mode_AF_PP & 0X0F) >> 2 = 10B
           
STM32F103固件庫源碼解析——GPIO配置

通過上述操作,可以從GPIOMode_TypeDef枚舉類型的變量中得到配置具體輸入、輸出所需要的寄存器參數。

STM32F103固件庫源碼解析——GPIO配置

而之是以将GPIOMode_TypeDef類型變量的低四位後兩位空出來(怎麼看出來後兩位空出來了呢?是因為該變量的低四位是0/4/8/C,後兩位都是0),是為了在程式中與GPIOSpeed_TypeDef類型變量相或,最終得到以4位為機關的CRL/CRH寄存器配置參數。

GPIOMode_TypeDef類型變量的第5位表示輸入還是輸出。

#define GPIO_Pin_0                 ((uint16_t)0x0001)  /*!< Pin 0 selected */
#define GPIO_Pin_1                 ((uint16_t)0x0002)  /*!< Pin 1 selected */
#define GPIO_Pin_2                 ((uint16_t)0x0004)  /*!< Pin 2 selected */
#define GPIO_Pin_3                 ((uint16_t)0x0008)  /*!< Pin 3 selected */
#define GPIO_Pin_4                 ((uint16_t)0x0010)  /*!< Pin 4 selected */
#define GPIO_Pin_5                 ((uint16_t)0x0020)  /*!< Pin 5 selected */
#define GPIO_Pin_6                 ((uint16_t)0x0040)  /*!< Pin 6 selected */
#define GPIO_Pin_7                 ((uint16_t)0x0080)  /*!< Pin 7 selected */
#define GPIO_Pin_8                 ((uint16_t)0x0100)  /*!< Pin 8 selected */
#define GPIO_Pin_9                 ((uint16_t)0x0200)  /*!< Pin 9 selected */
#define GPIO_Pin_10                ((uint16_t)0x0400)  /*!< Pin 10 selected */
#define GPIO_Pin_11                ((uint16_t)0x0800)  /*!< Pin 11 selected */
#define GPIO_Pin_12                ((uint16_t)0x1000)  /*!< Pin 12 selected */
#define GPIO_Pin_13                ((uint16_t)0x2000)  /*!< Pin 13 selected */
#define GPIO_Pin_14                ((uint16_t)0x4000)  /*!< Pin 14 selected */
#define GPIO_Pin_15                ((uint16_t)0x8000)  /*!< Pin 15 selected */
#define GPIO_Pin_All               ((uint16_t)0xFFFF)  /*!< All pins selected */
           

以上是GPIO_Pin的宏定義。

下面是GPIO_Init函數的詳細注釋,

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
{
  uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;
  uint32_t tmpreg = 0x00, pinmask = 0x00;
  /* Check the parameters */
  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
  assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode));
  assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin));  
  
/*---------------------------- GPIO Mode Configuration -----------------------*/
  //此處隻取 GPIO_Mode 的低四位,GPIO_Mode 低四位代表了輸入或輸出的具體模式
  currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F);
  if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)//在這裡擷取GPIO的工作速度  是以GPIO_Mode的第5位代表了是輸入還是輸出,判斷為輸出時才設定工作速度
  { 
    //GPIO_Mode第5位為1,說明是輸出模式,現在設定工作速度
    /* Check the parameters */
    assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed));
    /* Output mode */
    //在此,currentmode已經是可以寫入的寄存器參數了
    currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;
  }
/*---------------------------- GPIO CRL Configuration ------------------------*/
  /* Configure the eight low port pins */
  //下面确定currentmode具體寫入到哪一個GPIO口的配置位中
  if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)//判斷需要設定的GPIO是不是0-7
  {
    tmpreg = GPIOx->CRL;//将CRL寄存器值讀出
    for (pinpos = 0x00; pinpos < 0x08; pinpos++)
    {
      pos = ((uint32_t)0x01) << pinpos;
      /* Get the port pins position */
      currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;//  得到目前正在配置的Pin  并且確定本次操作隻有一個Pin需要配置
      if (currentpin == pos)
      {
        pos = pinpos << 2;//右移兩位相當于位數乘4,每一個GPIO口的配置占位4個,是以GPIO n的最低配置位就是 nx4
        /* Clear the corresponding low control register bits */
        pinmask = ((uint32_t)0x0F) << pos;//擷取對應配置位的掩碼
        tmpreg &= ~pinmask;//清除對應配置位
        /* Write the mode configuration in the corresponding bits */
        tmpreg |= (currentmode << pos);//将currentmode寫入臨時寄存器值中
        /* Reset the corresponding ODR bit */
        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
        {
          GPIOx->BRR = (((uint32_t)0x01) << pinpos);
        }
        else
        {
          /* Set the corresponding ODR bit */
          if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
          {
            GPIOx->BSRR = (((uint32_t)0x01) << pinpos);
          }
        }
      }
    }
    GPIOx->CRL = tmpreg;//更新寄存器值
  }
/*---------------------------- GPIO CRH Configuration ------------------------*/
  /* Configure the eight high port pins */
  if (GPIO_InitStruct->GPIO_Pin > 0x00FF)//判斷需要配置的腳是否大于7
  {
    tmpreg = GPIOx->CRH;
    for (pinpos = 0x00; pinpos < 0x08; pinpos++)
    {
      pos = (((uint32_t)0x01) << (pinpos + 0x08));
      /* Get the port pins position */
      currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos);
      if (currentpin == pos)
      {
        pos = pinpos << 2;
        /* Clear the corresponding high control register bits */
        pinmask = ((uint32_t)0x0F) << pos;
        tmpreg &= ~pinmask;
        /* Write the mode configuration in the corresponding bits */
        tmpreg |= (currentmode << pos);
        /* Reset the corresponding ODR bit */
        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
        {
          GPIOx->BRR = (((uint32_t)0x01) << (pinpos + 0x08));
        }
        /* Set the corresponding ODR bit */
        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
        {
          GPIOx->BSRR = (((uint32_t)0x01) << (pinpos + 0x08));
        }
      }
    }
    GPIOx->CRH = tmpreg;
  }
}