GPIO编程实践

  1. 功能描述
  2. 实践要点
    1. 基础知识
    2. 输入/输出
    3. 中断
  3. 附录

功能描述

  • 操控开发板GPIO,实现GPIO输入、输出、中断

实践要点

基础知识

  • GPIO属于较简单的设备,由led编程实践可知,GPIO的操作,通常使用sysfs方式。

  • GPIO存放的目录:/sys/class/gpio

  • gpiochipX

    • 当前SoC所包含的GPIO控制器,不同芯片的GPIO控制器不同,可以去芯片的datasheet查询。I.MX6U有5个GPIO控制器,GPIO1-GPIO5,分为对应gpiochip0-gpiochip128。每一个gpiochipX文件夹用来管理一组GPIO。
    • base:该控制器所管理的这组GPIO中引脚最小的编号。
    • label:GPOIO对应的标签(名字)。
    • ngpio:该控制器所管理的GPIO引脚的数量(引脚编号范围:base ~ base + ngpio - 1)。
  • /sys/class/gpio目录下:

    • export:用于将指定编号的gpio导出。

      echo 0 > export
      

      上述命令表示导出gpio0。

      注意:并不是所有gpio引脚都可以成功导出。如果已经被内核占用了,则无法导出,会报Device or resource busy的错误信息。

    • unexport:取消导出指定编号的gpio。

      echo 0 > unexport
      
    • gpiox:导出的对应的gpio引脚对应的文件夹,用于管理、控制该GPIO引脚。

  • gpioX

    • direction:配置gpio引脚的输入或输出模式。

      echo "in" > direction
      echo "out" > direction
      
    • value:输出模式下,写入0/1改变gpio的状态;输入模式下,读取gpio的值。

    • active_low:用于gpio的极性控制,默认为0(gpio电平1代表高,0代表低,否则gpio电平1代表低,0代表高)。

    • edge:控制中断的触发模式。

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

输入/输出

  • 这没什么好说的,导出对应的gpio后,通过sysfs方式打开对应文件,通过读写来管理或控制gpio状态即可。

中断

  • 当引脚被配置为中断后,可以使用poll()函数监听引脚的电平状态变化(poll函数可以监视一个或多个文件描述符上的I/O状态变化)。函数poll用法可查阅《Unix环境高级编程(第3版)》第408页。

  • 核心代码解析

    struct pollfd pfd;
    
    pfd.fd = open(gpioValuePath, O_RDONLY);
    if(pfd.fd == -1) {
        perror("open error");
        exit(-1);
    }
    pfd.events = POLLPRI;						//POLLPRI 可以不阻塞地读高优先级数据,中断是一种高优先级事件
    ret = read(pfd.fd, &val, 1);				//先读取一次清除状态
    if(ret < 0) {
        perror("read error");
        close(fd);
        exit(-1);
    }   
    /*
    poll函数:
    int poll(struct pollfd fdarray[], nfds_t nfds, int timeout);
    timeout == -1 : 永远等待。当所指定的描述符中的一个已经准备好,或捕捉到一个信号时返回。 
    (0:不等待 >0:等待timeout ms)
    */
    for(;;) {
        ret = poll(&pfd, 1, -1);
        if(ret < 0) {
            perror("poll error");
            exit(-1);
        }
        else if(ret == 0) {
            printf("poll timeout.\n");
            continue;
        }
    
        if(pfd.events & POLLPRI) {   			//判断中断是否触发
            //这里面可以实现自己的中断触发后执行的逻辑代码。
            if(lseek(pfd.fd, 0, SEEK_SET) < 0) {//回到文件开头
                perror("lseekk error");
                exit(-1);
            }
            if(read(pfd.fd, &val, 1) < 0) {		//读gpio value值
                perror("read error");
                exit(-1);
            }
    
            printf("GPIO中断触发,value=%c\n", val);
        }
    }
    

附录


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以邮件至 sigma_poet@126.com

💰

×

Help us with donation