使用文件IO操作GPIO SysFs方式

来源:互联网 发布:mac手绘用什么软件 编辑:程序博客网 时间:2024/05/18 17:23
 

使用文件IO操作GPIO SysFs方式

转自:http://blog.csdn.net/xukai871105/article/details/38456801
0 前言
    本文描述如果通过文件IO sysfs方式控制树莓派 GPIO端口。通过sysfs方式控制GPIO,先访问/sys/class/gpio目录,向export文件写入GPIO编号,使得该GPIO的操作接口从内核空间暴露到用户空间,GPIO的操作接口包括direction和value等,direction控制GPIO方向,而value可控制GPIO输出或获得GPIO输入。
    Linux学习可从应用出发,先不纠结Linux驱动编写,先把Linux给玩起来。

    【相同与不同】
    本文和【EasyARM i.mx28学习笔记——文件IO方式操作GPIO】内容相似,大部分代码相同。通过文件IO操作可以有效地避免平台差异,虽然EasyARM im287平台和树莓派完全不同,但是通过sysfs操作GPIO实现代码大致相同。
    和EasyARM im287不同,此处并没有使用交叉编译工具,有树莓派中的gcc工具链编译链接获得可执行文件,而EasyARM im287并不能这样操作。EasyARM im287采用busybox指令集,这也与树莓派中的debian指令集存在差异。

    【相关博文】
    【EasyARM i.mx28学习笔记——文件IO方式操作GPIO】
    【树莓派学习笔记——Shell脚本操作GPIO】
    【树莓派学习笔记——交叉编译工具链】
    【 Linux学习笔记——例说makefile 索引博文】

    【代码仓库】
    代码仓库位于bitbucket——rpi-gpio-sysfs ,请使用Hg克隆或者直接下载zip包。请不要使用任何版本的IE浏览器访问链接,除非你已经知道所使用的IE浏览器符合HTML5标准。推荐使用谷歌或者火狐浏览器访问,若使用国产双核浏览器请切换到极速模式。
    【原理图示意】

图1 连线示意图
1 暴露GPIO操作接口
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. static int gpio_export(int pin)  
  2. {  
  3.     char buffer[BUFFER_MAX];  
  4.     int len;  
  5.     int fd;  
  6.   
  7.     fd = open("/sys/class/gpio/export", O_WRONLY);  
  8.     if (fd < 0) {  
  9.         fprintf(stderr, "Failed to open export for writing!\n");  
  10.         return(-1);  
  11.     }  
  12.   
  13.     len = snprintf(buffer, BUFFER_MAX, "%d", pin);  
  14.     if (write(fd, buffer, len) < 0) {  
  15.         fprintf(stderr, "Fail to export gpio!");  
  16.         return -1;  
  17.     }  
  18.      
  19.     close(fd);  
  20.     return 0;  
  21. }  

2 隐藏GPIO操作接口
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. static int gpio_unexport(int pin)  
  2. {  
  3.     char buffer[BUFFER_MAX];  
  4.     int len;  
  5.     int fd;  
  6.   
  7.     fd = open("/sys/class/gpio/unexport", O_WRONLY);  
  8.     if (fd < 0) {  
  9.         fprintf(stderr, "Failed to open unexport for writing!\n");  
  10.         return -1;  
  11.     }  
  12.   
  13.     len = snprintf(buffer, BUFFER_MAX, "%d", pin);  
  14.     if (write(fd, buffer, len) < 0) {  
  15.         fprintf(stderr, "Fail to unexport gpio!");  
  16.         return -1;  
  17.     }  
  18.      
  19.     close(fd);  
  20.     return 0;  
  21. }  

3 配置GPIO方向
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. static int gpio_direction(int pin, int dir)  
  2. {  
  3.     static const char dir_str[] = "in\0out";  
  4.     char path[DIRECTION_MAX];  
  5.     int fd;  
  6.   
  7.     snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/direction", pin);  
  8.     fd = open(path, O_WRONLY);  
  9.     if (fd < 0) {  
  10.         fprintf(stderr, "failed to open gpio direction for writing!\n");  
  11.         return -1;  
  12.     }  
  13.   
  14.     if (write(fd, &dir_str[dir == IN ? 0 : 3], dir == IN ? 2 : 3) < 0) {  
  15.         fprintf(stderr, "failed to set direction!\n");  
  16.         return -1;  
  17.     }  
  18.   
  19.     close(fd);  
  20.     return 0;  
  21. }  
    【简单说明】
    【1】dir_str[dir == IN ? 0 : 3], dir == IN ? 2 : 3 如果输入为常数宏IN, 取dir_str[0]=“in”;若输入常数宏为OUT,取dir_str[0]=“out”。此处巧妙的使用了在数组中的“\0”。

4 控制GPIO输出
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. static int gpio_write(int pin, int value)  
  2. {  
  3.     static const char values_str[] = "01";  
  4.     char path[DIRECTION_MAX];  
  5.     int fd;  
  6.   
  7.     snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/value", pin);  
  8.     fd = open(path, O_WRONLY);  
  9.     if (fd < 0) {  
  10.         fprintf(stderr, "failed to open gpio value for writing!\n");  
  11.         return -1;  
  12.     }  
  13.   
  14.     if (write(fd, &values_str[value == LOW ? 0 : 1], 1) < 0) {  
  15.         fprintf(stderr, "failed to write value!\n");  
  16.         return -1;  
  17.     }  
  18.   
  19.     close(fd);  
  20.     return 0;  
  21. }  

5 获得GPIO输入
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. static int gpio_read(int pin)  
  2. {  
  3.     char path[DIRECTION_MAX];  
  4.     char value_str[3];  
  5.     int fd;  
  6.   
  7.     snprintf(path, DIRECTION_MAX, "/sys/class/gpio/gpio%d/value", pin);  
  8.     fd = open(path, O_RDONLY);  
  9.     if (fd < 0) {  
  10.         fprintf(stderr, "failed to open gpio value for reading!\n");  
  11.         return -1;  
  12.     }  
  13.   
  14.     if (read(fd, value_str, 3) < 0) {  
  15.         fprintf(stderr, "failed to read value!\n");  
  16.         return -1;  
  17.     }  
  18.   
  19.     close(fd);  
  20.     return (atoi(value_str));  
  21. }  

6 GPIO翻转操作
    【main函数】
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. int main(int argc, char *argv[])  
  2. {  
  3.     int i = 0;  
  4.       
  5.     GPIOExport(POUT);  
  6.     GPIODirection(POUT, OUT);  
  7.       
  8.     for (i = 0; i < 20; i++) {  
  9.         GPIOWrite(POUT, i % 2);  
  10.         usleep(500 * 1000);  
  11.     }  
  12.   
  13.     GPIOUnexport(POUT);  
  14.     return(0);  
  15. }  
    【makefile】——此处的代码tab显示可能存在问题,请以代码仓库为主。
[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. # 可执行文件  
  2. TARGET=test  
  3. # 依赖目标  
  4. SRCS=gpio-sysfs.c  
  5.   
  6. # 目标文件  
  7. OBJS = $(SRCS:.c=.o)  
  8.   
  9. # 指令编译器和选项  
  10. CC=gcc  
  11. CFLAGS=-Wall -std=gnu99  
  12.   
  13. $(TARGET):$(OBJS)  
  14.  $(CC) -o $@ $^  
  15.   
  16. clean:  
  17.  rm -rf $(TARGET) $(OBJS)  
  18.   
  19. # 连续动作,先清除再编译链接,最后执行  
  20. exec:clean $(TARGET)  
  21.  @echo 开始执行  
  22.  sudo ./$(TARGET)  
  23.  @echo 执行结束  
  24.   
  25. # 编译规则 $@代表目标文件 $< 代表第一个依赖文件  
  26. %.o:%.c  
  27.  $(CC) $(CFLAGS) -o $@ -c $<  

    【上传树莓派中 编译链接并执行】
    make exec
    makefile中exec目标包括以下一个过程,先清除目标文件和可执行文件,然后进行交叉编译,最后使用超级权限运行可执行文件。
    makefile的使用详见【 Linux学习笔记——例说makefile 索引博文】

7 总结
【1】树莓派和其他嵌入式Linux开发板存在差别和联系,树莓派同样可以使用sysfs控制GPIO。
【2】树莓派即在其他助剂中交叉编译,也可在平台直接编译。

8 参考资料
【1】RPi Low-level peripherals
0 0
原创粉丝点击