GPIO — General purpose input/output

通用输入/输出(GPIO)组织为一个端口多达32个I/ o(依赖于包),允许通过一个端口访问和控制多达32个引脚。 每个GPIO可以单独访问
GPIO具有以下用户可配置的特性:

  • 最大支持32 GPIO
  • 8 GPIO与模拟通道,用于SAADC, COMP或LPCOMP输入
  • 可配置的输出驱动器强度
  • 内部上拉和下拉电阻
  • 从所有引脚的高或低电平触发器唤醒
  • 在任何引脚上的状态改变触发中断
  • 所有引脚都可以被PPI任务/事件系统使用
  • 可以通过PPI和GPIOTE通道控制一个或多个GPIO输出
  • 所有引脚可以单独映射到接口块布局灵活性
  • 在SENSE信号上捕获的GPIO状态变化可以通过LATCH寄存器存储

GPIO端口外设最多实现32个引脚,从PIN0到PIN31。 每个这些引脚可以在PIN_CNF[n]寄存器中单独配置(n=0…31)。

**以下参数可以通过这些寄存器进行配置: **

  • 方向(输入/输出)
  • 驱动器强度
  • 使能上拉和下拉电阻
  • 引脚检测
  • 输入缓冲区断开
  • 模拟输入(用于选定引脚)

PIN_CNF寄存器是保留寄存器。 有关保留寄存器的更多信息,请参阅第78页的POWER - POWER supply章节。

引脚配置

引脚可以单独配置,通过PIN_CNF[n]寄存器的SENSE字段,检测其输入电平的高电平或低电平。

当在任何这样配置的引脚上检测到正确的电平时,传感机制将设置高检测信号。

每个引脚有一个单独的检测信号,默认的行为,如DETECTMODE寄存器定义的,是从GPIO端口的所有引脚的检测信号被组合成一个共同的检测信号,在整个系统中路由,然后可以被其他外围设备利用,
参见图21:第112页的GPIO端口和GPIO引脚详细信息。 这个机制在ON和OFF模式下都有作用。

[单片机框架][bsp层][nrf52832][nrf52840][nrf52810][nrf52820][bsp_gpio] GPIO配置和使用_单片机


官方手册下载:

​ https://infocenter.nordicsemi.com/pdf/nRF52810_PS_v1.3.pdf​

https://infocenter.nordicsemi.com/pdf/nRF52820_PS_v1.2.pdf

https://infocenter.nordicsemi.com/pdf/nRF52832_PS_v1.7.pdf

https://infocenter.nordicsemi.com/pdf/nRF52840_PS_v1.5.pdf

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

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

#include "RTE_Components.h"
#include CMSIS_device_header
#include "nrf_gpio.h"
#include "nrf_drv_gpiote.h"

#include "sdk_common.h"

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

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

/* Private Variables ---------------------------------------------------------*/
/* Private Function Prototypes -----------------------------------------------*/
static nrf_gpiote_polarity_t get_exti_event(bsp_gpio_exti_int_event_t exti_type)
{
if (BSP_GPIO_EXTI_INT_LOWFALL == exti_type)
{
return NRF_GPIOTE_POLARITY_HITOLO;
}
else if (BSP_GPIO_EXTI_INT_HIGHRISE == exti_type)
{
return NRF_GPIOTE_POLARITY_LOTOHI;
}
else if (BSP_GPIO_EXTI_INT_FALLRISE == exti_type)
{
return NRF_GPIOTE_POLARITY_TOGGLE;
}
else
{
return NRF_GPIOTE_POLARITY_TOGGLE;
}
}

static nrf_gpio_pin_pull_t get_nrf_pull(bsp_gpio_pin_pull_t pull)
{
if (pull == BSP_GPIO_PIN_PULLUP)
{
return NRF_GPIO_PIN_PULLUP;
}
else if(pull == BSP_GPIO_PIN_PULLDOWN)
{
return NRF_GPIO_PIN_PULLDOWN;
}
else
{
return NRF_GPIO_PIN_NOPULL;
}
}

/* Public Function Prototypes ------------------------------------------------*/
/**
* @brief [反初始化] 关闭指定引脚功能(恢复为浮空输入)
* @note NULL
* @param *gpiox: NULL
* @param pin: 引脚号
* @retval None
*/
void bsp_gpio_deinit(void *gpiox, uint8_t pin)
{
nrf_gpio_cfg_default(pin);
}

/**
* @brief [初始化] 引脚设置为输出模式
* @note NULL
* @param *gpiox: NULL
* @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)
{
nrf_gpio_cfg_output(pin);
}

/**
* @brief [初始化] 引脚设置为输入模式
* @note NULL
* @param *gpiox: NULL
* @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)
{
nrf_gpio_cfg_input(pin, get_nrf_pull(pull));
}

extern void gpiote_event_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action);
/**
* @brief [初始化] 引脚设置为[输入+中断]模式
* @param gpiox -- NULL
* @param pin -- 引脚号
* @param irqn -- NULL
* @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 下拉输入
*/
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)
{
static bool flag = 0;
ret_code_t err_code;

if (flag == 0)
{
err_code = nrf_drv_gpiote_init();
APP_ERROR_CHECK(err_code);
flag = 1;
}

nrf_drv_gpiote_in_config_t config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(exti_type);
config.pull = get_nrf_pull(pull);
config.sense = get_exti_event(exti_event);
err_code = nrf_drv_gpiote_in_init(pin, &config, gpiote_event_handler);
APP_ERROR_CHECK(err_code);
nrf_drv_gpiote_in_event_enable(pin, true);
}

/**
* @brief 设置引脚电平状态
* @note NULL
* @param *gpiox: NULL
* @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)
{
if (state)
{
nrf_gpio_pin_set(pin);
}
else
{
nrf_gpio_pin_clear(pin);
}
}

/**
* @brief 翻转引脚电平状态
* @note NULL
* @param *gpiox: NULL
* @param pin: 引脚号
* @retval None
*/
void bsp_gpio_set_toggle(void *gpiox, uint8_t pin)
{
nrf_gpio_pin_toggle(pin);
}

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

/**
* @brief 将指定引脚复用为ADC引脚(复用模拟输入)
* @note NULL
* @param *gpiox: NULL
* @param pin: 引脚号
* @retval None
*/
void bsp_gpio_init_adc(void *gpiox, uint8_t pin)
{
}

/**
* @brief 初始化i2c引脚
* @note NULL
* @param *gpiox: NULL
* @param pin: 引脚号
* @param arf: 复用值
* @retval None
*/
void bsp_gpio_init_i2c(void *gpiox, uint8_t pin, uint8_t arf)
{
}

/**
* @brief 初始化uart引脚
* @note NULL
* @param *gpiox: NULL
* @param pin: 引脚号
* @param arf: 复用值
* @retval None
*/
void bsp_gpio_init_uart(void *gpiox, uint8_t pin, uint8_t arf)
{
}

/**
* @brief 初始化tim_ch引脚
* @note NULL
* @param *gpiox: NULL
* @param pin: 引脚号
* @param arf: 复用值
* @retval None
*/
void bsp_gpio_init_tim(void *gpiox, uint8_t pin, uint8_t arf)
{
}
/********************************************************************************
* @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