在Linux中,最常见的读写GPIO方式就是用GPIO sysfs interface, 是通过操作 /sys/class/gpio 目录下的 export 、 unexport 、gpio{N}/direction, gpio{N} /value (用实际引脚号替代{N})等文件实现的,经常出现shell脚本里面。 在kernel 4.8开始,加入了libgpiod的支持;而原有基于sysfs的访问方式,将被逐渐放弃。
libgpiod是一种字符设备接口,GPIO访问控制是通过操作字符设备文件(比如 /dev/gpiodchip0 )实现的, 并通过libgpiod提供一些命令工具、c库以及python封装。
想要使用libgpiod,需要在开发板上安装libgpiod库。
#安装libgpiod库及头文件
sudo apt install libgpiod-dev vim
#安装gpiod 命令行工具
sudo apt install gpiod
常用的命令行如下,可使用 -h 查看命令相对应的使用说明
命令 | 作用 | 使用举例 |
---|---|---|
gpiodetect | 列出所有的 GPIO 控制器 | gpiodetect |
gpioinfo | 列出 GPIO 控制器的引脚情况 | gpioinfo 4 |
gpioset | 设置 GPIO 引脚的状态 | gpioset 4 19=0 |
gpioget | 获取 GPIO 引脚状态 | gpioget 4 1 |
gpiomon | 监控 GPIO 引脚状态并整理成表格 | gpiomon 4 1 |
查看数据手册可知在imx6ull中GPIO组的编号从1开始,而libgpiod引脚组从0开始, 因此 gpioset 4 19=0
,则表示的是GPIO5组编号为19的引脚。 并不是所有的引脚都能够使用libgpiod控制,例如led之类的一些已经被使用的引脚。
若想要在PC上交叉编译出能运行在板子的应用程序,交叉链接时使用的libgpiod库要与开发板的匹配, 可以直接把开发板的库拷贝到PC上链接使用。
开发板安装好ligpiod-dev后,可以通过以下命令找到具体的头文件和库文件:
# 在开发板上查找libgpiod库
dpkg -L libgpiod-dev
# 以下是输出
/usr/include/gpiod.h
/usr/lib/arm-linux-gnueabihf/libgpiod.a
/usr/lib/arm-linux-gnueabihf/libgpiod.so
查找结果中的gpiod.h、libgpiod.so和libgpiod.a就是开发板使用的头文件、动态和静态链接库, 它是debian 10 buster默认apt安装的版本。
常用的libgpiod API(C库)如下所示:
//成员变量
struct gpiod_chip; //GPIO组句柄
struct gpiod_line; //GPIO引脚句柄
//获取GPIO控制器(GPIO组)
struct gpiod_chip *gpiod_chip_open(const char *path);
//获取GPIO引脚
struct gpiod_line * gpiod_chip_get_line(struct gpiod_chip *chip, unsigned int offset);
//设置引脚方向为输入模式
int gpiod_line_request_input(struct gpiod_line *line,const char *consumer);
//设置引脚为输出模式
int gpiod_line_request_output(struct gpiod_line *line,const char *consumer, int default_val)
//设置引脚的高低电平
int gpiod_line_set_value(struct gpiod_line *line, int value);
//读取引脚状态
int gpiod_line_get_value(struct gpiod_line *line);
//释放GPIO引脚
void gpiod_line_release(struct gpiod_line *line);
//关闭GPIO组句柄并释放所有分配的资源。
void gpiod_chip_close(struct gpiod_chip *chip);
#include <gpiod.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
/*
//获取GPIO控制器(GPIO组)
struct gpiod_chip *gpiod_chip_open(const char *path);
//获取GPIO引脚
struct gpiod_line * gpiod_chip_get_line(struct gpiod_chip *chip, unsigned int offset);
//设置引脚方向为输入模式
int gpiod_line_request_input(struct gpiod_line *line,const char *consumer);
int= gpiod_line_request_output(line,"beep",0); //设置为输出模式,且为低电平,
//读取引脚状态
int gpiod_line_get_value(struct gpiod_line *line);
//释放GPIO引脚
void gpiod_line_release(struct gpiod_line *line);
//关闭GPIO组句柄并释放所有分配的资源。
void gpiod_chip_close(struct gpiod_chip *chip);
*/
int main(int argc, char **argv)
{
int i;
int ret;
struct gpiod_chip * chip; //GPIO控制器句柄
struct gpiod_line * line; //GPIO引脚句柄
/*获取GPIO控制器*/
chip = gpiod_chip_open("/dev/gpiochip0"); //第一组
if(chip == NULL)
{
printf("gpiod_chip_open error\n");
return -1;
}
/*获取GPIO引脚*/
line = gpiod_chip_get_line(chip, 19); //第一组的19号引脚
if(line == NULL)
{
printf("gpiod_chip_get_line error\n");
goto release_line;
}
/*设置GPIO为输出模式*/
ret = gpiod_line_request_output(line,"beep",0); //设置为输出模式,且为低电平,
if(ret < 0)
{
printf("gpiod_line_request_output error\n");
goto release_chip;
}
for(i = 0;i<10;i++)
{
gpiod_line_set_value(line,1);
usleep(500000); //延时0.5s
gpiod_line_set_value(line,0);
usleep(500000);
}
release_line:
/*释放GPIO引脚*/
gpiod_line_release(line);
release_chip:
/*释放GPIO控制器*/
gpiod_chip_close(chip);
return 0;
}
编译程序时需指定libgpiod库及路径头文件路径(不使用交叉编译时并不需要指定路径)。
然后我们在开发板上执行方式一
sudo arm-linux-gnueabihf-gcc beep.c -lgpiod -L./libgpiod/ -I./libgpiod/ -o beep
sudo chmod 777 beep
./beep