GPIO 设备

更新时间:
2024-03-14
下载文档

GPIO 设备

GPIO(General Purpose Input/Output),即通用输入/输出端口,以下简称 I/O 端口。一个 I/O 端口可提供输入、输出或中断三类功能,SylixOS 中的 GPIO 设备管理整个硬件系统上所有可用的 GPIO 端口,使应用程序能够通过标准接口使用 GPIO 的三类功能。GPIO 设备的相关定义位于 <sys/gpiofd.h> 文件,相关 API 描述如下。

#include <sys/gpiofd.h>
int gpiofd(unsigned int gpio, int flags, int gpio_flags);
int gpiofd_read(int fd, uint8_t *value);
int gpiofd_write(int fd, uint8_t  value);

函数 gpiofd 原型分析:

  • 此函数成功时返回对应 GPIO 端口的文件描述符,失败时返回负数。
  • 参数 gpio 为 GPIO 端口的唯一编号,该编号与具体的系统硬件相关,应用程序应该参考 BSP 包对 GPIO 端口编号的定义来正确选择。
  • 参数 flags 与 open 函数的第二个参数意义相似,即可以是 O_RDONLY、O_RDWR 等。
  • 参数 gpio_flags 是与 GPIO 特性相关的标识,它可以是多个位标识的组合。参考下表:

注意
当使用了 GPIO_FLAG_TRIG_LEVE 标识时,我们仅能用 GPIO_FLAG_TRIG_FALL 与 GPIO_FLAG_TRIG_RISE 中的一个与其组合使用,分别表示低电平触发和高电平触发。当没有使用 GPIO_FLAG_TRIG_LEVE 时,我们可以将 GPIO_FLAG_TRIG_FALL 和 GPIO_FLAG_TRIG_RISE 组合使用表示双边沿触发。

函数 gpiofd_read 读取一个 GPIO 端口的电平状态,只有 0 和 1 两个值,原型分析如下:

  • 此函数成功返回 0,失败返回错误码。
  • 参数 fd 为 GPIO 端口对应的文件描述符。
  • 输出参数 value 保存读取到的电平值,0 表示低电平,1 表示高电平。

函数 gpiofd_write 设置一个 GPIO 端口的电平状态,只有 0 和 1 两个值,原型分析如下:

  • 此函数成功返回 0,失败返回错误码。
  • 参数 fd 为 GPIO 端口对应的文件描述符。
  • 参数 value 为需要设置的电平值,0 表示低电平,1 表示高电平。

上面的函数仅能处理 GPIO 的输入输出,但无法使用其中断功能。因为在驱动程序中使用 GPIO 的中断功能的方式是调用系统内核 API 注册相应的中断服务程序,但应用程序不能调用这些函数。

我们知道,I/O 多路复用(select)允许任务阻塞地等待一个或多个文件描述符满足指定状态(可读、可写或异常)。SylixOS 利用这一点,为应用程序提供了使用 GPIO 中断功能的方法。当一个具有中断功能的 GPIO 产生中断时,内核会唤醒所有通过调用 select 等待该 GPIO 文件描述符可读状态的线程,通知线程中断产生。当 select 正确返回时,线程处理相应的事务,这类似于完成了一次中断服务。

以下程序展示了 GPIO 设备的一般使用方法。

#include <stdio.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/gpiofd.h>
#define LED_GPIO_NUM    52
#define KEY_GPIO_NUM    32
int  main (int  argc, char  *argv[])
{
    fd_set      fdset;
    int         led_fd;
    int         key_fd;
    int         ret;
    uint8_t     value = 1;
    led_fd = gpiofd(LED_GPIO_NUM, O_WRONLY, GPIO_FLAG_OUT_INIT_LOW);
    if (led_fd < 0) {
        fprintf(stderr, "open led gpiofd failed.\n");
        return  (-1);
    }
    key_fd = gpiofd(KEY_GPIO_NUM, O_RDONLY, GPIO_FLAG_TRIG_FALL);
    if (key_fd < 0) {
        fprintf(stderr, "open key gpiofd failed.\n");
        return  (-1);
    }
    while (1) {
        FD_ZERO(&fdset);
        FD_SET(key_fd, &fdset);
/*  
* 等待按键中断产生。
*/
        ret = select(key_fd + 1, &fdset, NULL, NULL, NULL);
        if (ret != 1) {
            fprintf(stderr, "select error.\n");
            break;
        }
        gpiofd_write(led_fd, value);
        value = !value;
    }
    close(led_fd);
    close(key_fd);
    return  (0);
}

上面的程序中,我们假设控制 LED 的端口编号为 52,检测按键中断的端口编号为 32,并假设当按键按下时会产生一个下降沿中断。我们将 fdset 设置为 select 函数的读等待文件描述符集,即等待按键 GPIO 文件可读,实际上就是等待按键中断产生。上面程序的效果是,每当按下一次按键,LED 灯的状态就会改变一次(从点亮到熄灭或从熄灭到点亮)。

文档内容是否对您有所帮助?
有帮助
没帮助