SevenZ的笔记 https://passport2.21ic.com/?747229 [收藏] [复制] [RSS]

日志

STM32学习笔记--GPIO的初始化(GPIO_Init)

已有 2728 次阅读2011-9-19 03:33 |系统分类:ARM| GPIO, arm的GPIO口配置, GPIO模式设置

        昨天在想熟悉一下TFT的操作,发现其中提到对I/O口的位带操作,我小试牛刀,发现其中对I/O口的配置不是很清楚,所以我进一步了解了一下一般情况下用固件库函数对I/O口模式的设置,方便其和I/O位带操作进行一个比较。


      以下是整个部分,我对其中的注释翻译过来并加入了自己的了解,用到的资料为:



     (文中称资料A)STM32F10xx固件函数库(2.1.0版本)


     (文中称资料B)STM32F10x微控制器参考手册(2009年12月第10版) 、


     (文中称资料C)Cortex-M3权威指南CnR2(电子书)


       方便大家查找 。


       对GPIO_Init的设置实主要是对CRL /CRH/BRR/ODR/ 这几个寄存器的设置。设置过程:


     1、对输入的参数GPIO_InitStruct的引脚还原


         2、对对应位引脚设置,分为设置模式,设置频率 


                                                   每个引脚设置CNF[1:0],MODE[1:0]四位


void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)  


                                          //调用初始化函数要求输入参量GPIO地址指针及结构体GPIO的地址指针


{


 


  uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;


  uint32_t tmpreg = 0x00, pinmask = 0x00;


 


  /* Check the parameters  下面是检查是否超出该值取值范围,参见资料A P36 */


  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 模式配置-----------------------*/


 



/* 下面是所有模式的设定值


typedef enum


{


       GPIO_Mode_AIN = 0x0,


       GPIO_Mode_IN_FLOATING = 0x04,


       GPIO_Mode_IPD = 0x28,


       GPIO_Mode_IPU = 0x48,


       GPIO_Mode_Out_OD = 0x14,                            //讲解为什么输出模式中几个值这么设定0x1-表示为输入


       GPIO_Mode_Out_PP = 0x10,                             //展开4个位分别为:00010000 B           --->0x10                 后4位的第1、2位表示模式,最后两位表示频率,


       GPIO_Mode_AF_OD = 0x1C,                              //                                      00010100B           --->0x14                 这里最后两位全部为0表示保留。


       GPIO_Mode_AF_PP = 0x18                                //                                      00011000B           --->0x18                 参见资料B    P106 表17


}GPIOMode_TypeDef;                                                //                                      00011100B           --->0x1C


*/


 


  currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F);


                                    //当我们调用GPIO_Init的时候引入参量GPIO_InitStruct,其中GPIO_InitStruct->Mode


                                    //中的模式为上面GPIOMode_TypeDef中的一种,和0x0F相与表示取相应模式的值


 


if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)       


                                    // 计算结果若为0x0- ,则和(uint32_t)0x10相与后为0,对应的为输入


                                    //                       若为0x2/4/1-,当和(uint32_t)0x10相与后不为0对应为输出


                                    //                       若为输出模式进行下面的设置,为currentmode加上频率                                   


 


 


    /* Check the parameters  同上,检查是否超出设定值范围*/


    assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed));


 


 


 


/* Output mode   输出模式*/




/* 速度有3种模式,依次为123 ---0x…01,0x…02,0x…03


typedef enum


{


  GPIO_Speed_10MHz = 1,


  GPIO_Speed_2MHz,    


  GPIO_Speed_50MHz  


}GPIOSpeed_TypeDef;


*/


 


currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;


                           //对应输出模式加上输出频率值,一会用于写入控制寄存器(CR-)中


  }


 


 


/*---------------------------- GPIO CRL Configuration 对CRL的配置------------------------*/


  /* Configure the eight low port pins  配置低8 */


                                       //main函数中有:


                                       // GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_x | GPIO_Pin_x | GPIO_Pin_x | GPIO_Pin_x ;


                                       // 如:


                                       //GPIO_Pin_8 = 0x0100   GPIO_Pin_8 = 0x0200


                                       // GPIO_Pin_8 = 0x0400   GPIO_Pin_8 = 0x0800


                                        //当它们相或得0x0F00


 


  if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)


                                       //分析上面的过程可得下面的if语句是否执行,若跳过不执行转到高8位执行即对CRH设置


                                       //若满足则执行下面语句


 {


    tmpreg = GPIOx->CRL;                          


                                      //暂存CRL的值到tmpreg


   


    for (pinpos = 0x00; pinpos < 0x08; pinpos++)         //position 0~7位配置


    {


  


      pos = ((uint32_t)0x01) << pinpos;                           //地址位左移相应pinpos位数,用于取得需要设置的对应位


      /* Get the port pins position   取得端口脚的位置*/


      currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;//0x01由上面左移相应位得到pos


                                                                                              //刚刚在选取引脚的时候不是用了一个或选取引脚吗


                                                                                              //就是   GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_x | GPIO_Pin_x |


                                                                                              // 然后把它pos相与还原对应位分别得到低端的0~7


 


 


      if (currentpin == pos)                                                  //判断上面被还原位是否被选中,原理是当该位选中时条件就成立,否currentpin值为0条件不会为真


      {


                  


        //以下是设置pinpos对应位的模式,如pinpos0x00,则表示对第零位设置


        pos = pinpos << 2;                                                      // pinpos左移2位表示对CNF[1:0]设置,参见资料B P113


       


       /* Clear the corresponding low control register bits    清除CRL中对应位*/


        pinmask = ((uint32_t)0x0F) << pos;


        tmpreg &= ~pinmask;                                                 //tmpreg暂存CRL的值,pinmask取反并与CRL值相与表示


                                //屏蔽对应位的值,达到清除对应位


 


        /* Write the mode configuration in the corresponding bits   写入当前位的模式值*/


        tmpreg |= (currentmode << pos);                             //写入对应位的模式设置,current表示当前的意思,在前面对模式的值有了一个提取,保存在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;                                                   //最后8位都配置完成后写入CRL


  }


 


 


/*---------------------------- GPIO CRH Configuration ------------------------*/


//CRH的设置,和CRL的配置一个原理


  /* Configure the eight high port pins */


  if (GPIO_InitStruct->GPIO_Pin > 0x00FF)


  {


    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;


  }


}


 


路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)