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;
}
{
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; // 普通输出
}
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;
}