Linux无需开发底层驱动,从应用层获取GPIO中断

来源:互联网 发布:细说php完整版精要版 编辑:程序博客网 时间:2024/06/05 04:30

写在前头

*.版权声明:本篇文章为原创,可随意转载,转载请注明出处,谢谢!另我创建一个QQ群82642304,欢迎加入!


获取中断

  1. GPIO中断在嵌入式开发中经常用到,到了linux下,处理GPIO的中断就没有裸机那么简单了。 Linux内核中有一套GPIO框架,管理和控制芯片上的GPIO管教,包括配置输入输出,配置电平高低(输出)和获取电平高低(输入),中断管理。
  2. CPU厂家需要按照GPIO框架的接口,实现底层的具体控制。一般的话,厂家提供的SDK都已经开发好了,不需要客户去开发。
  3. 应用层上控制GPIO网上有许多资料,但是获取中断,网上的大部分资料都是需要开发底层驱动,由底层驱动获取到GPIO的中断然后再通知应用层。
  4. 对于不想开发驱动的我来说,还有另外一种方法可以直接从应用层上获取到GPIO的中断,Linux内核文档Documentation/gpio/gpio-legacy.txt:691中提到的:
691     "value" ... reads as either 0 (low) or 1 (high).  If the GPIO692         is configured as an output, this value may be written;693         any nonzero value is treated as high.694 695         If the pin can be configured as interrupt-generating interrupt696         and if it has been configured to generate interrupts (see the697         description of "edge"), you can poll(2) on that file and698         poll(2) will return whenever the interrupt was triggered. If699         you use poll(2), set the events POLLPRI and POLLERR. If you700         use select(2), set the file descriptor in exceptfds. After701         poll(2) returns, either lseek(2) to the beginning of the sysfs702         file and read the new value or close the file and re-open it703         to read the value.704 705     "edge" ... reads as either "none", "rising", "falling", or706         "both". Write these strings to select the signal edge(s)707         that will make poll(2) on the "value" file return.708 709         This file exists only if the pin can be configured as an710         interrupt generating input pin.

就是说可以通过读取/sys/class/gpio/gpioN/value的值来获取中断。
5. 但是不是简单的read,而是通过epoll、poll、select等这些IO复用函数来控制,对于epoll或者poll,需要监听的事件是EPOLLPRI或POLLPRI,而不是EPOLLIN或POLLIN,对于select,需要将文件描述符放在exceptfds中,而且文件描述符被触发时需要通过调用read读取数据,还要通过lseek将文件流指针置回文件开头。


例如

对于epoll来说,伪代码如下

...#include <sys/epoll.h>...int main(int argc,char * argv[]){    struct epoll_event evd;    struct epoll_event * events;    ...    int epollfd = epoll_create(10);    ...    events = calloc (10, sizeof(struct epoll_event));    evd.data.fd = fd;    evd.events = EPOLLPRI;    epoll_ctl(epollfd,EPOLL_CTL_ADD,fd,&evd);     while (1) {        n = epoll_wait(epollfd,events,10,-1);        for (i = 0;i < n;i++) {            if (events[i].events & EPOLLPRI) {                memset(buf,0x00,sizeof(buf));                read(events[i].data.fd,buf,sizeof(buf));                lseek(events[i].data.fd,0,SEEK_SET);                //do yourself            }        }    }}

对于poll,伪代码如下

...#include <sys/poll.h>...int main(int argc,char* argv[]){    struct pollfd fdset;    unsigned char buf[128];    while (1) {        memset(&fdset,0x00,sizeof(struct pollfd));        fdset.fd = fd;         fdset.events = POLLPRI;        poll(&fdset,1,3000);        if (fdset.events & POLLPRI) {            read(fdset.fd,buf,sizeof(buf));            lseek(fdset.fd,0,SEEK_SET);            //do yourself        }    }}

select的话我就不写了,一样的做法。
另,我实际测试,使用epoll或者poll时监听事件(POLLIN | POLLET)也是可以的。

0 0
原创粉丝点击