zoukankan      html  css  js  c++  java
  • STM32F407VET6 底层驱动之GPIO寄存器封装

      在项目中为了使项目底层驱动更稳定,效率更高,接口更简洁,同时将项目的应用层和底层彻底的切断耦合关系,因此直接操作GPIO寄存器,并封装成固定的接口给项目使用。在以后无论使用什么单片机,只要底层的接口不变那么项目的上层代码可直接移植使用,无需做任何修改。

    1、GPIO封装的接口如下:

      a、引脚复用设置:unsigned int gpio_af_config(eGpioType_t gpio, ePinType_t pin, eGpioAfType_t af)

      b、引脚功能设置:unsigned int gpio_config(eGpioType_t gpio, ePinType_t pin, eGpioModeType_t mode, unsigned char level)

      c、引脚输出电平设置:unsigned int gpio_set_pin(eGpioType_t gpio, ePinType_t pin, unsigned char level)

      d、引脚输入电平读取:unsigned char gpio_read_pin(eGpioType_t gpio, ePinType_t pin)

      e、端口输出电平设置:unsigned int gpio_set_port(eGpioType_t gpio, unsigned int level)

      f、端口输入电平读取:unsigned int gpio_read_port(eGpioType_t gpio)

      g、引脚输出电平翻转:void gpio_out_reversal(eGpioType_t gpio, ePinType_t pin)

    2、和引脚相关的枚举类型如下(目的是为了将项目上层代码与底层驱动彻底的断开耦合):

    // GPIO端口类型
    typedef enum _eGpioType
    {
       eGPIOA,
       eGPIOB,
       eGPIOC,
       eGPIOD,
       eGPIOE,
       eGPIOF,
       eGPIOG,
       eGPIOH,
       eGPIOI,
    }eGpioType_t;

    // GPIO引脚类型
    typedef enum _ePinType
    {
       ePIN0 = 0x0001,
       ePIN1 = 0x0002,
       ePIN2 = 0x0004,
       ePIN3 = 0x0008,
       ePIN4 = 0x0010,
       ePIN5 = 0x0020,
       ePIN6 = 0x0040,
       ePIN7 = 0x0080,
       ePIN8 = 0x0100,
       ePIN9 = 0x0200,
       ePIN10 = 0x0400,
       ePIN11 = 0x0800,
       ePIN12 = 0x1000,
       ePIN13 = 0x2000,
       ePIN14 = 0x4000,
       ePIN15 = 0x8000,
       ePIN_ALL = 0xFFFF,
    }ePinType_t;

    // GPIO输入输出类型
    typedef enum _eGpioModeType
    {
       // 系统上电默认为输入模式
       eGPIO_AN, // 模拟输入
       eGPIO_AF_UP, // 复用功能、上拉
       eGPIO_AF_DP, // 复用功能、下拉
       eGPIO_AF_NP, // 复用功能、无上下拉
       eGPIO_IN_UP, // 普通上拉输入
       eGPIO_IN_DP, // 普通下拉输入
       eGPIO_IN_NP, // 普通输入无上下拉
       eGPIO_OUT_PP_UP, // 上拉、推挽、输出
       eGPIO_OUT_PP_DP, // 下拉、推挽、输出
       eGPIO_OUT_PP_NP, // 无上下拉、推挽、输出
       eGPIO_OUT_OD_UP, // 上拉、开漏、输出
       eGPIO_OUT_OD_DP, // 下拉、开漏、输出
       eGPIO_OUT_OD_NP, // 无上下拉、开漏、输出
    }eGpioModeType_t;

    // GPIO引脚复用类型
    typedef enum _eGpioAfType
    {
       eGPIO_AF_RTC_50Hz = 0, // RTC_50Hz Alternate Function mapping
       eGPIO_AF_MCO = 0, // MCO (MCO1 and MCO2) Alternate Function mapping
       eGPIO_AF_TAMPER = 0, // TAMPER (TAMPER_1 and TAMPER_2) Alternate Function mapping
       eGPIO_AF_SWJ = 0, // SWJ (SWD and JTAG) Alternate Function mapping
       eGPIO_AF_TRACE = 0, // TRACE Alternate Function mapping
       eGPIO_AF_TIM1 = 1, // TIM1 Alternate Function mapping
       eGPIO_AF_TIM2 = 1, // TIM2 Alternate Function mapping
       eGPIO_AF_TIM3 = 2, // TIM3 Alternate Function mapping
       eGPIO_AF_TIM4 = 2, // TIM4 Alternate Function mapping
       eGPIO_AF_TIM5 = 2, // TIM5 Alternate Function mapping
       eGPIO_AF_TIM8 = 3, // TIM8 Alternate Function mapping
       eGPIO_AF_TIM9 = 3, // TIM9 Alternate Function mapping
       eGPIO_AF_TIM10 = 3, // TIM10 Alternate Function mapping
       eGPIO_AF_TIM11 = 3, // TIM11 Alternate Function mapping
       eGPIO_AF_I2C1 = 4, // I2C1 Alternate Function mapping
       eGPIO_AF_I2C2 = 4, // I2C2 Alternate Function mapping
       eGPIO_AF_I2C3 = 4, // I2C3 Alternate Function mapping
       eGPIO_AF_SPI1 = 5, // SPI1/I2S1 Alternate Function mapping
       eGPIO_AF_SPI2 = 5, // SPI2/I2S2 Alternate Function mapping
       eGPIO_AF5_SPI3 = 5, // SPI3/I2S3 Alternate Function mapping (Only for STM32F411xE Devices)
       eGPIO_AF_SPI4 = 5, // SPI4/I2S4 Alternate Function mapping
       eGPIO_AF_SPI5 = 5, // SPI5 Alternate Function mapping
       eGPIO_AF_SPI6 = 5, // SPI6 Alternate Function mapping
       eGPIO_AF_SPI3 = 6, // SPI3/I2S3 Alternate Function mapping
       eGPIO_AF6_SPI2 = 6, // SPI2 Alternate Function mapping (Only for STM32F411xE Devices)
       eGPIO_AF6_SPI4 = 6, // SPI4 Alternate Function mapping (Only for STM32F411xE Devices)
       eGPIO_AF6_SPI5 = 6, // SPI5 Alternate Function mapping (Only for STM32F411xE Devices)
       eGPIO_AF_SAI1 = 6, // SAI1 Alternate Function mapping
       eGPIO_AF_USART1 = 7, // USART1 Alternate Function mapping
       eGPIO_AF_USART2 = 7, // USART2 Alternate Function mapping
       eGPIO_AF_USART3 = 7, // USART3 Alternate Function mapping
       eGPIO_AF7_SPI3 = 7, // SPI3/I2S3ext Alternate Function mapping
       eGPIO_AF_I2S3EXT = 7, // AF 7 selection Legacy
       eGPIO_AF_UART4 = 8, // UART4 Alternate Function mapping
       eGPIO_AF_UART5 = 8, // UART5 Alternate Function mapping
       eGPIO_AF_USART6 = 8, // USART6 Alternate Function mapping
       eGPIO_AF_UART7 = 8, // UART7 Alternate Function mapping
       eGPIO_AF_UART8 = 8, // UART8 Alternate Function mapping
       eGPIO_AF_CAN1 = 9, // CAN1 Alternate Function mapping
       eGPIO_AF_CAN2 = 9, // CAN2 Alternate Function mapping
       eGPIO_AF_TIM12 = 9, // TIM12 Alternate Function mapping
       eGPIO_AF_TIM13 = 9, // TIM13 Alternate Function mapping
       eGPIO_AF_TIM14 = 9, // TIM14 Alternate Function mapping
       eGPIO_AF9_I2C2 = 9, // I2C2 Alternate Function mapping (Only for STM32F401xx/STM32F411xE Devices)
       eGPIO_AF9_I2C3 = 9, // I2C3 Alternate Function mapping (Only for STM32F401xx/STM32F411xE Devices)
       eGPIO_AF_OTG_FS = 10, // OTG_FS Alternate Function mapping
       eGPIO_AF_OTG_HS = 10, // OTG_HS Alternate Function mapping
       eGPIO_AF_ETH = 11, // ETHERNET Alternate Function mapping
       eGPIO_AF_SDIO = 12, // SDIO Alternate Function mapping
       eGPIO_AF_OTG_HS_FS = 12, // OTG HS configured in FS, Alternate Function mapping
       eGPIO_AF_FMC = 12, // FMC Alternate Function mapping
       eGPIO_AF_FSMC = 12, // FSMC Alternate Function mapping
       eGPIO_AF_DCMI = 13, // DCMI Alternate Function mapping
       eGPIO_AF_LTDC = 14, // LCD-TFT Alternate Function mapping
       eGPIO_AF_EVENTOUT = 15, // EVENTOUT Alternate Function mapping
    }eGpioAfType_t;

     3、代码实现:

    /********************************************************
     * 函数功能:获取对应GPIO句柄
     * 形    参:gpio:指定GPIO端口
     * 返 回 值:无
     ********************************************************/
    static GPIO_TypeDef *gpio_handle_get(eGpioType_t gpio)
    {
       switch(gpio)
       {
          case eGPIOA: return GPIOA;
          case eGPIOB: return GPIOB;
          case eGPIOC: return GPIOC;
          case eGPIOD: return GPIOD;
          case eGPIOE: return GPIOE;
          case eGPIOF: return GPIOF;
          case eGPIOG: return GPIOG;
          case eGPIOH: return GPIOH;
          case eGPIOI: return GPIOI;
          default: break;
       }
       return NULL;
    }

    /********************************************************
     * 函数功能:引脚复用配置(注:每次只能设置一个引脚)
     * 形    参:gpio:指定GPIO端口
                 pin:指定GPIO引脚
                 af:复用类型
     * 返 回 值:0=成功
                 1=失败
                 2=引脚类型错误
     ********************************************************/
    unsigned int gpio_af_config(eGpioType_t gpio, ePinType_t pin, eGpioAfType_t af)
    {
       if(pin == 0 || pin > ePIN15)
       {
          return 2;
       }
       GPIO_TypeDef *GPIOx = gpio_handle_get(gpio);
       unsigned char pinx = 31U - __CLZ(pin);
       if(GPIOx != NULL)
       {
          GPIOx->AFR[pinx >> 3] &= ~(0x0FUL << (((unsigned int)pinx & 0x07UL) << 2));
          GPIOx->AFR[pinx >> 3] = GPIOx->AFR[pinx >> 3] | ((unsigned int)af << (((unsigned int)pinx & 0x07UL) << 2));
          return 0;
       }
       return 1;
    }

    /********************************************************
     * 函数功能:通用引脚配置
     * 形    参:gpio:指定GPIO端口
                 pin:指定GPIO引脚
                 mode:引脚模式
                 level:初始电平状态(0 or 1)
     * 返 回 值:0=成功
                 1=失败
                 2=端口错误
     ********************************************************/
    unsigned int gpio_config(eGpioType_t gpio, ePinType_t pin, eGpioModeType_t mode, unsigned char level)
    {
       unsigned char pinx = 0;
       unsigned int ospeed = 0x03; // 0=2MHz; 1=25MHz; 2=50MHz; 3=100MHz
       GPIO_TypeDef *GPIOx = gpio_handle_get(gpio);
     
       if(GPIOx == NULL)
       {
          return 2;
       }
     
       pinx = 32U - __CLZ(pin);
       if(pinx == 0)
       {
          return 1;
       }
       for(unsigned char i = 0; i < pinx; i++)
       {
          if(pin & (0x1 << i)) // 找到需要设置的引脚
          {
             unsigned int pin_pupd = 0; // 默认无上下拉
             unsigned int pin_mode = 0; // 默认普通输入
             if(mode == eGPIO_IN_UP || mode == eGPIO_IN_DP || mode == eGPIO_IN_NP)
             {
                pin_mode = 0x00; // 普通输入(系统复位默认状态)
             }
             else if(mode == eGPIO_AN)
             {
                pin_mode = 0x03; // 模拟输入
             }
             else if(mode == eGPIO_AF_UP || mode == eGPIO_AF_DP || mode == eGPIO_AF_NP)
             {
                pin_mode = 0x02; // 复用功能
             }
             else
             {
                pin_mode = 0x01; // 普通输出
             }
             RCC->AHB1ENR |= (0x1UL << gpio); // 使能GPIO时钟
             GPIOx->MODER &= ~(0x3UL << (i << 1)); // 先清除原来的设置
             GPIOx->MODER |= pin_mode << (i << 1); // 设置新的模式
             if((pin_mode == 0x01) || (pin_mode == 0x02)) // 如果是输出模式/复用功能模式
             {
                unsigned int otype = 0; // 默认推挽输出
                if(mode == eGPIO_OUT_OD_UP || mode == eGPIO_OUT_OD_DP || mode == eGPIO_OUT_OD_NP)
                {
                  otype = 1; // 开漏输出
                }
        
                // Speed mode configuration
                GPIOx->OSPEEDR &= ~(0x3UL << (i << 1)); // 清除原来的设置
                GPIOx->OSPEEDR |= (ospeed << (i << 1)); // 设置新的速度值
        
                // Output mode configuration
                GPIOx->OTYPER &= ~(0x1U << i); // 清除原来的设置
                GPIOx->OTYPER |= otype << i; // 设置新的输出模式
             }
       
             if(mode == eGPIO_OUT_OD_UP || mode == eGPIO_OUT_PP_UP || mode == eGPIO_IN_UP || mode == eGPIO_AF_UP)
             {
                pin_pupd = 1; // 上拉
             }
             else if(mode == eGPIO_OUT_OD_DP || mode == eGPIO_OUT_PP_DP || mode == eGPIO_IN_DP || mode == eGPIO_AF_DP)
             {
                pin_pupd = 2; // 下拉
             }
             else if(mode == eGPIO_OUT_OD_NP || mode == eGPIO_OUT_PP_NP || mode == eGPIO_IN_NP || mode == eGPIO_AF_NP)
             {
                pin_pupd = 0; // 无上下拉
             }
             else
             {
                pin_pupd = 3; // 保留
             }
       
             // Pull-up Pull down resistor configuration
             GPIOx->PUPDR &= ~(0x3UL << (i << 1)); // 先清除原来的设置
             GPIOx->PUPDR |= pin_pupd << (i << 1); // 设置新的上下拉
       
             // 设置引脚初始电平
             if(pin_mode == 0x00 || pin_mode == 0x01)
             {
                gpio_set_pin(gpio, pin, level); // 只有在输入或输出的时候才设置引脚的初始化电平
             }
          }
       }
       return 0;
    }

    /********************************************************
     * 函数功能:输出引脚电平设置
     * 形    参:gpio:指定GPIO端口
                 pin:指定GPIO引脚
                 level:初始电平状态(0 or 1)
     * 返 回 值:0=成功
                 1=失败
     ********************************************************/
    unsigned int gpio_set_pin(eGpioType_t gpio, ePinType_t pin, unsigned char level)
    {
       GPIO_TypeDef *GPIOx = gpio_handle_get(gpio);
     
       if(GPIOx != NULL)
       {
          if(level != 0)
          {
             GPIOx->BSRRL = pin; // 输出高电平
          }
          else
          {
             GPIOx->BSRRH = pin; // 输出低电平
          }
      
          return 0;
       }
       else
       {
          return 1;
       }
    }

    /********************************************************
     * 函数功能:输出端口电平设置
     * 形    参:gpio:指定GPIO端口
                 level:初始电平状态(0 or 1)
     * 返 回 值:0=成功
                 1=失败
     ********************************************************/
    unsigned int gpio_set_port(eGpioType_t gpio, unsigned int level)
    {
       GPIO_TypeDef *GPIOx = gpio_handle_get(gpio);
     
       if(GPIOx != NULL)
       {
          GPIOx->ODR = level;
          return 0;
       }
       else
       {
          return 1;
       }
    }

    /********************************************************
     * 函数功能:输入引脚电平状态读取
     * 形    参:gpio:指定GPIO端口
                 pin:指定GPIO引脚
     * 返 回 值:指定引脚电平状态(0 or 1)
     ********************************************************/
    unsigned char gpio_read_pin(eGpioType_t gpio, ePinType_t pin)
    {
       if(gpio_handle_get(gpio)->IDR & pin)
       {
          return 1;
       }
       else
       {
          return 0;
       }
    }

    /********************************************************
     * 函数功能:输入端口电平状态读取
     * 形    参:gpio:指定GPIO端口
                 pin:指定GPIO引脚
     * 返 回 值:指定引脚电平状态(0 or 1)
     ********************************************************/
    unsigned int gpio_read_port(eGpioType_t gpio)
    {
       return gpio_handle_get(gpio)->IDR;
    }

    /********************************************************
     * 函数功能:输出引脚电平翻转
     * 形    参:gpio:指定GPIO端口
                 pin:指定GPIO引脚
     * 返 回 值:无
     ********************************************************/
    void gpio_out_reversal(eGpioType_t gpio, ePinType_t pin)
    {
       gpio_handle_get(gpio)->ODR ^= pin;
    }

  • 相关阅读:
    微信小程序之:获得appid
    小程序v0.10基本布局
    小程序v0.02 清理干净
    微信小程序v0.01
    让Eclipse在10秒内启动的7个优化提速技巧
    转 1 年经验 Java 求职面试题
    坑爹啊
    ES6,时间格式yyyy-MM-dd HH:MM:SS
    ln: creating hard link 问题
    boost实现串口通信(一):小试牛刀
  • 原文地址:https://www.cnblogs.com/icode-wzc/p/12910186.html
Copyright © 2011-2022 走看看