7. GPIO控制¶
GPIO是General Purpose I/O的缩写,即通用输入输出端口,简单来说就是MCU/CPU可控制的引脚, 这些引脚通常有多种功能,最基本的是高低电平输入检测和输出,部分引脚还会与主控器的片上外设绑定, 如作为串口、I2C、网络、电压检测的通讯引脚。
Linux提供了GPIO子系统驱动框架,使用该驱动框架即可灵活地控制板子上的GPIO。
7.1. 方式一:使用GPIO sysfs接口控制IO¶
在Linux中,最常见的读写GPIO方式就是用GPIO sysfs interface, 是通过操作 /sys/class/gpio 目录下的 export 、 unexport 、gpio{N}/direction, gpio{N} /value (用实际引脚号替代{N})等文件实现的,经常出现shell脚本里面。 在kernel 4.8开始,加入了libgpiod的支持;而原有基于sysfs的访问方式,将被逐渐放弃。
使用方式请参考以下链接: 《野火Linux基础教程-控制蜂鸣器》
7.2. 方式二:使用libgpiod控制IO¶
libgpiod是一种字符设备接口,GPIO访问控制是通过操作字符设备文件(比如 /dev/gpiodchip0 )实现的, 并通过libgpiod提供一些命令工具、c库以及python封装。
想要使用libgpiod,需要在开发板上安装libgpiod库。
1 2 3 4 5 | #安装libgpiod库及头文件
sudo apt install libgpiod-dev
#安装gpiod 命令行工具
sudo apt install gpiod
|
7.2.1. 命令行控制¶
常用的命令行如下,可使用 -h 查看命令相对应的使用说明
命令 |
作用 |
使用举例 |
说明 |
---|---|---|---|
gpiodetect |
列出所有的GPIO控制器 |
gpiodetect(无参数) |
列出所有的GPIO控制器 |
gpioinfo |
列出gpio控制器的引脚情况 |
gpioinfo 4 |
列出gpio4控制器引脚组情况 |
gpioset |
设置gpio |
gpioset 4 19=0 |
设置gpio4组编号19引脚为低电平 |
gpioget |
获取gpio引脚状态 |
gpioget 4 1 |
获取gpio4组编号1的引脚状态 |
gpiomon |
监控gpio的状态 |
gpiomon 4 1 |
监控gpio4组编号1的引脚状态 |
重要
不是所有的引脚都能够使用libgpiod控制,例如led之类的一些已经被使用的引脚。
7.2.2. 使用libgpiod编程¶
若想要在PC上交叉编译出能运行在板子的应用程序,交叉链接时使用的libgpiod库要与开发板的匹配, 可以直接把开发板的库拷贝到PC上链接使用。
开发板安装好ligpiod-dev后,可以通过以下命令找到具体的头文件和库文件:
1 2 3 4 5 6 | # 在开发板上查找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安装的版本。
为方便使用,我们已拷贝到配套代码中:debian buster 的libgpiod头文件和库 。
常用的libgpiod API(C库)如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | //成员变量
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);
|
根据上面libgpiod提供API,编写了以下控制蜂鸣器的程序(蜂鸣器的所在的引脚为PC13),其源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | #include <gpiod.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
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/gpiochip2");
if(chip == NULL)
{
printf("gpiod_chip_open error\n");
return -1;
}
/*获取GPIO引脚*/
line = gpiod_chip_get_line(chip, 13);
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库及路径头文件路径(不使用交叉编译时并不需要指定路径)。
1 2 3 4 5 | #方式一:手动编译,需要指定libgpiod库的头文件路径以及动态库路径
arm-linux-gnueabihf-gcc beep beep.c -lgpiod -L./libgpiod/ -I./libgpiod/
#方式二:直接用本文档配套的代码,它包含了makefile,在Source/libgpio_beep目录下直接通过make编译
make
|