RaspberryPi 4B 使用 libgpiod 操作 gpio

本文介绍了如何在Raspberry Pi OS中使用libgpiod库来控制GPIO,以实现LED灯的亮灭操作。文章详细讲解了从GPIOsysfs接口的使用过渡到libgpiod的步骤,包括安装libgpiod库、编写C程序控制GPIO输出以及通过libgpiod控制RGB三色LED灯的方法。通过示例代码展示了如何设置GPIO方向、输出值以及实现红绿灯交替闪烁和颜色混合效果。
摘要由CSDN通过智能技术生成

RaspberryPi OS 是 Linux 的一个发行版,基于 Debian 制作。因此我们熟悉的基于 sysfs 方式控制 GPIO(/sys/class/gpio)都是可以使用的。但是嵌入式 Linux 系统下之前被广泛应用的 GPIO 工具 sysfs GPIO 接口,目前这个项目已经处于 deprecated 状态,经 Linux Kernel Community 确定其替代者就是 GPIO 字符设备 API Libgpiod。

libgpiod —— 与Linux GPIO 交互的 C 库和工具,字符设备(gpiod 代表 GPIO 设备)

从 Linux 4.8 开始,GPIO sysfs 接口已被弃用。用户空间应该使用取而代之的是字符设备。这个库简单的 API 实现封装了 ioctl 调用和数据结构。

一、硬件接线

通过控制 gpio 引脚输出高电平就可以控制 LED 灯的点亮。使用树莓派传感器套件里的双色 LED 灯模块。原理图如下:

在这里插入图片描述

现在再来看树莓派的 gpio 引脚图:

在这里插入图片描述

我这里使用 GPIO 17 和 GPIO 18 引脚去控制双色 LED 灯模块的红灯(R)或绿灯(G)点亮。

接线如下:

树莓派引脚双色 LED 灯模块引脚
GPIO 17R
GPIO 18S(G)
GNDGND

查看树莓派的 gpio 引脚图还有一个快捷方式,在树莓派命令行窗口直接输入命令:

pinout

显示如下:

在这里插入图片描述

二、使用 GPIO sysfs 接口

  1. sysfs 导出 GPIO 17 和 GPIO 18
echo 17 > /sys/class/gpio/export
echo 18 > /sys/class/gpio/export

现在再去 ls /sys/class/gpio/ 目录,就会多出来 gpio17 和 gpio18 目录。

  1. 设置 gpio 模式为输出
echo out > /sys/class/gpio/gpio17/direction
echo out > /sys/class/gpio/gpio18/direction
  1. 设置 gpio 高电平点亮 LED,点亮绿色(G)灯。
echo 1 > /sys/class/gpio/gpio18/value

熄灭写 0 即可。

echo 0 > /sys/class/gpio/gpio18/value

三、使用 libgpiod

3.1 安装

首先安装 libgpiod,先查找一下。

pi@raspberrypi:~/Package $ sudo apt-cache search libgpiod
gpiod - Tools for interacting with Linux GPIO character device - binary
libgpiod-dev - C library for interacting with Linux GPIO device - static libraries and headers
libgpiod-doc - C library for interacting with Linux GPIO device - library documentation
libgpiod2 - C library for interacting with Linux GPIO device - shared libraries
python3-libgpiod - Python bindings for libgpiod (Python 3)

gpiod —— 与 Linux GPIO 字符设备交互的工具 - bin 二进制

libgpiod-dev —— 用于与 Linux GPIO 设备交互的 C 库 - 静态库和头文件

libgpiod-doc —— 库文档

libgpiod2 —— 用于与 Linux GPIO 设备交互的 C 库 - 共享库

python3-libgpiod —— libgpiod 的 Python 绑定(Python 3)

直接 install libgpiod-dev

sudo apt-get install libgpiod-dev

在这里插入图片描述

可以看到实际上安装了 libgpiod-dev 的同时也安装了 libgpiod2,也就是其静态库和动态库都安装了。

3.2 使用

写一个程序验证一下,红绿灯交替闪烁一共 20 次。

下面的程序用到了 libgpiod 以下 API:

  1. gpiod_chip 结构体

它代表支持 gpio 的芯片。包括每个 gpio 口 gpiod_line 数组 lines,数组的个数用 num_lines 指出。还包含了 fd 设备句柄,以及名称和标签。

struct gpiod_chip {
	struct gpiod_line **lines;
	unsigned int num_lines;

	int fd;

	char name[32];
	char label[32];
};
  1. gpiod_line 结构体

direction —— GPIO 的方向

active_state —— 活动状态配置

output_value —— 最后写入 GPIO 的逻辑值

info_flags —— GPIO_GET_LINEINFO_IOCTL 返回的 GPIOLINE_FLAGs

req_flags —— 提供 GPIOD_LINE_REQUEST_FLAGs 来请求 GPIO

state —— LINE_FREE,LINE_REQUESTED_VALUES 或 LINE_REQUESTED_EVENTS

struct line_fd_handle {
	int fd;
	int refcount;
};

struct gpiod_line {
	unsigned int offset;

	/* The direction of the GPIO line. */
	int direction;

	/* The active-state configuration. */
	int active_state;

	/* The logical value last written to the line. */
	int output_value;

	/* The GPIOLINE_FLAGs returned by GPIO_GET_LINEINFO_IOCTL. */
	__u32 info_flags;

	/* The GPIOD_LINE_REQUEST_FLAGs provided to request the line. */
	__u32 req_flags;

	/*
	 * Indicator of LINE_FREE, LINE_REQUESTED_VALUES or
	 * LINE_REQUESTED_EVENTS.
	 */
	int state;

	struct gpiod_chip *chip;
	struct line_fd_handle *fd_handle;

	char name[32];
	char consumer[32];
};
  1. gpiod_chip_open_by_name

按名称打开 gpiochip。

  1. gpiod_chip_get_line

在给定的偏移量处获取 GPIO 的句柄。

offset —— GPIO偏移量

  1. gpiod_line_request_output

设置输出方向。

consumer —— 使用者的名称

default_val —— 初始值

  1. gpiod_line_set_value

设置单个 GPIO 的值。

例程代码

#include <gpiod.h>
#include <stdio.h>
#include <unistd.h>

#ifndef	CONSUMER
#define	CONSUMER	"Consumer"
#endif

int main(int argc, char **argv)
{
	char *chipname = "gpiochip0";
	unsigned int line_num_17 = 17;	// GPIO 17
	unsigned int line_num_18 = 18;	// GPIO 18
	unsigned int val;
	struct gpiod_chip *chip;
	struct gpiod_line *line17, *line18;
	int i, ret;

	chip = gpiod_chip_open_by_name(chipname);
	if (!chip) {
		printf("Open chip by name failed. name: %s\n", chipname);
		goto end;
	}

	line17 = gpiod_chip_get_line(chip, line_num_17);
	if (!line17) {
		printf("Get line failed. line_num: %u\n", line_num_17);
		goto close_chip;
	}

	line18 = gpiod_chip_get_line(chip, line_num_18);
	if (!line18) {
		printf("Get line failed. line_num: %u\n", line_num_18);
		goto release_line17;
	}

	ret = gpiod_line_request_output(line17, CONSUMER, 0);
	if (ret < 0) {
		printf("Request line17 as output failed\n");
		goto release_line18;
	}

	ret = gpiod_line_request_output(line18, CONSUMER, 0);
	if (ret < 0) {
		printf("Request line18 as output failed\n");
		goto release_line18;
	}

	/* Blink 20 times */
	val = 0;
	for (i = 20; i > 0; i--) {
		ret = gpiod_line_set_value(line17, val);
		if (ret < 0) {
			printf("Set line17 output failed. val: %u\n", val);
			goto release_line18;
		}
		ret = gpiod_line_set_value(line18, !val);
		if (ret < 0) {
			printf("Set line18 output failed. val: %u\n", !val);
			goto release_line18;
		}
		printf("Times %d\n", i);
		sleep(1);
		val = !val;
	}

release_line18:
	gpiod_line_release(line18);
release_line17:
	gpiod_line_release(line17);
close_chip:
	gpiod_chip_close(chip);
end:
	return 0;
}

编译程序

gcc RG_LED.c -o RG_LED -lgpiod

运行

./RG_LED

效果图如下,实际情况是红绿交替闪烁。

在这里插入图片描述
在这里插入图片描述

3.3 点亮 RGB 三色 LED

三色 LED 模块原理图如下,可以控制三原色混合。

在这里插入图片描述
下面是接线图:

树莓派引脚RGB 三色 LED 灯模块引脚
GPIO 16R
GPIO 17B
GPIO 18G
GNDGND

例程代码如下,在上面的代码的基础上抽离出公共方法 blend_led 。

#include <gpiod.h>
#include <stdio.h>
#include <unistd.h>

#ifndef	CONSUMER
#define	CONSUMER	"Consumer"
#endif

int blend_led(struct gpiod_line *r, int r_val, struct gpiod_line *g, int g_val, struct gpiod_line *b, int b_val);

/**
* GPIO 16 <-> R
* GPIO 17 <-> B
* GPIO 18 <-> G
*/
int main(int argc, char **argv)
{
	char *chipname = "gpiochip0";
	unsigned int line_num_16 = 16;	// GPIO 16
	unsigned int line_num_17 = 17;	// GPIO 17
	unsigned int line_num_18 = 18;	// GPIO 18
	
	struct gpiod_chip *chip;
	struct gpiod_line *line16, *line17, *line18;
	int ret;

	chip = gpiod_chip_open_by_name(chipname);
	if (!chip) {
		printf("Open chip by name failed. name: %s\n", chipname);
		goto end;
	}
	
	line16 = gpiod_chip_get_line(chip, line_num_16);
	if (!line16) {
		printf("Get line failed. line_num: %u\n", line_num_16);
		goto close_chip;
	}

	line17 = gpiod_chip_get_line(chip, line_num_17);
	if (!line17) {
		printf("Get line failed. line_num: %u\n", line_num_17);
		goto release_line16;
	}

	line18 = gpiod_chip_get_line(chip, line_num_18);
	if (!line18) {
		printf("Get line failed. line_num: %u\n", line_num_18);
		goto release_line17;
	}
	
	ret = gpiod_line_request_output(line16, CONSUMER, 0);
	if (ret < 0) {
		printf("Request line16 as output failed\n");
		goto release_line18;
	}

	ret = gpiod_line_request_output(line17, CONSUMER, 0);
	if (ret < 0) {
		printf("Request line17 as output failed\n");
		goto release_line18;
	}

	ret = gpiod_line_request_output(line18, CONSUMER, 0);
	if (ret < 0) {
		printf("Request line18 as output failed\n");
		goto release_line18;
	}
	
	//R
	ret = blend_led(line16, 1, line17, 0, line18, 0);
	if (ret < 0) {
		printf("Set output failed.\n");
		goto release_line18;
	}
	
	sleep(1);
	//G
	ret = blend_led(line16, 0, line17, 0, line18, 1);
	if (ret < 0) {
		printf("Set output failed.\n");
		goto release_line18;
	}
	sleep(1);
	
	//B
	ret = blend_led(line16, 0, line17, 1, line18, 0);
	if (ret < 0) {
		printf("Set output failed.\n");
		goto release_line18;
	}
	sleep(1);
	
	//yellow
	ret = blend_led(line16, 1, line17, 0, line18, 1);
	if (ret < 0) {
		printf("Set output failed.\n");
		goto release_line18;
	}
	sleep(1);
	
	ret = blend_led(line16, 1, line17, 1, line18, 0);
	if (ret < 0) {
		printf("Set output failed.\n");
		goto release_line18;
	}
	sleep(1);
	
	ret = blend_led(line16, 0, line17, 1, line18, 1);
	if (ret < 0) {
		printf("Set output failed.\n");
		goto release_line18;
	}
	sleep(1);
	
	ret = blend_led(line16, 1, line17, 1, line18, 1);
	if (ret < 0) {
		printf("Set output failed.\n");
		goto release_line18;
	}

release_line18:
	gpiod_line_release(line18);
release_line17:
	gpiod_line_release(line17);
release_line16:
	gpiod_line_release(line16);
close_chip:
	gpiod_chip_close(chip);
end:
	return 0;
}

int blend_led(struct gpiod_line *r, int r_val, struct gpiod_line *g, int g_val, struct gpiod_line *b, int b_val){
	int ret = 0;
	ret = gpiod_line_set_value(r, r_val);
	if (ret < 0) {
		printf("Set r output failed. val: %u\n", r_val);
		return ret;
	}
	
	ret = gpiod_line_set_value(g, g_val);
	if (ret < 0) {
		printf("Set g output failed. val: %u\n", g_val);
		return ret;
	}
	
	ret = gpiod_line_set_value(b, b_val);
	if (ret < 0) {
		printf("Set b output failed. val: %u\n", b_val);
		return ret;
	}
	
	return 0;
}

编译运行即可看到结果,R、G、B…的颜色顺序闪烁,间隔一秒。

gcc rgb_led.c -o rgb_led -lgpiod
./rgb_led
### 回答1: Raspberry Pi 4B的波特率是根据使用的串口或者通信协议而定的。Raspberry Pi 4B有多个可用的UART串口,每个串口都可以设置不同的波特率。对于UART串口,可以通过设置config.txt文件或者使用软件来配置不同的波特率,常见的波特率有9600、115200等。 另外,对于其他通信协议,如SPI和I2C,Raspberry Pi 4B也支持不同的通信速率,这些通信速率也可以被认为是一种波特率。SPI通信速率可以在代码中进行配置,一般在MHz级别。I2C通信速率也可以通过代码进行配置,一般在100kHz或400kHz。 需要注意的是,波特率是指单位时间内传输的比特数,波特率越高,传输速率越快,但也会引入更多的噪声和误码。因此,在选择和配置波特率时,需要根据实际应用场景的需求进行权衡,确保数据传输的稳定性和准确性。 总之,Raspberry Pi 4B的波特率取决于所使用的串口或通信协议,并且可以通过软件或代码进行配置。根据不同的需求和应用场景,选择合适的波特率可以实现稳定和快速的数据传输。 ### 回答2: Raspberry Pi 4B的波特率是指用于与其他设备进行通信的传输速率。波特率是指在单位时间内传输的数据位数。Raspberry Pi 4B支持多种不同的波特率,可以根据需要进行设置。 Raspberry Pi 4B的默认波特率是115200,这是一个常用的标准波特率,可用于与其他硬件设备进行串口通信。可以通过设置串口配置文件或者命令行界面来修改默认波特率。 除了默认波特率外,Raspberry Pi 4B还支持更高的波特率,如230400、460800、921600等。这些更高的波特率可以用于需要快速数据传输的应用,例如高速传输大量数据或者与其他高速设备进行通信。 修改Raspberry Pi 4B的波特率可以通过修改配置文件来实现,如修改串口配置文件中的波特率参数。另外,也可以通过命令行界面使用特定的指令来修改波特率设置。在修改波特率之后,需要确保与Raspberry Pi 4B通信的设备也能支持相同的波特率,以保证正常的数据传输。 总之,Raspberry Pi 4B的波特率是可以根据需求进行修改的,它可以支持多种不同的波特率用于与其他设备进行通信。根据实际应用的需要选择合适的波特率可以确保数据的快速、稳定传输。 ### 回答3: Raspberry Pi 4B支持的常用串口通信波特率是300字。 Raspberry Pi 4B在硬件上增加了两个串口UART接口,其中一个UART接口可通过GPIO引脚使用,另一个UART可通过USB-C接口使用。这两个UART接口都可以用于与外部设备进行串口通信。 在Raspberry Pi上,设定波特率通常需要在操作系统中进行配置。对于GPIO UART接口,可以通过在命令行中使用"stty"命令来设定波特率。通过设置特定的参数,比如"-F /dev/serial0"来指定使用的串口设备,并通过参数"-speed 300"来设置波特率为300。 对于USB-C UART接口,通常可以在操作系统的串口设置菜单中设定波特率。支持的波特率通常包括300、1200、2400等常见的波特率。用户可以根据实际需要选择适合的波特率。 总而言之,Raspberry Pi 4B支持的波特率包括300字,用户可以根据实际需求选择适合的波特率来与外部设备进行串口通信。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TYYJ-洪伟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值