zoukankan      html  css  js  c++  java
  • GPIO的库函数

     

    1 void GPIO_DeInit(GPIO_TypeDef* GPIOx)

    这个函数调用了rcc.c里面的RCC_AHB1PeriphResetCmd,对外设端口进行复位,最终操作的是RCC_AHB1RSTR和RCC_AHB2RSTR,这样操作后,使端口寄存器恢复默认值
    void GPIO_DeInit(GPIO_TypeDef* GPIOx)
    {
      /* Check the parameters */
      assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    
      if (GPIOx == GPIOA)
      {
        RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_GPIOA, ENABLE); //复位端口
        RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_GPIOA, DISABLE);//不复位
      }
      else if (GPIOx == GPIOB)
      {
        RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_GPIOB, ENABLE);
        RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_GPIOB, DISABLE);
      }
      else if (GPIOx == GPIOC)
      {
        RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_GPIOC, ENABLE);
        RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_GPIOC, DISABLE);
      }
      else if (GPIOx == GPIOD)
      {
        RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_GPIOD, ENABLE);
        RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_GPIOD, DISABLE);
      }
      else if (GPIOx == GPIOE)
      {
        RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_GPIOE, ENABLE);
        RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_GPIOE, DISABLE);
      }
      else if (GPIOx == GPIOF)
      {
        RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_GPIOF, ENABLE);
        RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_GPIOF, DISABLE);
      }
      else if (GPIOx == GPIOG)
      {
        RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_GPIOG, ENABLE);
        RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_GPIOG, DISABLE);
      }
      else if (GPIOx == GPIOH)
      {
        RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_GPIOH, ENABLE);
        RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_GPIOH, DISABLE);
      }
    
      else if (GPIOx == GPIOI)
      {
        RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_GPIOI, ENABLE);
        RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_GPIOI, DISABLE);
      }
      else if (GPIOx == GPIOJ)
      {
        RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_GPIOJ, ENABLE);
        RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_GPIOJ, DISABLE);
      }
      else
      {
        if (GPIOx == GPIOK)
        {
          RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_GPIOK, ENABLE);
          RCC_AHB1PeriphResetCmd(RCC_AHB1Periph_GPIOK, DISABLE);
        }
      }
    }

    2  这个函数传入的参数是GPIO_TypeDef和GPIO_InitStruct,GPIO_TypeDef是一个数组,包含了所有GPIO相关的寄存器。GPIO_InitTypeDef也是一个数组,包含了对GPIO的具体配置选项,比如输入输出选择等等。

    void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
    {
      uint32_t pinpos = 0x00, pos = 0x00 , currentpin = 0x00;
      // 参数检查
      assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
      assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin));
      assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode));
      assert_param(IS_GPIO_PUPD(GPIO_InitStruct->GPIO_PuPd));
    
      for (pinpos = 0x00; pinpos < 0x10; pinpos++) //从第0个pin开始扫描要赋值哪个pin
      {
        pos = ((uint32_t)0x01) << pinpos;
        /* Get the port pins position */
        currentpin = (GPIO_InitStruct->GPIO_Pin) & pos; //GPIO_InitStruct->GPIO_Pin会确定GPIOX端口中具体哪个管脚被初始化
    
        if (currentpin == pos) //扫描到了需要初始化的管脚,进行配置
        { //现在GPIOX是一个指向GPIO_TypeDef的指针,那么GPIO->就是在操作moder寄存器
          GPIOx->MODER  &= ~(GPIO_MODER_MODER0 << (pinpos * 2)); // 把这个要配置的pin对于的moder寄存器的两位清零
          GPIOx->MODER |= (((uint32_t)GPIO_InitStruct->GPIO_Mode) << (pinpos * 2));//把相应的配置写入寄存器
    
          if ((GPIO_InitStruct->GPIO_Mode == GPIO_Mode_OUT) || (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_AF))//如果配置成输出或者复用,才需要配置速度
          {
            /* Check Speed mode parameters */
            assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed));
    
            /* Speed mode configuration */
            GPIOx->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEEDR0 << (pinpos * 2)); //这里和moder寄存器的配置是一样的
            GPIOx->OSPEEDR |= ((uint32_t)(GPIO_InitStruct->GPIO_Speed) << (pinpos * 2));
    
            /* Check Output mode parameters */
            assert_param(IS_GPIO_OTYPE(GPIO_InitStruct->GPIO_OType));
    
            /* Output mode configuration*/
            GPIOx->OTYPER  &= ~((GPIO_OTYPER_OT_0) << ((uint16_t)pinpos)) ;
            GPIOx->OTYPER |= (uint16_t)(((uint16_t)GPIO_InitStruct->GPIO_OType) << ((uint16_t)pinpos));
               //配置输出或者推挽,一个bit对应一个pin,所以不需要pinpos*2
          }
    
          /* Pull-up Pull down resistor configuration*/
          GPIOx->PUPDR &= ~(GPIO_PUPDR_PUPDR0 << ((uint16_t)pinpos * 2));
          GPIOx->PUPDR |= (((uint32_t)GPIO_InitStruct->GPIO_PuPd) << (pinpos * 2)); // 配置上下拉
        }
      }
    }

    这个函数的调用方法如下所示:

    void myGPIO_Init(void)
    {         
      GPIO_InitTypeDef  GPIO_InitStructure;
    
      RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);//使能F端口的时钟//GPIOF9,F10初始化
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;//选择需要配置的管脚。GPIO_Pin_9的值被定义成0x0200
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;// 配置成输出
      GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;// 配置成push-pull
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
      GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//配置成上拉
      GPIO_Init(GPIOF, &GPIO_InitStructure);// 调用上面这个初始化函数
    
    }

    以上有很多例如:GPIO_Pin_9 ,GPIO_Mode_OUT,都是定义在stm32f4xx_gpio.h的枚举类的值。以上这个函数,把各种值赋给GPIO_InitTypeDef类型的GPIO_InitStructure数组,然后调用GPIO_Init这个函数,把这些设置写入寄存器。GPIOF是F端口的寄存器基地址。

    3.void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct)

    这个函数和上面这个调用类似,是把这些GPIO寄存器恢复默认值

    void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct)
    {
      /* Reset GPIO init structure parameters values */
      GPIO_InitStruct->GPIO_Pin  = GPIO_Pin_All;
      GPIO_InitStruct->GPIO_Mode = GPIO_Mode_IN;
      GPIO_InitStruct->GPIO_Speed = GPIO_Speed_2MHz;
      GPIO_InitStruct->GPIO_OType = GPIO_OType_PP;
      GPIO_InitStruct->GPIO_PuPd = GPIO_PuPd_NOPULL;
    }

    4.void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)

    端口配置锁定寄存器,传入的参数的哪个端口,哪个管脚,具体见GPIOx_LCKR寄存器。是用来锁定管脚的配置,这个寄存器低16位是具体某个管脚的锁定使能。LCKK管脚是总的锁定激活。这里的5步操作,在手册中是由规定的:“锁定键写序列”

    void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
    {
      __IO uint32_t tmp = 0x00010000;
    
      /* Check the parameters */
      assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
      assert_param(IS_GPIO_PIN(GPIO_Pin));
    
      tmp |= GPIO_Pin;
      /* Set LCKK bit */
      GPIOx->LCKR = tmp;
      /* Reset LCKK bit */
      GPIOx->LCKR =  GPIO_Pin;
      /* Set LCKK bit */
      GPIOx->LCKR = tmp;
      /* Read LCKK bit*/
      tmp = GPIOx->LCKR;
      /* Read LCKK bit*/
      tmp = GPIOx->LCKR;
    }

     5. uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)

       这个函数其实是读IDR寄存器,即管脚的输入值

    uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
    {
      uint8_t bitstatus = 0x00;
    
      /* Check the parameters */
      assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
      assert_param(IS_GET_GPIO_PIN(GPIO_Pin));
    
      if ((GPIOx->IDR & GPIO_Pin) != (uint32_t)Bit_RESET) //IDR寄存器中,需要读的这个管脚如果不是0
      {
        bitstatus = (uint8_t)Bit_SET;
      }
      else
      {
        bitstatus = (uint8_t)Bit_RESET;
      }
      return bitstatus;
    }

    6、uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx)

     这个函数是读16比特

    uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx)
    {
      /* Check the parameters */
      assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    
      return ((uint16_t)GPIOx->IDR);
    }

    7、uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)

    这个函数是读ODR寄存器,即输出的值,可以看GPIO的结构,输出也是可以读的。

    uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
    {
      uint8_t bitstatus = 0x00;
    
      /* Check the parameters */
      assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
      assert_param(IS_GET_GPIO_PIN(GPIO_Pin));
    
      if (((GPIOx->ODR) & GPIO_Pin) != (uint32_t)Bit_RESET)
      {
        bitstatus = (uint8_t)Bit_SET;
      }
      else
      {
        bitstatus = (uint8_t)Bit_RESET;
      }
      return bitstatus;

    8、uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx)

    类似,这里读16比特

    uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx)
    {
      /* Check the parameters */
      assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    
      return ((uint16_t)GPIOx->ODR);
    }

    9、void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)

    写1

    void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
    {
      /* Check the parameters */
      assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
      assert_param(IS_GPIO_PIN(GPIO_Pin));
    
      GPIOx->BSRRL = GPIO_Pin;
    }

    10、void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)

    写0

    void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
    {
      /* Check the parameters */
      assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
      assert_param(IS_GPIO_PIN(GPIO_Pin));
    
      GPIOx->BSRRH = GPIO_Pin;
    }

    11、void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal)

    把GPIO的某一位写0或者写1

    void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal)
    {
      /* Check the parameters */
      assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
      assert_param(IS_GET_GPIO_PIN(GPIO_Pin));
      assert_param(IS_GPIO_BIT_ACTION(BitVal));
    
      if (BitVal != Bit_RESET)
      {
        GPIOx->BSRRL = GPIO_Pin;
      }
      else
      {
        GPIOx->BSRRH = GPIO_Pin ;
      }
    }

    12、void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal)

    对某个端口16位赋值

    void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal)
    {
      /* Check the parameters */
      assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    
      GPIOx->ODR = PortVal;
    }

    13、void GPIO_ToggleBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)

    对某个端口的值进行取反

    void GPIO_ToggleBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
    {
      /* Check the parameters */
      assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
    
      GPIOx->ODR ^= GPIO_Pin;
    }

    14、void GPIO_PinAFConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinSource, uint8_t GPIO_AF)

    配置GPIO的复用功能,具体见AFRL和AFRH寄存器

    void GPIO_PinAFConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinSource, uint8_t GPIO_AF)
    {
      uint32_t temp = 0x00;
      uint32_t temp_2 = 0x00;
      
      /* Check the parameters */
      assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
      assert_param(IS_GPIO_PIN_SOURCE(GPIO_PinSource));
      assert_param(IS_GPIO_AF(GPIO_AF));
      //每个管脚的AF配置,在寄存器中都占了4位
      temp = ((uint32_t)(GPIO_AF) << ((uint32_t)((uint32_t)GPIO_PinSource & (uint32_t)0x07) * 4)) ;//表示移到这两个寄存器中的哪个4位
      GPIOx->AFR[GPIO_PinSource >> 0x03] &= ~((uint32_t)0xF << ((uint32_t)((uint32_t)GPIO_PinSource & (uint32_t)0x07) * 4)) ;//先清零
    //AFR有两个寄存器,AFR[GPIO-PinSource>>0x03]确定哪个寄存器

    temp_2 = GPIOx->AFR[GPIO_PinSource >> 0x03] | temp; //把寄存器中需要赋值的几个bit赋值
    GPIOx
    ->AFR[GPIO_PinSource >> 0x03] = temp_2; //写入需要的值
    }

    调用方式如下:

    GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1)
    GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1)

    不是所有的管脚,可以复用成任意的管脚,PA9和PA10有如下说明。可以看到PA9和USART1_TX,PA10是USART1_RX。

    PA9:TIM1_CH2, USART1_TX,LCD_COM1, TIM15_BKIN,EVENTOU
    PA10:TIM1_CH3, USART1_RX,OTG_FS_ID, LCD_COM2,TIM17_BKIN, EVENTOUT

    另外还需要说明的是,这几个接口,定义的AF的配置都是7,都是一样的。但是某个管脚是限定成哪个接口的,所以不会搞错。即把PA9和PA10的AF配置成7.是不会映射到USART2去的。同时,不同的USART对应不同的寄存器偏移地址。

    #define GPIO_AF_USART1         ((uint8_t)0x07)  /* USART1 Alternate Function mapping  */
    #define GPIO_AF_USART2         ((uint8_t)0x07)  /* USART2 Alternate Function mapping  */
    #define GPIO_AF_USART3         ((uint8_t)0x07)  /* USART3 Alternate Function mapping  */
    #define GPIO_AF7_SPI3          ((uint8_t)0x07)  /* SPI3/I2S3ext Alternate Function mapping */




     

  • 相关阅读:
    图片加载框架之Glide和Picasso
    图片加载框架之fresco
    图片加载框架之ImageLoader
    依赖注入框架之androidannotations
    依赖注入框架之butterknife
    Android依赖注入框架之Dagger2
    EvenBus源码分析
    时间总线框架之EvenBus
    数据库开源框架之litepal
    数据库开源框架之sqlcipher加密数据库
  • 原文地址:https://www.cnblogs.com/nasduc/p/4685236.html
Copyright © 2011-2022 走看看