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;
}

 

posted @ 2020-05-18 14:00  一梦一人生  阅读(1252)  评论(0编辑  收藏  举报