15. GPIO 应用编程

1. 应用层如何操控 GPIO

GPIO 也是通过 sysfs 方式进行操控的,在/sys/class/gpio目录下
在这里插入图片描述

  • gpiochipX: I.MX6UL 有 5 个 GPIO,X 由小到大分别对应 1 ~ 5 GPIO,随便进入一个目录,可以看到一些属性文件,这里介绍 3 个
    • base: 与 X 相同,表示该控制器所管理的这组 GPIO 引脚中最小的编号
    • label: 该组 GPIO 的名字
    • ngpio: 所管理的 GPIO 引脚的数量,范围是 base ~ base + ngpio -1
  • export: 用于将指定编号的 GPIO 引脚导出。使用 gpio 引脚之前,需要将其导出。export 是只写文件,不能读取,将一个指定的 X 写入到 export 文件中即可将对应的 gpio 引脚导出,导出之后可以发现在 gpio 目录下生成了一个新的目录,就是导出的 gpio 引脚对应的目录。不是所有的引脚都可以导出,如果对应的 GPIO 已经在内核中被使用,是无法成功导出的。
  • unexport: 将导出的引脚剔除,也是只写文件。
  • gpioX: 这是导出后生成的目录,这里只关心 4 个文件
    • direction: 配置 GPIO 引脚为输入in或输出out模式。该文件可读可写。echo "out" > direction
    • value: 在输出模式下,写 0 表示输出低电平,写 1 表示输出高电平
      echo "in" > direction
      echo "1" > value
      
    • active_low: 用于控制极性,可读可写,默认情况为 0,此时 value=1 表示输出高电平;为 1 时,value=1 输出低电平。
    • edge: 控制中断的触发模式,该文件可读可写。配置该文件之前,需要将 GPIO 设置为输入模式。
      echo "none" > edge 	# 非中断引脚
      echo "rising" > edge # 上升沿触发
      echo "falling" > edge # 下降沿触发
      echo "both" > edge # 边沿触发
      

2. GPIO 应用编程之输出

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
using namespace std;

char *gpio_path;
char *attr_path;

void USAGE(char *argv[])
{
    printf("usage: %s GPIO编号 输出电平\n",argv[0]);
}

void set(char *path,char *str)
{
    sprintf(attr_path,"gpio_path/%s",path);
    int fd=open(attr_path,O_WRONLY);
    write(fd,str,sizeof str);
    close(fd);
}

int main(int argc,char *argv[])
{
    int len;
    int fd;
    if(argc!=3)
    {
        USAGE(argv);
        return -1;
    }
    
    sprintf(gpio_path,"/sys/class/gpio/gpio%s",argv[1]);
    if(access(gpio_path,F_OK)) // 判断导出目录是否存在,存在返回0
    {
        // 不存在
        fd=open("/sys/class/gpio/export",O_WRONLY);
        if(fd<0)
        {
            perror("open");
            return -1;
        }
        len=strlen(argv[1]);
        // 将对应的GPIO编号写入到export中
        if(len!=write(fd,argv[1],len))
        {
            perror("write");
            close(fd);
            return -1;
        }
        close(fd);
    }
    
    // 配置为输出模式
    set("direction","out");
    // 极性设置
    set("active_low","0");
    // 输出高低电平
    set("value",argv[2]);
    return 0;
}

3. GPIO 应用编程之输入

这个代码就是需要将引脚配置为输入模式,并且是非中断模式。就不详细编写

4. GPIO 应用编程之中断

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 */
	pfd.events = POLLPRI; //只关心高优先级数据可读(中断)
	read(pfd.fd, &val, 1);//先读取一次清除状态
	for ( ; ; ) 
	{
		ret = poll(&pfd, 1, -1); //调用 poll
		if (0 > ret) 
		{
			perror("poll error");
			exit(-1);
		}
		else if (0 == ret) 
		{
			fprintf(stderr, "poll timeout.\n");
			continue;
		}
		/* 校验高优先级数据是否可读 */
		if(pfd.revents & POLLPRI) 
		{
			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);
}

调用 poll 监视文件描述符上的 IO 状态变化,POLLPRI 表示有高优先级数据可读取,中断就是一种高优先级事件。

  • 18
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值