正点原子阿尔法监测GPIO中断触发

文章介绍了如何利用poll函数监听GPIO中断,在Linux系统下编写GPIO中断程序,包括配置GPIO为输入模式、设置中断触发方式,以及读取中断事件。程序会阻塞等待直到有中断发生,然后读取并打印中断触发时的电平状态。
摘要由CSDN通过智能技术生成

目录

一、poll函数介绍

二、GPIO中断程序编写

三、运行可执行程序

四、作者自述


一、poll函数介绍

1. poll函数events标志       

        本实验为GPIO中断触发实验,所以需要一个机制能够检测中断的触发,中断的优先级高于主程序运行的优先级,而poll函数刚好提供了一个监听高优先级事件的标志,所以本实验采用poll函数去监听IO口有无触发中断。

2.struct pollfd结构体

struct pollfd {
int fd;
short events; 
short revents; 
};
tips: fd 是一个文件描述符,struct pollfd 结构体中的 events 和 revents 都是位掩码,调用者初始化 events 来指定需要为文件描述符 fd 做检查的事件。当 poll()函数返回时,revents 变量由 poll()函数内部进行设置,用于说明文件描述符 fd 发生了哪些事件(注意,poll()没有更改 events 量),我们可以对 revents 进行检查,判断文件描述符 fd 发生了什么事件。
3.events和revents标志

 tips:POLLIN、POLLRDNORMPOLLRDBANDPOLLPRIPOLLRDHUP与数据可读相关;POLLOUTPOLLWRNORMPOLLWRBAND与可写数据相关;POLLERR、POLLHUPPOLLNVAL)是设定在 revents 变量中用来返回有关文件描述符的附加信息,如果在 events 变量中指定了这三个标志,则会被忽略。

二、GPIO中断程序编写

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

static char gpio_path[100];

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

    //配置gpio电气属性
    sprintf(file_path,"%s/%s",gpio_path,attr);
    fd = open(file_path,O_WRONLY);//只写方式打开文件
    if(fd < 0)
    {
        fprintf(stderr,"打开%s文件失败!!!\n",file_path);
        return -1;
    }

    len = strlen(val);
    if(write(fd,val,len) != len)  //配置模式参数
    {
        perror("write error");
        close(fd);
        return -1;
    }

    close(fd);
    return 0;

}

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

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

    //判断需要操作的GPIO是否导出
    sprintf(gpio_path,"/sys/class/gpio/gpio%s",argv[1]);
    ret = access(gpio_path,F_OK);
    if(ret != 0)  //目录不存在
    {
        int fd,len;

        fd = open("/sys/class/gpio/export",O_WRONLY);//只写方式打开文件
        if(fd < 0)
        {
            perror("open error");
            exit(-1);
        }

        len = strlen(argv[1]);
        //导出gpio
        if(write(fd,argv[1],len) != len)
        {
            fprintf(stderr,"导出gpio失败\n");
            close(fd);
            exit(-1);
        }
        close(fd); //关闭export文件
    }

    //配置为输入模式
    ret = gpio_config("direction","in");
    if(ret < 0)
    {
        fprintf(stderr,"配置输入模式出错\n");
        exit(-1);
    }

    //配置极性
    ret = gpio_config("active_low","0");
    if(ret < 0)
    {
        fprintf(stderr,"配置极性出错\n");
        exit(-1);
    }

    //配置中断出发方式,上升沿和下降沿(边沿触发)
    ret = gpio_config("edge","both");
    if(ret < 0)
    {
        fprintf(stderr,"配置触发方式出错\n");
        exit(-1);
    }

    //打开value属性文件
    sprintf(file_path,"%s/%s",gpio_path,"value");
    pfd.fd = open(file_path,O_RDONLY);
    if(pfd.fd < 0)
    {
        fprintf(stderr,"打开value属性文件出错\n");
        exit(-1);
    }

    //poll监听事件
    pfd.events = POLLPRI;//指定监听事件,只关心高优先级数据可读
    ret = read(pfd.fd,&val,1); //先读取一次清除标志
    if(ret < 0)
    {
        fprintf(stderr,"读取中断事件出错\n");
        exit(-1);
    }

    for(;;)
    {
        ret = poll(&pfd,1,-1);//阻塞监听知道有事件发生
        if(ret < 0)
        {
            fprintf(stderr,"poll error");
            exit(-1);
        }
        //返回 0 表示该调用在任意一个文件描述符成为就绪态之前就超时了。
        else if(ret == 0)
        {
            fprintf(stderr,"poll timeout\n");
            continue;//回到for循环继续执行
        }

        //检查高优先级数据是否可读
        if(pfd.revents & POLLPRI)
        {
            ret = lseek(pfd.fd,0,SEEK_SET);//将光标位置移到头部
            if(ret < 0)
            {
                perror("lseek error");
                exit(-1);
            }
            
            //往value属性文件里面读取一个数据
            ret = read(pfd.fd,&val,1);
            if(ret < 0)
            {
                perror("read error");
                exit(-1);
            }

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

}

三、运行可执行程序

1.交叉编译源文件

 arm-linux-gnueabihf-gcc gpio_exti.c -o gpio_extiAPP

2.运行可执行文件

./gpio_extiAPP 1
tips:”gpio_extiAPP“为可执行文件程序名。”1“为gpio端口

 tips:本实验为GPIO边沿触发中断实验,可以将gpio1交替连接到3.3V和GND端口模拟上升沿和下降沿,查看GPIO端口电平变化状态。

四、作者自述

        记录生活。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
下面是一个使用epoll机制监测GPIO中断C语言demo: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <poll.h> #include <errno.h> #include <string.h> #include <sys/epoll.h> #define GPIO_PIN_NUM 17 // 监测GPIO引脚号 #define MAX_EVENTS 2 // 监测的最大事件数 int main() { int fd, epoll_fd, ret, count = 0; char buf[MAX_EVENTS]; struct epoll_event event, events[MAX_EVENTS]; struct pollfd pfd; // 打开GPIO文件 fd = open("/sys/class/gpio/gpio17/value", O_RDONLY); if(fd < 0) { printf("Failed to open GPIO file!\n"); return -1; } // 设置GPIO引脚为输入模式 fd = open("/sys/class/gpio/gpio17/direction", O_WRONLY); if(fd < 0) { printf("Failed to open GPIO direction file!\n"); return -1; } write(fd, "in", 2); close(fd); // 创建epoll实例 epoll_fd = epoll_create(1); if(epoll_fd < 0) { printf("Failed to create epoll instance!\n"); return -1; } // 添加GPIO文件描述符到epoll实例中 event.events = EPOLLIN | EPOLLET; event.data.fd = fd; ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &event); if(ret < 0) { printf("Failed to add GPIO file descriptor to epoll instance!\n"); return -1; } // 等待GPIO中断事件发生 while(1) { ret = epoll_wait(epoll_fd, events, MAX_EVENTS, -1); if(ret < 0) { printf("Failed to wait for events!\n"); return -1; } else if(ret == 0) { printf("Timeout!\n"); } else { // 遍历所有就绪事件 for(int i = 0; i < ret; i++) { if(events[i].events & EPOLLIN) { // 读取GPIO文件内容 lseek(events[i].data.fd, 0, SEEK_SET); read(events[i].data.fd, buf, MAX_EVENTS); // 处理GPIO中断事件 if(buf[0] == '0') { printf("GPIO interrupt detected! Count: %d\n", ++count); } } } } } // 关闭文件描述符和epoll实例 close(fd); close(epoll_fd); return 0; } ``` 这个demo使用了poll()和epoll_wait()函数来监测GPIO中断事件。首先,程序打开GPIO文件并将GPIO引脚设置为输入模式。然后,创建epoll实例并将GPIO文件描述符添加到epoll实例中。最后,程序在一个无限循环中等待epoll事件的发生,当有事件发生时,程序读取GPIO文件内容并处理GPIO中断事件。需要注意的是,该程序只监测一个GPIO引脚的中断事件,如果需要监测多个GPIO引脚,需要在程序中添加相应的代码。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值