打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

LiSun

打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

GPIO(general purpose intput output)是通用输入输出端口的简称,可以通过软件来控制其输入和输出。51
单片机芯片的 GPIO 引脚与外部设备连接起来,从而实现与外部通讯、 控制以及数据采集的功能。过 GPIO 最简单的应用还属点亮 LED
灯了,只需通过软件控制 GPIO 输出高低电平即可。当然GPIO
还可以作为输入控制,比如在引脚上接入一个按键,通过电平的高低判断按键是否按下。

通用输入/输出口用于芯片和外部进行数据传输,共有 4 组 GPIO:GPIOA、GPIOB、GPIOC 和GPIOD。4 组 GPIO 的功能基本相同,可以通过配置将 GPIO 映射到对应芯片引脚,每个引脚可以被独立配置为数字输入或者输出口,也可以被配置为模拟输入。另外,还可以配置成外部中断、片上外设输入/输出等复用功能。同一时刻一个引脚仅可被映射一个复用功能,通过端口复用功能寄存器(GPIOx_AFR)配置。

每个通用 I/O 口都有 5 个配置寄存器(GPIOx_DIRCR、GPIOx_OTYPER、GPIOx_PUPDR,GPIOx_SLEWCR 和 GPIOx_DRVCR),2 个数据寄存器(GPIOx_IDR 和 GPIOx_ODR),1 个输出置位寄存器(GPIOx_ODSET),1 个输出复位寄存器(GPIOx_ODCLR)和 1 个复用功能寄存器(GPIOx_AFR)。

每个端口都可以配置成内部上拉(pull up)/下拉(pull down)的输入/输出,高阻输入(floating input),推挽输出(push-pull output),开漏输出(open drain output),增强驱动能力输出。芯片复位后端口复位为高阻输入,目的是防止芯片在异常复位时,导致外部器件产生异常动作。为了避免高阻输入而产生的漏电,用户要在芯片启动之后对端口进行相应配置(配置成内部拉高输入或者输出)。端口被配成模拟端口后,数字功能被隔离,不能输出数字“1”和“0” ,CPU 读取端口的结果为“0” 。

所有端口都可以提供外部中断, 并且每个中断都可以配置成高电平触发、 低电平触发、 上升沿触发、下降沿触发或者任意边沿触发,支持边沿模式下的输入消抖。支持在工作模式/睡眠模式/深度睡眠模式下产生中断。

/********************************************************************************
* @file    bsp_gpio.c
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-04-09
* @brief   gpio初始化
********************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>

#include "RTE_Components.h"
#include CMSIS_device_header

#include "bsp_exti.h"
#include "bsp_gpio.h"

/* Private Includes ----------------------------------------------------------*/
#include "business_gpio.h"
#include "business_function.h"

/* Private Variables ---------------------------------------------------------*/
/* Private Function Prototypes -----------------------------------------------*/
static uint8_t get_exti_event(bsp_gpio_exti_int_event_t exti_type)
{
    if (BSP_GPIO_EXTI_INT_LOWFALL == exti_type)
    {
        return GPIO_EXTI_INT_LOWFALL;
    }
    else if (BSP_GPIO_EXTI_INT_HIGHRISE == exti_type)
    {
        return GPIO_EXTI_INT_HIGHRISE;
    }
    else if (BSP_GPIO_EXTI_INT_FALLRISE == exti_type)
    {
        return GPIO_EXTI_INT_FALLRISE;
    }
    else
    {
        return GPIO_EXTI_INT_FALLRISE;
    }
}
/* Public Function Prototypes ------------------------------------------------*/
/**
 * @brief  [反初始化] 关闭指定引脚功能(恢复为浮空输入)
 * @note   NULL
 * @param  *gpiox: gpio组号(GPIOA/GPIOB/GPIOC/GPIOD等等)
 * @param  pin: 引脚号
 * @retval None
 */
void bsp_gpio_deinit(void *gpiox, uint8_t pin)
{
    HAL_GPIO_DeInit(gpiox, pin);
}

/**
 * @brief  [初始化] 引脚设置为输出模式
 * @note   NULL
 * @param  *gpiox: gpio组号(GPIOA/GPIOB/GPIOC/GPIOD等等)
 * @param  pin: 引脚号
 * @param  out_mode:  BSP_GPIO_PIN_OUT_OD 开漏输出, BSP_GPIO_PIN_OUT_PP 推免输出, BSP_GPIO_PIN_AF_OD 复用开漏, BSP_GPIO_PIN_AF_PP 复用推免
 * @retval None
 */
void bsp_gpio_init_output(void *gpiox, uint8_t pin, bsp_gpio_pin_out_t out_mode)
{
    volatile GPIO_InitTypeDef gpio_init_struct;

    gpio_init_struct.Pin              = pin;
    gpio_init_struct.Pull             = GPIO_NOPULL;
    gpio_init_struct.Debounce.Enable  = GPIO_DEBOUNCE_DISABLE;   // 禁止输入去抖动
    gpio_init_struct.SlewRate         = GPIO_SLEW_RATE_HIGH;
    gpio_init_struct.DrvStrength      = GPIO_DRV_STRENGTH_HIGH;
    if (out_mode == BSP_GPIO_PIN_OUT_OD)
    {
        gpio_init_struct.Mode        = GPIO_MODE_OUTPUT;
        gpio_init_struct.OpenDrain   = GPIO_OPENDRAIN;
    }
    else if (out_mode == BSP_GPIO_PIN_OUT_PP)
    {
        gpio_init_struct.Mode        = GPIO_MODE_OUTPUT;
        gpio_init_struct.OpenDrain   = GPIO_PUSHPULL;
    }
    else if (out_mode == BSP_GPIO_PIN_AF_OD)
    {
        gpio_init_struct.Mode        = GPIO_MODE_AF;
        gpio_init_struct.OpenDrain   = GPIO_OPENDRAIN;
    }
    else if (out_mode == BSP_GPIO_PIN_AF_PP)
    {
        gpio_init_struct.Mode        = GPIO_MODE_AF;
        gpio_init_struct.OpenDrain   = GPIO_PUSHPULL;
    }
    HAL_GPIO_Init(gpiox, (GPIO_InitTypeDef *)&gpio_init_struct);
}

/**
 * @brief  [初始化] 引脚设置为输入模式
 * @note   NULL
 * @param  *gpiox: gpio组号(GPIOA/GPIOB/GPIOC/GPIOD等等)
 * @param  pin: 引脚号
 * @param  pull: BSP_GPIO_PIN_NOPULL 无上下拉, BSP_GPIO_PIN_PULLUP 上拉输入, BSP_GPIO_PIN_PULLDOWN 下拉输入
 * @retval None
 */
void bsp_gpio_init_input(void *gpiox, uint8_t pin, bsp_gpio_pin_pull_t pull)
{
    volatile GPIO_InitTypeDef gpio_init_struct;

    gpio_init_struct.Pin              = pin;
    gpio_init_struct.Pull             = pull;
    gpio_init_struct.Debounce.Enable  = GPIO_DEBOUNCE_DISABLE;   // 禁止输入去抖动
    gpio_init_struct.SlewRate         = GPIO_SLEW_RATE_HIGH;
    gpio_init_struct.DrvStrength      = GPIO_DRV_STRENGTH_HIGH;
    gpio_init_struct.Mode             = GPIO_MODE_INPUT;

    HAL_GPIO_Init(gpiox, (GPIO_InitTypeDef *)&gpio_init_struct);
}

static uint8_t get_exti_type(bsp_gpio_exti_int_type_t exti_type)
{
    if (BSP_GPIO_EXTI_INT_LEVEL == exti_type)
    {
        return GPIO_EXTI_INT_LEVEL;
    }
    else
    {
        return GPIO_EXTI_INT_EDGE;
    }
}



/**
 * @brief  [初始化] 引脚设置为[输入+中断]模式
 * @note   NULL
 * @param  *gpiox: gpio组号(GPIOA/GPIOB/GPIOC/GPIOD等等)
 * @param  pin: 引脚号
 * @param  irqn: 中断号(在typedef enum IRQn中,例如:USART1_IRQn)
 * @param  exti_type: BSP_GPIO_EXTI_INT_LEVEL 电平触发, BSP_GPIO_EXTI_INT_EDGE 边沿触发
 * @param  exti_event: BSP_GPIO_EXTI_INT_LOWFALL 低电平触发(下降沿), BSP_GPIO_EXTI_INT_HIGHRISE 高电平触发(上降沿), BSP_GPIO_EXTI_INT_FALLRISE 高低电平触发或任意电平变化
 * @param  pull: BSP_GPIO_PIN_NOPULL 无上下拉, BSP_GPIO_PIN_PULLUP 上拉输入, BSP_GPIO_PIN_PULLDOWN 下拉输入
 * @retval None
 */
void bsp_gpio_init_input_exit(void *gpiox, uint8_t pin, uint8_t irqn,
                              bsp_gpio_exti_int_type_t exti_type,
                              bsp_gpio_exti_int_event_t exti_event,
                              bsp_gpio_pin_pull_t pull)
{
    volatile GPIO_InitTypeDef gpio_init_struct;

    gpio_init_struct.Pin               = pin;
    gpio_init_struct.Pull              = pull;
    gpio_init_struct.Debounce.Enable   = GPIO_DEBOUNCE_ENABLE;   // 禁止输入去抖动
    gpio_init_struct.SlewRate          = GPIO_SLEW_RATE_HIGH;
    gpio_init_struct.DrvStrength       = GPIO_DRV_STRENGTH_HIGH;

    /* Configure Button pin as input with External interrupt */
    gpio_init_struct.Mode              = EXTI_MODE;
    gpio_init_struct.Exti.Enable       = GPIO_EXTI_INT_ENABLE;
    gpio_init_struct.Exti.EdgeLevelSel = get_exti_type(exti_type);
    gpio_init_struct.Exti.RiseFallSel  = get_exti_event(exti_event);
    HAL_GPIO_Init(gpiox, (GPIO_InitTypeDef *)&gpio_init_struct);

    bsp_exit_clear_flag(gpiox, pin);
    /* Enable and set Button EXTI Interrupt to the lowest priority */
    bsp_exit_set(irqn, PRIORITY_LOW);
}

/**
 * @brief  设置引脚电平状态
 * @note   NULL
 * @param  *gpiox: gpio组号(GPIOA/GPIOB/GPIOC/GPIOD等等)
 * @param  pin: 引脚号
 * @param  state: BSP_GPIO_PIN_RESET 低电平, BSP_GPIO_PIN_SET 高电平
 * @retval None
 */
void bsp_gpio_set_pin(void *gpiox, uint8_t pin, bsp_gpio_pin_state_t state)
{
    HAL_GPIO_WritePin(gpiox, pin, (GPIO_PinState)state);
}

/**
 * @brief  翻转引脚电平状态
 * @note   NULL
 * @param  *gpiox: gpio组号(GPIOA/GPIOB/GPIOC/GPIOD等等)
 * @param  pin: 引脚号
 * @retval None
 */
void bsp_gpio_set_toggle(void *gpiox, uint8_t pin)
{
    HAL_GPIO_TogglePin(gpiox, pin);
}

/**
 * @brief  得到指定gpio状态
 * @note   NULL
 * @param  *gpiox: gpio组号(GPIOA/GPIOB/GPIOC/GPIOD等等)
 * @param  pin: 引脚号
 * @retval 0 -- 低电平, 1 -- 高电平
 */
bool bsp_gpio_get_state(void *gpiox, uint8_t pin)
{
    return (bool)HAL_GPIO_ReadPin(gpiox, pin);
}

/**
 * @brief  将指定引脚复用为ADC引脚(复用模拟输入)
 * @note   NULL
 * @param  *gpiox: gpio组号(GPIOA/GPIOB/GPIOC/GPIOD等等)
 * @param  pin: 引脚号
 * @retval None
 */
void bsp_gpio_init_adc(void *gpiox, uint8_t pin)
{
    volatile GPIO_InitTypeDef gpio_init_struct;

    gpio_init_struct.Pin               = pin;
    gpio_init_struct.Mode              = GPIO_MODE_ANALOG;       // 模拟输入
    gpio_init_struct.OpenDrain         = GPIO_OPENDRAIN;	     // 开漏输出
    gpio_init_struct.Debounce.Enable   = GPIO_DEBOUNCE_DISABLE;  // 禁止输入去抖动
    gpio_init_struct.SlewRate          = GPIO_SLEW_RATE_HIGH;    // 电压转换速率
    gpio_init_struct.DrvStrength       = GPIO_DRV_STRENGTH_HIGH; // 驱动强度
    gpio_init_struct.Pull              = GPIO_NOPULL;            // 无上下拉

    HAL_GPIO_Init(gpiox, (GPIO_InitTypeDef *)&gpio_init_struct);
}

/**
 * @brief  初始化i2c引脚
 * @note   NULL
 * @param  *gpiox: gpio组号(GPIOA/GPIOB/GPIOC/GPIOD等等)
 * @param  pin: 引脚号
 * @param  arf: 复用值
 * @retval None
 */
void bsp_gpio_init_i2c(void *gpiox, uint8_t pin, uint8_t arf)
{
    volatile GPIO_InitTypeDef gpio_init_struct;

    gpio_init_struct.Pin               = pin;
    gpio_init_struct.Mode              = GPIO_MODE_AF;           // GPIO端口复用功能
    gpio_init_struct.OpenDrain         = GPIO_OPENDRAIN;         // 开漏输出
    gpio_init_struct.Debounce.Enable   = GPIO_DEBOUNCE_DISABLE;  // 禁止输入去抖动
    gpio_init_struct.SlewRate          = GPIO_SLEW_RATE_LOW;     // 电压转换速率
    gpio_init_struct.DrvStrength       = GPIO_DRV_STRENGTH_HIGH; // 驱动强度
    gpio_init_struct.Pull              = GPIO_PULLUP;            // 上拉
    gpio_init_struct.Alternate         = arf;

    HAL_GPIO_Init(gpiox, (GPIO_InitTypeDef *)&gpio_init_struct);
}

/**
 * @brief  初始化uart引脚
 * @note   NULL
 * @param  *gpiox: gpio组号(GPIOA/GPIOB/GPIOC/GPIOD等等)
 * @param  pin: 引脚号
 * @param  arf: 复用值
 * @retval None
 */
void bsp_gpio_init_uart(void *gpiox, uint8_t pin, uint8_t arf)
{
    volatile GPIO_InitTypeDef GPIO_InitStruct;

    GPIO_InitStruct.Pin             = pin;
    GPIO_InitStruct.Mode            = GPIO_MODE_AF;
    GPIO_InitStruct.OpenDrain       = GPIO_PUSHPULL;
    GPIO_InitStruct.Debounce.Enable = GPIO_DEBOUNCE_DISABLE;
    GPIO_InitStruct.SlewRate        = GPIO_SLEW_RATE_HIGH;
    GPIO_InitStruct.DrvStrength     = GPIO_DRV_STRENGTH_HIGH;
    GPIO_InitStruct.Pull            = GPIO_PULLUP;
    GPIO_InitStruct.Alternate       = arf;

    HAL_GPIO_Init(gpiox, (GPIO_InitTypeDef *)&GPIO_InitStruct);
}

/**
 * @brief  初始化tim_ch引脚
 * @note   NULL
 * @param  *gpiox: gpio组号(GPIOA/GPIOB/GPIOC/GPIOD等等)
 * @param  pin: 引脚号
 * @param  arf: 复用值
 * @retval None
 */
void bsp_gpio_init_tim(void *gpiox, uint8_t pin, uint8_t arf)
{
    volatile GPIO_InitTypeDef GPIO_InitStruct;

    GPIO_InitStruct.Pin             = pin;
    GPIO_InitStruct.Mode            = GPIO_MODE_AF;
    GPIO_InitStruct.OpenDrain       = GPIO_PUSHPULL;
    GPIO_InitStruct.Debounce.Enable = GPIO_DEBOUNCE_DISABLE;
    GPIO_InitStruct.SlewRate        = GPIO_SLEW_RATE_HIGH;
    GPIO_InitStruct.DrvStrength     = GPIO_DRV_STRENGTH_HIGH;
    GPIO_InitStruct.Pull            = GPIO_PULLUP;
    GPIO_InitStruct.Alternate       = arf;

    HAL_GPIO_Init(gpiox, (GPIO_InitTypeDef *)&GPIO_InitStruct);
}

/********************************************************************************
* @file    bsp_gpio.h
* @author  jianqiang.xue
* @version V1.0.0
* @date    2021-04-09
* @brief   GPIO控制
********************************************************************************/

#ifndef __BSP_GPIO_H
#define __BSP_GPIO_H

/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>

/* Public enum ---------------------------------------------------------------*/
/**
 * @brief  GPIO Bit SET and Bit RESET enumeration
 */
typedef enum
{
    BSP_GPIO_PIN_RESET = 0U,
    BSP_GPIO_PIN_SET
} bsp_gpio_pin_state_t;

typedef enum
{
    BSP_GPIO_PIN_NOPULL = 0U,
    BSP_GPIO_PIN_PULLUP,
    BSP_GPIO_PIN_PULLDOWN
} bsp_gpio_pin_pull_t;

typedef enum
{
    BSP_GPIO_PIN_OUT_OD = 0U,
    BSP_GPIO_PIN_OUT_PP,
    BSP_GPIO_PIN_AF_OD,
    BSP_GPIO_PIN_AF_PP
} bsp_gpio_pin_out_t;

typedef enum
{
    BSP_GPIO_EXTI_INT_LEVEL = 0U,     // 电平触发
    BSP_GPIO_EXTI_INT_EDGE,           // 边沿触发
} bsp_gpio_exti_int_type_t;

typedef enum
{
    BSP_GPIO_EXTI_INT_LOWFALL = 0U,   // 低电平触发(下降沿)
    BSP_GPIO_EXTI_INT_HIGHRISE,       // 高电平触发(上降沿)
    BSP_GPIO_EXTI_INT_FALLRISE        // 高低电平触发或任意电平变化
} bsp_gpio_exti_int_event_t;

/* Public Function Prototypes ------------------------------------------------*/

// 常规引脚初始化

void bsp_gpio_deinit(void *gpiox, uint8_t pin);
void bsp_gpio_init_output(void *gpiox, uint8_t pin, bsp_gpio_pin_out_t out_mode);
void bsp_gpio_init_input(void *gpiox, uint8_t pin, bsp_gpio_pin_pull_t pull);
void bsp_gpio_init_input_exit(void *gpiox, uint8_t pin, uint8_t irqn, bsp_gpio_exti_int_type_t exti_type, bsp_gpio_exti_int_event_t exti_event, bsp_gpio_pin_pull_t pull);

// 外设引脚初始化

void bsp_gpio_init_adc(void *gpiox, uint8_t pin);
void bsp_gpio_init_i2c(void *gpiox, uint8_t pin, uint8_t arf);
void bsp_gpio_init_uart(void *gpiox, uint8_t pin, uint8_t arf);
void bsp_gpio_init_tim(void *gpiox, uint8_t pin, uint8_t arf);

// 引脚控制和状态获取

void bsp_gpio_set_pin(void *gpiox, uint8_t pin, bsp_gpio_pin_state_t state);
void bsp_gpio_set_toggle(void *gpiox, uint8_t pin);
bool bsp_gpio_get_state(void *gpiox, uint8_t pin);

#endif

posted on 2022-08-13 11:00  xuejianqiang  阅读(127)  评论(0编辑  收藏  举报
打造一个通用性MCU架构,支持CX32/AT32/NRF51/NRF52等。 OS支持RTX4/RTX5/FreeRtos。 采用VsCode+GCC组合,VsCode+KEIL5,超强开发方式。 QQ群:524408033