1,概述

通用型之输入输出(General-purpose input/output,通常称为GPIO),GPIO管理功能提供GPIO控制寄存器,实现软件对 GPIO 属性的配置,使用户能够方便地操作 GPIO。每个GPIO可以配置为输入、输出和可选功能三种模式。在每个模式下(除模拟可选功能),提供设置上拉,下拉,浮空三种端口状态,此外GPIO还提供中断功能,可以配置为上升沿触发,下降沿触发或者高电平/低电平触发。

2,API参考

2.1 重要结构体、枚举介绍

2.1.1GPIO配置结构体

  • 用于设置GPIO工作模式、电平以及是否上拉
    1. struct HAL_IOMUX_PIN_FUNCTION_MAP {
    2. enum HAL_IOMUX_PIN_T pin;
    3. enum HAL_IOMUX_FUNCTION_T function;
    4. enum HAL_IOMUX_PIN_VOLTAGE_DOMAINS_T volt;
    5. enum HAL_IOMUX_PIN_PULL_SELECT_T pull_sel;
    6. };

    2.1.2 GPIO输入输出枚举

    enum HAL_GPIO_DIR_T {
    HAL_GPIO_DIR_IN = 0,     //GPIO_IN
    HAL_GPIO_DIR_OUT = 1,     //GPIO_OUT    
    };
    

    2.1.3 GPIO中断类型枚举

    enum HAL_GPIO_IRQ_TYPE_T {
    HAL_GPIO_IRQ_TYPE_LEVEL_SENSITIVE = 0,  //电平触发
    HAL_GPIO_IRQ_TYPE_EDGE_SENSITIVE,        //边沿触发
    };
    

    2.1.4 GPIO中断触发电平枚举

    enum HAL_GPIO_IRQ_POLARITY_T {
    HAL_GPIO_IRQ_POLARITY_LOW_FALLING = 0, //低电平/下降沿
    HAL_GPIO_IRQ_POLARITY_HIGH_RISING,       //高电平/上升沿
    };
    

    2.1.5 GPIO中断函数指针

  • 函数参数:

    • pin :GPIO接口枚举

      typedef void (* HAL_GPIO_PIN_IRQ_HANDLER)(enum HAL_GPIO_PIN_T pin);
      

      2.1.6 GPIO中断配置结构体

    • 在配置GPIO中断时,所有中断相关参数都包含在此结构体中

      struct HAL_GPIO_IRQ_CFG_T {
      uint8_t irq_enable:1;                        //中断使能
      uint8_t irq_debounce:1;                        //GPIO消抖使能
      enum HAL_GPIO_IRQ_TYPE_T irq_type;            //GPIO中断类型
      enum HAL_GPIO_IRQ_POLARITY_T irq_polarity;    //GPIO中断电平
      HAL_GPIO_PIN_IRQ_HANDLER irq_handler;        //中断处理函数
      };
      

      2.2 主要函数介绍

      2.2.1 GPIO初始化

  • 函数原型:

    uint32_t hal_iomux_init(const struct HAL_IOMUX_PIN_FUNCTION_MAP *map, uint32_t count)
    
  • 功能描述:设置GPIO工作模式

  • 函数参数:

    • *map:GPIO配置结构体指针,可一次性初始化多个GPIO
    • count:GPIO数量

      2.2.2 GPIO输入/输出设置

  • 函数原型:

    void hal_gpio_pin_set_dir(enum HAL_GPIO_PIN_T pin, enum HAL_GPIO_DIR_T dir, uint8_t val_for_out);
    
  • 功能描述:设置指定GPIO为输入或者输出模式,如为输出模式则规定初始电平

  • 函数参数:

    • pin:指定GPIO
    • dir:输入/输出模式
    • valt_for_out:输出模式初始电平,0为低电平、1为高电平

      2.2.3 GPIO电平置高

  • 函数原型:

    void hal_gpio_pin_set(enum HAL_GPIO_PIN_T pin);
    
  • 功能描述:将指定GPIO的电平置高

  • 函数参数:

    • pin:指定GPIO

      2.2.4 GPIO电平置低

  • 函数原型:

    void hal_gpio_pin_clr(enum HAL_GPIO_PIN_T pin);
    
  • 功能描述:将指定GPIO的电平置低

  • 函数参数:

    • pin:指定GPIO

      2.2.5 获取指定GPIO输入/输出模式

  • 函数原型:

    enum HAL_GPIO_DIR_T hal_gpio_pin_get_dir(enum HAL_GPIO_PIN_T pin);
    
  • 功能描述:获取指定GPIO当前为输入或是输出模式

  • 函数参数:
    • pin:需要判断的GPIO
  • 返回值:

    • 0:输入模式
    • 1:输出模式

      2.2.6 获取指定GPIO当前值

  • 函数原型:

    uint8_t hal_gpio_pin_get_val(enum HAL_GPIO_PIN_T pin);
    
  • 功能描述:获取指定GPIO当前电平

  • 函数参数:
    • pin:指定GPIO
  • 返回值:

    • 0:低电平
    • 1:高电平

      2.2.7 GPIO中断注册函数

  • 函数原型:

    uint8_t hal_gpio_setup_irq(enum HAL_GPIO_PIN_T pin, const struct HAL_GPIO_IRQ_CFG_T *cfg);
    
  • 功能描述:将设置好的GPIO中断参数配置给指定GPIO

  • 函数参数:
    • pin:指定GPIO
    • *cfg:GPIO中断配置结构体指针
  • 返回值:

    • 0:配置成功
    • 1:配置失败

      3,使用教程

      3.1 头文件引用

      #include "hal_gpio.h"  //通用IO配置头文件
      #include "hal_iomux.h" //IO多路输入输出配置文件
      
  • 上述两个头文件必须引用才能正常使用GPIO

    3.2 初始化GPIO

  • 首先引用HAL_IOMUX_PIN_FUNCTION_MAP结构体来配置IO以及模式

    struct HAL_IOMUX_PIN_FUNCTION_MAP cfg_hw_gpio;
     cfg_hw_gpio.pin = gpio->port;                    //端口选择
     cfg_hw_gpio.function = HAL_IOMUX_FUNC_AS_GPIO;    //功能选择,选择GPIO功能
     cfg_hw_gpio.volt = HAL_IOMUX_PIN_VOLTAGE_VIO;    //电平选择,VIO:高,MEM:低
     cfg_hw_gpio.pull_sel = HAL_IOMUX_PIN_NOPULL;    //选择是否上拉
    
  • 也可以一次性配置多个IO

    struct HAL_IOMUX_PIN_FUNCTION_MAP pinmux[] = {
          {HAL_GPIO_PIN_P0_2, HAL_IOMUX_FUNC_AS_GPIO, HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_NOPULL},
          {HAL_GPIO_PIN_P0_4, HAL_IOMUX_FUNC_AS_GPIO, HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_NOPULL},
          {HAL_GPIO_PIN_P0_5, HAL_IOMUX_FUNC_AS_GPIO, HAL_IOMUX_PIN_VOLTAGE_MEM, HAL_IOMUX_PIN_NOPULL},
      };
    
  • 结构体配置完成后使用 hal_iomux_init ()来初始化IO

    hal_iomux_init(pinmux, ARRAY_SIZE(pinmux));
    
  • 至此完成GPIO初始化

    3.3 API使用

  • 在初始化GPIO后便可以使用前文介绍过的各个函数

  • 初始化后的GPIO还没有设置输入输出模式,需要手动设置

    hal_gpio_pin_set_dir(HAL_GPIO_PIN_P0_2, HAL_GPIO_DIR_OUT, 0); //配置P0_2口为输出口,初始电平为低电平
    hal_gpio_pin_set_dir(HAL_GPIO_PIN_P0_4, HAL_GPIO_DIR_IN, 0);  //配置P0_4口为输入口
    hal_gpio_pin_set_dir(HAL_GPIO_PIN_P0_5, HAL_GPIO_DIR_IN, 0);  //配置P0_5口为输入口
    
  • 配置好输入或输出后可以使用相应的函数

    static void gpio_output_test(void)
    {
     printf("set gpio %d high\r\n", HAL_GPIO_PIN_P0_2);
     hal_gpio_pin_set(HAL_GPIO_PIN_P0_2); // set high
     mdelay(1000);    //delay 1000ms
     printf("set gpio %d low\r\n", HAL_GPIO_PIN_P0_2);
     hal_gpio_pin_clr(HAL_GPIO_PIN_P0_2); // set low
    }
    
    static void gpio_input_test(void)
    {
     uint8_t val = 0;
     while (1) {
         uint8_t tmp = hal_gpio_pin_get_val(HAL_GPIO_PIN_P0_4);    //读取P0_4的电平
         if (tmp != val) {
             printf("gpio %d toggle from %d to %d\r\n", HAL_GPIO_PIN_P0_4, val, tmp);
             val = tmp;
         }
         mdelay(100);    
     }
    }
    

    3.4 GPIO中断使用

  • 要使用GPIO中断首先要对中断结构体HAL_GPIO_IRQ_CFG_T进行配置

    struct HAL_GPIO_IRQ_CFG_T cfg;
      cfg.irq_debounce = 1;
      cfg.irq_enable = 1;
      cfg.irq_type = HAL_GPIO_IRQ_TYPE_EDGE_SENSITIVE; // 边沿触发
      cfg.irq_handler = gpio_irq_handler;     //中断回调函数
      cfg.irq_polarity = HAL_GPIO_IRQ_POLARITY_HIGH_RISING; // 上升沿触发
    
  • 在结构体中已经引用了回调函数,因此下一步便是设置回调函数

    static void gpio_irq_handler(enum HAL_GPIO_PIN_T pin)
    {
     uint8_t val = hal_gpio_pin_get_val(pin);        
     printf("irq: gpio %d, val %d\r\n", pin, val);
    }
    
  • 最后再注册中断回调函数

    hal_gpio_setup_irq(HAL_GPIO_PIN_P0_5, &cfg); //将回调函数注册给GPIO P0_5
    

    3.5 Demo演示

  • 将前文中使用到的各个例程结合起来可以得到:

    void gpio_test(void)
    {
     //IO配置
     struct HAL_IOMUX_PIN_FUNCTION_MAP pinmux[] = {
         {HAL_GPIO_PIN_P0_2, HAL_IOMUX_FUNC_AS_GPIO, HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_NOPULL},
         {HAL_GPIO_PIN_P0_4, HAL_IOMUX_FUNC_AS_GPIO, HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_NOPULL},
         {HAL_GPIO_PIN_P0_5, HAL_IOMUX_FUNC_AS_GPIO, HAL_IOMUX_PIN_VOLTAGE_MEM, HAL_IOMUX_PIN_NOPULL},
     };
    
     hal_iomux_init(pinmux, ARRAY_SIZE(pinmux)); //IO初始化
     //IO输入输出设置
     hal_gpio_pin_set_dir(HAL_GPIO_PIN_P0_2, HAL_GPIO_DIR_OUT, 0);
     hal_gpio_pin_set_dir(HAL_GPIO_PIN_P0_4, HAL_GPIO_DIR_IN, 0);
     hal_gpio_pin_set_dir(HAL_GPIO_PIN_P0_5, HAL_GPIO_DIR_IN, 0);
    
     //IRQ cfg配置
     struct HAL_GPIO_IRQ_CFG_T cfg;
     cfg.irq_debounce = 1;
     cfg.irq_enable = 1;
     cfg.irq_type = HAL_GPIO_IRQ_TYPE_EDGE_SENSITIVE; 
     cfg.irq_handler = gpio_irq_handler;  //回调函数
     cfg.irq_polarity = HAL_GPIO_IRQ_POLARITY_HIGH_RISING;
     hal_gpio_setup_irq(HAL_GPIO_PIN_P0_5, &cfg);  //注册
    
     gpio_output_test(); //见前文
    
     gpio_input_test(); //见前文
    }
    
  • 此例程配置了P0_2、P0_4、P0_5三个GPIO,02设置为输出口,初始低电平,04、05设置为输入口

  • 02口用于输出电平测试,04口用于输入电平测试,05口用于中断测试
  • 02口输出高电平后1s输出低电平,并串口打印信息
  • 将02口与04口连接,04口输入高电平时与初始值(0)不同,串口打印信息与当前电平
  • 将02口与05口连接,电平上升沿触发中断,串口打印相应信息

    注:在wifi_app/app/bes_test中可查看源码