GPIO 应用编程-I.MX6U嵌入式Linux C应用编程学习笔记基于正点原子阿尔法开发板

GPIO 应用编程

在这里插入图片描述

应用层如何操控 GPIO

GPIO 控制器管理

  • I.MX6UL/I.MX6ULL 包含 5 个 GPIO 控制器GPIO1、GPIO2、GPIO3、GPIO4、GPIO5,分别对应 gpiochip0、gpiochip32、gpiochip64、gpiochip96、gpiochip128

  • 每个 gpiochipX 文件夹管理一组 GPIO 引脚,包含 base、label、ngpio 属性文件

    • base:表示该控制器管理的GPIO引脚中最小的编号。这个基数值与gpiochipX中的X是相同的,通过这个编号系统可以索引到具体的GPIO引脚

    • label:提供该组GPIO的标签或名称,方便用户识别不同的GPIO组

    • ngpio:显示该控制器所管理的GPIO引脚的总数。引脚的编号范围从base开始,到base+ngpio-1结束

GPIO 引脚编号计算

  • 例如,GPIO4_IO16 对应编号为 96 + 16 = 112

GPIO 引脚导出与删除

  • 使用 export 文件导出 GPIO 引脚在/sys/class/gpio 目录下生成 gpioX 文件夹

    • export 文件是只写文件

    • 已被内核使用的引脚无法导出

    • echo 0 > export # 导 出 编 号 为 0 的 GPIO 引 脚

  • 使用 unexport 文件删除导出的 GPIO 引脚

    • unexport 文件是只写文件

    • echo 0 > unexport # 删除导出的编号为 0 的 GPIO 引脚

GPIO 引脚控制(文件可读可写)

  • 在 gpioX 文件夹中,通过 direction 文件设置输入/输出模式

    • 该文件可读、可写

    • “out”(输出模式)

    • “in”(输入模式)

  • 通过 value 文件控制输出电平或读取输入电平

    • 输出模式下

      • "0"控制 GPIO 引脚输出低电平

      • "1"控制 GPIO 引脚输出高电平

    • 输入模式下

      • 读取 value 文件获取 GPIO 引脚当前的输入电平状态
  • active_low 文件控制极性

    • 该文件可读可写

    • active_low 等于 0 时

echo “0” > active_low
echo “out” > direction
echo “1” > value #输出高
echo “0” > value #输出低

active_low 等于 1 时

$ echo “1” > active_low
$ echo “out” > direction
$ echo “1” > value #输出低
$ echo “0” > value #输出高

  • edge 文件设置中断触发模式

    • 该文件可读可写

    • 非中断引脚:echo “none” > edge
      上升沿触发:echo “rising” > edge
      下降沿触发:echo “falling” > edge
      边沿触发:echo “both” > edge

    • 当引脚被配置为中断后可以使用 poll()函数监听引脚的电平状态变化

GPIO 应用编程之输出

开始:程序的入口点

参数检查是否为三个

  • 是则构造GPIO路径

    • 通过路径检查GPIO是否已导出

      • 否则打开"/sys/class/gpio/export"

        • 写入GPIO编号,导出GPIO

        • 关闭文件

  • 否则输出用法信息,程序退出

配置GPIO为输出模式

  • 配置为输出模式

  • 配置极性

  • 控制GPIO输出高低电平

正常退出:程序正常退出,返回状态 0

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

//存储GPIO路径
static char gpio_path[100];

//将用户指定的值写入到给定GPIO属性的文件中
static int gpio_config(const char *attr, const char *val)
{
    char file_path[100];
    int len;
    int fd;

    sprintf(file_path, "%s/%s", gpio_path, attr);
    if (0 > (fd = open(file_path, O_WRONLY))) {
        perror("open error");
        return fd;
    }

    len = strlen(val);
    if (len != write(fd, val, len)) {
        perror("write error");
        close(fd);
        return -1;
    }

    close(fd);  //关闭文件
    return 0;
}

int main(int argc, char *argv[])
{
    /* 校验传参 */
    if (3 != argc) {
        fprintf(stderr, "usage: %s <gpio> <value>\n", argv[0]);
        exit(-1);
    }

    /* 判断指定编号的GPIO是否导出 */
    sprintf(gpio_path, "/sys/class/gpio/gpio%s", argv[1]);

    //如果路径存在,access 返回 0
    if (access(gpio_path, F_OK)) {//如果目录不存在 则需要导出

        int fd;
        int len;

        if (0 > (fd = open("/sys/class/gpio/export", O_WRONLY))) {
            //perror调用此函数不需要传入 errno,会直接将错误提示字符串打印出来,
            //除此之外还可以在输出的错误提示字符串之前加入自己的打印信息
            perror("open error");
            exit(-1);
        }

        len = strlen(argv[1]);
        //如果写入长度与值长度不符
        if (len != write(fd, argv[1], len)) {//导出gpio
            perror("write error");
            close(fd);
            exit(-1);
        }

        close(fd);  //关闭文件
    }

    /* 配置为输出模式 */
    if (gpio_config("direction", "out"))
        exit(-1);

    /* 极性设置 */
    if (gpio_config("active_low", "0"))
        exit(-1);

    /* 控制GPIO输出高低电平 */
    if (gpio_config("value", argv[2]))
        exit(-1);

    /* 退出程序 */
    exit(0);
}

GPIO 应用编程之输入

开始:程序的入口点

参数检查是否为两个

  • 是则构造GPIO路径

    • 通过路径检查GPIO是否已导出

      • 否则打开"/sys/class/gpio/export"

        • 写入GPIO编号,导出GPIO

        • 关闭文件

  • 否则输出用法信息,程序退出

配置GPIO为输出模式

  • 配置为输入模式

  • 配置极性

  • 配置为非中断方式

读取GPIO电平状态

  • 拼接value文件的路径

  • 尝试打开value文件

    • 如果打开失败,打印错误信息并退出程序
  • 尝试读取文件内容(GPIO的当前值)

    • 如果读取失败,打印错误信息并退出程序
  • 打印读取到的GPIO值

关闭打开的文件

正常退出:程序正常退出,返回状态 0

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

static char gpio_path[100];

static int gpio_config(const char *attr, const char *val)
{
    char file_path[100];
    int len;
    int fd;

    sprintf(file_path, "%s/%s", gpio_path, attr);
    if (0 > (fd = open(file_path, O_WRONLY))) {
        perror("open error");
        return fd;
    }

    len = strlen(val);
    if (len != write(fd, val, len)) {
        perror("write error");
        close(fd);
        return -1;
    }

    close(fd);  //关闭文件
    return 0;
}

int main(int argc, char *argv[])
{
    char file_path[100];
    char val;
    int fd;

    /* 校验传参 */
    if (2 != argc) {
        fprintf(stderr, "usage: %s <gpio>\n", argv[0]);
        exit(-1);
    }

    /* 判断指定编号的GPIO是否导出 */
    sprintf(gpio_path, "/sys/class/gpio/gpio%s", argv[1]);

    if (access(gpio_path, F_OK)) {//如果目录不存在 则需要导出

        int len;

        if (0 > (fd = open("/sys/class/gpio/export", O_WRONLY))) {
            perror("open error");
            exit(-1);
        }

        len = strlen(argv[1]);
        if (len != write(fd, argv[1], len)) {//导出gpio
            perror("write error");
            close(fd);
            exit(-1);
        }

        close(fd);  //关闭文件
    }

    /* 配置为输入模式 */
    if (gpio_config("direction", "in"))
        exit(-1);

    /* 极性设置 */
    if (gpio_config("active_low", "0"))
        exit(-1);

    /* 配置为非中断方式 */
    if (gpio_config("edge", "none"))
        exit(-1);

    /* 读取GPIO电平状态 */
    sprintf(file_path, "%s/%s", gpio_path, "value");

    if (0 > (fd = open(file_path, O_RDONLY))) {
        perror("open error");
        exit(-1);
    }

    if (0 > read(fd, &val, 1)) {
        perror("read error");
        close(fd);
        exit(-1);
    }

    printf("value: %c\n", val);

    /* 退出程序 */
    close(fd);
    exit(0);
}

GPIO 应用编程之中断

开始:程序的入口点

参数检查是否为两个

  • 是则构造GPIO路径

    • 通过路径检查GPIO是否已导出

      • 否则打开"/sys/class/gpio/export"

        • 写入GPIO编号,导出GPIO

        • 关闭文件

  • 否则输出用法信息,程序退出

配置GPIO为输出模式

  • 配置为输入模式

  • 配置极性

  • 配置中断触发方式: 上升沿和下降沿

打开value属性文件

  • 如果打开失败,显示错误信息并退出程序

初始化poll结构体

  • 设置关心的事件为POLLPRI

首次读取状态以清除

循环等待GPIO中断

  • 调用poll等待事件

    • 如果poll出错,显示错误信息并退出程序

    • 如果poll超时,继续循环

  • 如果检测到中断(POLLPRI事件)

    • 将读位置移动到头部

      • 如果移动失败,显示错误信息并退出程序
    • 读取新的GPIO值

      • 如果读取失败,显示错误信息并退出程序
    • 打印GPIO中断信息

结束:程序正常执行不会到达此步骤,因为它处于无限循环中等待GPIO中断事件

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <poll.h>

static char gpio_path[100];

static int gpio_config(const char *attr, const char *val)
{
    char file_path[100];
    int len;
    int fd;

    sprintf(file_path, "%s/%s", gpio_path, attr);
    if (0 > (fd = open(file_path, O_WRONLY))) {
        perror("open error");
        return fd;
    }

    len = strlen(val);
    if (len != write(fd, val, len)) {
        perror("write error");
        return -1;
    }

    close(fd);  //关闭文件
    return 0;
}

int main(int argc, char *argv[])
{
    struct pollfd pfd;
    char file_path[100];
    int ret;
    char val;

    /* 校验传参 */
    if (2 != argc) {
        fprintf(stderr, "usage: %s <gpio>\n", argv[0]);
        exit(-1);
    }

    /* 判断指定编号的GPIO是否导出 */
    sprintf(gpio_path, "/sys/class/gpio/gpio%s", argv[1]);

    if (access(gpio_path, F_OK)) {//如果目录不存在 则需要导出

        int len;
        int fd;

        if (0 > (fd = open("/sys/class/gpio/export", O_WRONLY))) {
            perror("open error");
            exit(-1);
        }

        len = strlen(argv[1]);
        if (len != write(fd, argv[1], len)) {//导出gpio
            perror("write error");
            exit(-1);
        }

        close(fd);  //关闭文件
    }

    /* 配置为输入模式 */
    if (gpio_config("direction", "in"))
        exit(-1);

    /* 极性设置 */
    if (gpio_config("active_low", "0"))
        exit(-1);

    /* 配置中断触发方式: 上升沿和下降沿 */
    if (gpio_config("edge", "both"))
        exit(-1);

    /* 打开value属性文件 */
    sprintf(file_path, "%s/%s", gpio_path, "value");

    if (0 > (pfd.fd = open(file_path, O_RDONLY))) {
        perror("open error");
        exit(-1);
    }

    /* 调用poll */
    //POLLPRI标志表示有高优先级事件发生,通常与中断相关
    pfd.events = POLLPRI; //只关心高优先级数据可读(中断)

    read(pfd.fd, &val, 1);//先读取一次清除状态
    for ( ; ; ) {

        ret = poll(&pfd, 1, -1);    //调用poll
        //如果返回值ret小于0,表示poll()调用失败
        if (0 > ret) {
            perror("poll error");
            exit(-1);
        }
        //如果返回值ret等于0,表示poll()调用在指定的超时时间内没有检测到任何事件
        else if (0 == ret) {
            fprintf(stderr, "poll timeout.\n");
            //continue语句跳过当前循环的剩余部分,直接开始下一次循环迭代
            continue;
        }

        /* 校验高优先级数据是否可读 */
        if(pfd.revents & POLLPRI) {//检查revents字段中是否设置了POLLPRI位
            //lseek控制文件读写位置
            //文件的开始(SEEK_SET)
            if (0 > lseek(pfd.fd, 0, SEEK_SET)) {//将读位置移动到头部
                perror("lseek error");
                exit(-1);
            }

            if (0 > read(pfd.fd, &val, 1)) {
                perror("read error");
                exit(-1);
            }

            printf("GPIO中断触发<value=%c>\n", val);
        }
    }

    /* 退出程序 */
    exit(0);
}

在开发板上测试

GPIO 输出测试

  • ./testApp 1 1 #控制 GPIO1_IO01 输出高电平

  • ./testApp 1 0
    #控制 GPIO1_IO01 输出低电平

GPIO 输入测试

  • ./testApp 1
    #读取 GPIO1_IO01 引脚此时的电平状态

GPIO 中断测试

  • ./testApp 1
    # 监测 GPIO1_IO01 引脚中断触发

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-20 16:04:04       123 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-20 16:04:04       131 阅读
  3. 在Django里面运行非项目文件

    2024-07-20 16:04:04       109 阅读
  4. Python语言-面向对象

    2024-07-20 16:04:04       117 阅读

热门阅读

  1. 题解:T480715 true

    2024-07-20 16:04:04       28 阅读
  2. 你有多自律就有多自由

    2024-07-20 16:04:04       30 阅读
  3. 2024 暑假友谊赛 2

    2024-07-20 16:04:04       32 阅读
  4. 【CTFWP】ctfshow——web41

    2024-07-20 16:04:04       30 阅读
  5. Scala学习笔记19: 隐式转换和隐式参数

    2024-07-20 16:04:04       29 阅读
  6. Qmi8658a姿态传感器使用心得(2)linux

    2024-07-20 16:04:04       26 阅读
  7. springcloud与dubbo的rpc通信都是分别基于什么实现的

    2024-07-20 16:04:04       25 阅读
  8. AI论文写作软件哪些比较好用?

    2024-07-20 16:04:04       28 阅读
  9. vue-treeselect

    2024-07-20 16:04:04       30 阅读
  10. 反悔贪心

    2024-07-20 16:04:04       25 阅读
  11. 我们的耳穴项目迈进了一大步

    2024-07-20 16:04:04       29 阅读
  12. 【前后端联调】HttpMessageNotReadableException

    2024-07-20 16:04:04       25 阅读
  13. 恒等式结论

    2024-07-20 16:04:04       24 阅读
  14. Https post 请求时绕过证书验证方案

    2024-07-20 16:04:04       28 阅读