LV010-GPIO控制实例
这一部分的示例可以看这里:LV16_GPIO_CTRL · linux-dev-org/imx6ull-app-demo
一、GPIO——输出
1. 代码编写
控制开发板上的某一个 GPIO 输出高、低不同的电平状态 的代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
static char gpio_out_path[100];
static int gpio_out_config(const char *attr, const char *val)
{
int len = 0;
int fd = -1;
char file_path[100] = {0};
sprintf(file_path, "%s/%s", gpio_out_path, attr);
if (0 > (fd = open(file_path, O_WRONLY)))
{
perror("open error");
return fd;
}
len = strlen(val);
if (len != write(fd, val, len))
{
perror("write error");
close(fd);
return -1;
}
close(fd); // 关闭文件
return 0;
}
int main(int argc, char *argv[])
{
/* 校验传参 */
if (3 != argc)
{
fprintf(stderr, "usage: %s <gpio> <value>\n", argv[0]);
exit(-1);
}
/* 判断指定编号的GPIO是否导出 */
sprintf(gpio_out_path, "/sys/class/gpio/gpio%s", argv[1]);
if (access(gpio_out_path, F_OK))
{
// 如果目录不存在 则需要导出
int fd = -1;
int len = 0;
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");
close(fd);
exit(-1);
}
close(fd); // 关闭文件
}
/* 配置为输出模式 */
if (gpio_out_config("direction", "out"))
{
exit(-1);
}
/* 极性设置 */
if (gpio_out_config("active_low", "0"))
{
exit(-1);
}
/* 控制GPIO输出高低电平 */
if (gpio_out_config("value", argv[2]))
{
exit(-1);
}
/* 退出程序 */
exit(0);
}执行程序时需要传入两个参数, argv[1]指定 GPIO 的编号、 argv[2]指定输出电平状态(0 表示低电平、1 表示高电平)。
上述代码中首先使用 access()函数判断指定编号的 GPIO 引脚是否已经导出,也就是判断相应的 gpioX目录是否存在,如果不存在则表示未导出,则通过"/sys/class/gpio/export"文件将其导出;导出之后先配置了GPIO 引脚为输出模式,也就是向 direction 文件中写入"out";接着再配置极性,通过向 active_low 文件中写入"0"(不用配置也可以) ;最后再控制 GPIO 引脚输出相应的电平状态,通过对 value 属性文件写入"1"或 "0"来使其输出高电平或低电平。
2. 开发板测试
在测试之前,选择一个测试引脚,这里以板子上的 GPIO1_IO01 引脚为例,该引脚在底板上已经引出,如下所示:

执行该应用程序控制开发板上的 GPIO1_IO01 引脚输出高或低电平:
./app_demo 1 1 #控制 GPIO1_IO01 输出高电平
./app_demo 1 0 #控制 GPIO1_IO01 输出低电平执行相应的命令后,可以使用万用表或者连接一个 LED 小灯进行检验,以验证实验结果!
二、GPIO——输入
1. 代码编写
某引脚配置为输入,读取电平状态的代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
static char gpio_in_path[100];
static int gpio_in_config(const char *attr, const char *val)
{
int len = 0;
int fd = -1;
char file_path[100] = {0};
sprintf(file_path, "%s/%s", gpio_in_path, attr);
if (0 > (fd = open(file_path, O_WRONLY)))
{
perror("open error");
return fd;
}
len = strlen(val);
if (len != write(fd, val, len))
{
perror("write error");
close(fd);
return -1;
}
close(fd); // 关闭文件
return 0;
}
int main(int argc, char *argv[])
{
char val = 0;
int fd = -1;
char file_path[100] = {0};
/* 校验传参 */
if (2 != argc)
{
fprintf(stderr, "usage: %s <gpio>\n", argv[0]);
exit(-1);
}
/* 判断指定编号的GPIO是否导出 */
sprintf(gpio_in_path, "/sys/class/gpio/gpio%s", argv[1]);
if (access(gpio_in_path, F_OK))
{
// 如果目录不存在 则需要导出
int len = 0;
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");
close(fd);
exit(-1);
}
close(fd); // 关闭文件
}
/* 配置为输入模式 */
if (gpio_in_config("direction", "in"))
{
exit(-1);
}
/* 极性设置 */
if (gpio_in_config("active_low", "0"))
{
exit(-1);
}
/* 配置为非中断方式 */
if (gpio_in_config("edge", "none"))
{
exit(-1);
}
/* 读取GPIO电平状态 */
sprintf(file_path, "%s/%s", gpio_in_path, "value");
if (0 > (fd = open(file_path, O_RDONLY)))
{
perror("open error");
exit(-1);
}
if (0 > read(fd, &val, 1))
{
perror("read error");
close(fd);
exit(-1);
}
printf("value: %c\n", val);
/* 退出程序 */
close(fd);
exit(0);
}执行程序时需要传入一个参数, argv[1]指定要读取电平状态的 GPIO 对应的编号。上述代码中首先使用 access()函数判断指定编号的 GPIO 引脚是否已经导出, 若未导出, 则通过"/sys/class/gpio/export"文件将其导出;导出之后先配置了 GPIO 引脚为输入模式,也就是向 direction 文件中写入"in";接着再配置极性、设置 GPIO 引脚为非中断模式(向 edge 属性文件中写入"none")。最后打开 value 属性文件,读取 GPIO 的电平状态并将其打印出来。
2. 开发板测试
在测试之前,选择一个测试引脚,这里以板子上的 GPIO1_IO01 引脚为例,该引脚在底板上已经引出,如下所示:

首先通过杜邦线将 GPIO1_IO01 引脚连接到板子上的 3.3V 电源引脚上,接着执行命令读取 GPIO 电平状态。命令如下:
./app_demo 1应该会看到打印出的 value 等于 1,表示读取到 GPIO 的电平确实是高电平;接着将 GPIO1_IO01 引脚连接到板子上的 GND 引脚上,执行命令:
./app_demo 1应该会看到打印出的 value 等于 0,表示读取到 GPIO 的电平确实是低电平。
三、GPIO——中断
1. 代码编写
在应用层可以将 GPIO 配置为中断触发模式,例如将 GPIO 配置为上升沿触发、下降沿触发或者边沿触发 。将 GPIO 配置为边沿触发模式并监测中断触发状态的示例代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <poll.h>
static char gpio_intr_path[100];
static int gpio_intr_config(const char *attr, const char *val)
{
int len = 0;
int fd = -1;
char file_path[100] = {0};
sprintf(file_path, "%s/%s", gpio_intr_path, attr);
if (0 > (fd = open(file_path, O_WRONLY)))
{
perror("open error");
return fd;
}
len = strlen(val);
if (len != write(fd, val, len))
{
perror("write error");
return -1;
}
close(fd); // 关闭文件
return 0;
}
int main(int argc, char *argv[])
{
int ret = 0;
char val = 0;
struct pollfd pfd = {0};
char file_path[100] = {0};
/* 校验传参 */
if (2 != argc)
{
fprintf(stderr, "usage: %s <gpio>\n", argv[0]);
exit(-1);
}
/* 判断指定编号的GPIO是否导出 */
sprintf(gpio_intr_path, "/sys/class/gpio/gpio%s", argv[1]);
if (access(gpio_intr_path, F_OK))
{
// 如果目录不存在 则需要导出
int len = 0;
int fd = -1;
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_intr_config("direction", "in"))
{
exit(-1);
}
/* 极性设置 */
if (gpio_intr_config("active_low", "0"))
{
exit(-1);
}
/* 配置中断触发方式: 上升沿和下降沿 */
if (gpio_intr_config("edge", "both"))
{
exit(-1);
}
/* 打开value属性文件 */
sprintf(file_path, "%s/%s", gpio_intr_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);
}2. 开发板测试
在测试之前,选择一个测试引脚,这里以板子上的 GPIO1_IO02 (图中红框下面的引脚)引脚为例,该引脚在底板上已经引出,如下所示:

执行应用程序监测 GPIO1_IO02 引脚的中断触发情况,如下所示 :
./app_demo 2 # 监测 GPIO1_IO02 引脚中断触发当执行命令之后,我们可以使用杜邦线将 GPIO1_IO02 引脚连接到 GND 或 3.3V 电源引脚上,来回切换,使得 GPIO1_IO02 引脚的电平状态发生由高到低或由低到高的状态变化, 以验证 GPIO 中断的边沿触发情况;当发生中断时,终端将会打印相应的信息,如图所示。
