你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32F103固件库源码解析——GPIO配置

[复制链接]
STMCU小助手 发布时间:2022-5-2 09:23
首先,需要熟悉下一些重要的杂散的知识。

20210206141642133.png

上图是一个标准的GPIO配置过程。

GPIO_InitTypeDef是一个结构体,

20210206141658208.png

20210206141710961.png

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

20210206141725790.png

上面的枚举类型设计得很巧妙,其用低四位代表具体输入/输出模式,低四位右移两位即是对应的寄存器配置,如下:

  1. (GPIO_Mode_AIN & 0X0F) >> 2 = 00B
  2. (GPIO_Mode_Out_PP & 0X0F) >> 2 = 00B
复制代码

JI8DXY_B]))3TWOV]51CFM1.png

  1. (GPIO_Mode_IN_FLOATING & 0X0F) >> 2 = 01B
  2. (GPIO_Mode_Out_OD & 0X0F) >> 2 = 01B
复制代码


LRYCHR@~}RYR3)J840Z[JSF.png

  1. (GPIO_Mode_IPD & 0X0F) >> 2 = 10B
  2. (GPIO_Mode_IPU & 0X0F) >> 2 = 10B
  3. (GPIO_Mode_AF_PP & 0X0F) >> 2 = 10B
复制代码

`KY64`M8V}S}WUKVQ_KU4JO.png

通过上述操作,可以从GPIOMode_TypeDef枚举类型的变量中得到配置具体输入、输出所需要的寄存器参数。

ZTIC[APjTIC4SNGRR6W.png

而之所以将GPIOMode_TypeDef类型变量的低四位后两位空出来(怎么看出来后两位空出来了呢?是因为该变量的低四位是0/4/8/C,后两位都是0),是为了在程序中与GPIOSpeed_TypeDef类型变量相或,最终得到以4位为单位的CRL/CRH寄存器配置参数。

GPIOMode_TypeDef类型变量的第5位表示输入还是输出。

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

以上是GPIO_Pin的宏定义。

下面是GPIO_Init函数的详细注释,

  1. void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
  2. {
  3.   uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;
  4.   uint32_t tmpreg = 0x00, pinmask = 0x00;
  5.   /* Check the parameters */
  6.   assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
  7.   assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode));
  8.   assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin));  

  9. /*---------------------------- GPIO Mode Configuration -----------------------*/
  10.   //此处只取 GPIO_Mode 的低四位,GPIO_Mode 低四位代表了输入或输出的具体模式
  11.   currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F);
  12.   if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)//在这里获取GPIO的工作速度  因此GPIO_Mode的第5位代表了是输入还是输出,判断为输出时才设定工作速度
  13.   {
  14.     //GPIO_Mode第5位为1,说明是输出模式,现在设置工作速度
  15.     /* Check the parameters */
  16.     assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed));
  17.     /* Output mode */
  18.     //在此,currentmode已经是可以写入的寄存器参数了
  19.     currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;
  20.   }
  21. /*---------------------------- GPIO CRL Configuration ------------------------*/
  22.   /* Configure the eight low port pins */
  23.   //下面确定currentmode具体写入到哪一个GPIO口的配置位中
  24.   if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)//判断需要设置的GPIO是不是0-7
  25.   {
  26.     tmpreg = GPIOx->CRL;//将CRL寄存器值读出
  27.     for (pinpos = 0x00; pinpos < 0x08; pinpos++)
  28.     {
  29.       pos = ((uint32_t)0x01) << pinpos;
  30.       /* Get the port pins position */
  31.       currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;//  得到当前正在配置的Pin  并且确保本次操作只有一个Pin需要配置
  32.       if (currentpin == pos)
  33.       {
  34.         pos = pinpos << 2;//右移两位相当于位数乘4,每一个GPIO口的配置占位4个,所以GPIO n的最低配置位就是 nx4
  35.         /* Clear the corresponding low control register bits */
  36.         pinmask = ((uint32_t)0x0F) << pos;//获取对应配置位的掩码
  37.         tmpreg &= ~pinmask;//清除对应配置位
  38.         /* Write the mode configuration in the corresponding bits */
  39.         tmpreg |= (currentmode << pos);//将currentmode写入临时寄存器值中
  40.         /* Reset the corresponding ODR bit */
  41.         if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
  42.         {
  43.           GPIOx->BRR = (((uint32_t)0x01) << pinpos);
  44.         }
  45.         else
  46.         {
  47.           /* Set the corresponding ODR bit */
  48.           if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
  49.           {
  50.             GPIOx->BSRR = (((uint32_t)0x01) << pinpos);
  51.           }
  52.         }
  53.       }
  54.     }
  55.     GPIOx->CRL = tmpreg;//更新寄存器值
  56.   }
  57. /*---------------------------- GPIO CRH Configuration ------------------------*/
  58.   /* Configure the eight high port pins */
  59.   if (GPIO_InitStruct->GPIO_Pin > 0x00FF)//判断需要配置的脚是否大于7
  60.   {
  61.     tmpreg = GPIOx->CRH;
  62.     for (pinpos = 0x00; pinpos < 0x08; pinpos++)
  63.     {
  64.       pos = (((uint32_t)0x01) << (pinpos + 0x08));
  65.       /* Get the port pins position */
  66.       currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos);
  67.       if (currentpin == pos)
  68.       {
  69.         pos = pinpos << 2;
  70.         /* Clear the corresponding high control register bits */
  71.         pinmask = ((uint32_t)0x0F) << pos;
  72.         tmpreg &= ~pinmask;
  73.         /* Write the mode configuration in the corresponding bits */
  74.         tmpreg |= (currentmode << pos);
  75.         /* Reset the corresponding ODR bit */
  76.         if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
  77.         {
  78.           GPIOx->BRR = (((uint32_t)0x01) << (pinpos + 0x08));
  79.         }
  80.         /* Set the corresponding ODR bit */
  81.         if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
  82.         {
  83.           GPIOx->BSRR = (((uint32_t)0x01) << (pinpos + 0x08));
  84.         }
  85.       }
  86.     }
  87.     GPIOx->CRH = tmpreg;
  88.   }
  89. }

复制代码

收藏 评论0 发布时间:2022-5-2 09:23

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版