Linux下的GPIO编程

目录

一、前言

二、sysfs方式

1、sysfs简介

2、基本目录结构

 3、编号计算

4、sysfs方式控制GPIO

三、libgpiod库 

1、libgpiod库简介

2、API函数

四、LED灯编程


一、前言

        在Linux下,我们通常使用 sysfs libgpiod库 两种方式进行控制GPIO,目前,libgpiod库已成为人们广泛采用的方法。接下来,我将通过控制LED灯的亮灭来讲解Linux下如何进行GPIO编程。

        我这里使用的RGB三色灯是共阳极的(大家根据硬件的实际情况进行修改)。

        根据引脚实际情况进行连接,我这里选取了1、3、5、7号引脚。

  • RGB三色灯 G(Gnd) 连接到了 开发板40Pin 1#脚上
  • RGB三色灯 R(红灯) 连接到了 开发板40Pin 3#脚上
  • RGB三色灯 G(绿灯) 连接到了 开发板40Pin 7#脚上
  • RGB三色灯 B(蓝灯) 连接到了 开发板40Pin 5#脚上

二、sysfs方式

1、sysfs简介

        尽管 sysfs 方式控制GPIO在现代系统中已逐渐被弃用,但了解其工作原理仍然有助于理解 Linux 内核的操作方式。sysfs 是 Linux 文件系统中的一个伪文件系统,用于导出内核对象的信息,以文件和目录的形式呈现。这些文件和目录可以被用户空间进程读取和写入,以访问和操作内核对象。

        通过 sysfs,用户可以直接通过文件系统的接口来与内核进行交互,而不需要直接操作内核数据结构。这种抽象层提供了一种方便而统一的方式来管理和配置系统硬件和内核参数,使得Linux系统更加灵活和易于管理。

2、基本目录结构

        我们通过查看 /sys/class/gpio 来查看基本目录结构。

(1)export:用于通知Linux内核导出需要的GPIO引脚。

(2)unexport: 用于通知Linux内核取消导出的GPIO引脚。

(3)gpiochipX:用于保存系统中GPIO寄存器的信息。

        GPIO 芯片在文件系统中表示为字符设备文件,在 /dev 目录下,每个 GPIO 芯片都有一个对应的字符设备文件。

 3、编号计算

        要想通过 sysfs 方式控制LED灯,需要先根据引脚计算出其编号。根据引脚连接方式,我们可以知道引脚#3、#5、#7分别对应的是GPIO1_IO03、GPIO1_IO02、GPIO1_IO18。

编号计算公式为:NUM = (x - 1)* 32 + Y  

        接下来我都以红灯所连的 #3 引脚为例。

GPIO1_IO03 = (1-1)*32 + 3 = 3

4、sysfs方式控制GPIO

(1)通知内核导出需要的GPIO引脚

查看gpio3文件夹

  •  direction:gpio的输入输出属性。
  • active_low:设置gpio的有效电平,由于我们常用1为高电平、0为低电平的编程习惯,active_low通常设置为0 。
  • value:gpio的电平值。

(2)设置GPIO引脚为输出模式

(3)通过输出高低电平控制LED亮灭

        通过上图共阳极LED原理图可知,输出高电平LED灭,输出低电平LED亮。

(4) 通知内核导出需要的GPIO引脚

三、libgpiod库 

1、libgpiod库简介

        libgpiod是一个用于在Linux系统上访问GPIO设备的C库,它提供了一个用户空间API,允许开发者以编程方式控制和管理系统上的GPIO引脚。

        我们在服务器做交叉编译时,在编译和链接过程中需要相应的头文件和动态库文件,所以我们需要下载第三方库文件,下载时注意版本选择!

下载链接:libgpiod/libgpiod.git - C library and tools for interacting with the linux GPIO character device (kernel.org)icon-default.png?t=N7T8https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git

        先查看板子上libgpiod库的版本号。

         此时,在服务器上按顺序依次输入如下命令:

mkdir libgpiod && cd libgpiod

wget https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/snapshot/libgpiod-2.0.tar.gz

tar -xzf libgpiod-2.0.tar.gz

cd libgpiod-2.0/

./autogen.sh 

export CROSS_COMPILE=arm-linux-gnueabihf-
export CC=${CROSS_COMPILE}gcc
export CXX=${CROSS_COMPILE}g++
export AS=${CROSS_COMPILE}as
export AR=${CROSS_COMPILE}ar
export LD=${CROSS_COMPILE}ld
export NM=${CROSS_COMPILE}nm
export RANLIB=${CROSS_COMPILE}ranlib
export OBJDUMP=${CROSS_COMPILE}objdump
export STRIP=${CROSS_COMPILE}strip

unset CFLAGS
unset LDFLAGS

echo "ac_cv_func_malloc_0_nonnull=yes" > arm-linux.cache

./configure --prefix=`pwd`/../install --build=i686-pc-linux --host=arm-linux --enable-static --enable-tools --cache-file=arm-linux.cache

make

make install

         libgpiod下载后目录结构如下:

2、API函数

         我在这里就整理了几个常用API函数,想查看更详细的讲解,可以看libgpiod的API文档说明。

libgpiod: GPIO chipsicon-default.png?t=N7T8https://libgpiod.readthedocs.io/en/latest/group__chips.html(1)打开/关闭所需要的GPIO芯片

struct gpiod_chip *gpiod_chip_open(const char *path);	

void gpiod_chip_close(struct gpiod_chip *chip);
  • path:要打开的gpiochip 设备路径(/dev/gpiochipx)。
  • 返回值:成功返回GPIO芯片句柄,失败则返回NULL。

(2)申请/释放所需要的GPIO口

struct gpiod_line_request * gpiod_chip_request_lines(struct gpiod_chip *chip, struct gpiod_request_config *req_cfg, struct gpiod_line_config *line_cfg);

void gpiod_line_request_release(struct gpiod_line_request *request);
  • chip:GPIO芯片句柄。
  • req_cfg:request的配置。
  • line_cfg:line的配置。
  • 返回值:成功返回GPIO口句柄,失败则返回NULL。

(3)设置GPIO输出电平

int gpiod_line_request_set_value(struct gpiod_line_request *request, unsigned int offset, enum gpiod_line_value value)
  • request:GPIO口句柄。
  • offset:GPIO line编号。
  • value:设置的逻辑电平值。

四、LED灯编程

#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <string.h>

#include <gpiod.h>

#define DELAY	300

#define ON	0
#define OFF	1

/*Three LEDs number*/
enum
{
	LED_R = 0,
	LED_G,
	LED_B,
	LEDCNT,
};

enum
{
	ACTIVE_HIGH,	/*LOW level will turn led on*/
	ACTIVE_LOW,	/*HIGH level will turn led on*/
};

/*Three LEDS hardware information*/
typedef struct led_s
{
	const char			*name;
	int				chip_num;
	int				gpio_num;
	int				active;
	struct gpiod_line_request	*request;
}led_t;

static led_t leds_info[LEDCNT] = 
{
	{"red",	 0, 3,ACTIVE_HIGH,NULL},
	{"green",0,18,ACTIVE_HIGH,NULL},
	{"blue", 0, 2,ACTIVE_HIGH,NULL},
};

/*Three LEDs API context*/
typedef struct leds_s
{
	led_t		*leds;
	int		count;
}leds_t;

/*function declaration*/
int init_led(leds_t *leds);
int term_led(leds_t *leds);
int turn_led(leds_t *leds, int which, int cmd);
static inline void msleep(unsigned long ms);

static int	g_stop = 0;

void sig_handler(int signum)
{
	switch( signum )
	{
		case SIGINT:
			g_stop = 1;
			break;
		case SIGTERM:
			g_stop = 1;
			break;
		default:
			break;
	}
	return ;
}

int main(int argc, char *argv[])
{
	int		rv;
	leds_t		leds = 
	{
		.leds  = leds_info,
		.count = LEDCNT,
	};

	if( (rv = init_led(&leds)) < 0 )
	{
		printf("initial leds gpio failure,rv=%d\n",rv);
		return -1;
	}
	printf("initial RGB LED gpios okay!\n");

	signal(SIGINT,  sig_handler);
	signal(SIGTERM, sig_handler);
	
	while( !g_stop )
	{
		turn_led(&leds,LED_R,ON);
		msleep(DELAY);
		turn_led(&leds,LED_R,OFF);
		msleep(DELAY);

		turn_led(&leds,LED_G,ON);
		msleep(DELAY);
		turn_led(&leds,LED_G,OFF);
		msleep(DELAY);

		turn_led(&leds,LED_B,ON);
		msleep(DELAY);
		turn_led(&leds,LED_B,OFF);
		msleep(DELAY);
	}

	term_led(&leds);
	return 0;
}

int turn_led(leds_t *leds, int which, int cmd)
{
	led_t		*led;
	int		rv = 0;
	int		value = 0;

	if( !leds || which<0 || which>=leds->count )
	{
		printf("Invalid input arguments\n");
		return -1;		
	}

	led = &leds->leds[which];

	value = OFF == cmd ? GPIOD_LINE_VALUE_ACTIVE : GPIOD_LINE_VALUE_INACTIVE;

	gpiod_line_request_set_value(led->request, led->gpio_num, value);

	return 0;
}	

static inline void msleep(unsigned long ms)
{
	struct timespec		cSleep;
	unsigned long		ulTmp;

	cSleep.tv_sec = ms / 1000;
	if(cSleep.tv_sec == 0)
	{
		ulTmp = ms * 10000;
		cSleep.tv_nsec = ulTmp * 100;
	}
	else
	{
		cSleep.tv_nsec = 0;
	}

	nanosleep(&cSleep, 0);

	return ;
}

int init_led(leds_t *leds)
{
	led_t				*led;
	int				i,rv = 0;
	char				chip_dev[32];
	struct gpiod_chip		*chip;
	struct gpiod_line_settings	*settings;
	struct gpiod_line_config	*line_cfg;
	struct gpiod_request_config	*req_cfg;

	if( !leds )
	{
		printf("Invalid input arguments\n");
		return -1;
	}
	
	/*struct gpiod_line_settings
	{
		enum gpiod_line_direction	direction;		设置 GPIO 线的方向(输入/输出)
		enum gpiod_line_edge		edge_detection;		设置 GPIO 线的边沿检测,用于捕获信号变化
		enum gpiod_line_drive		drive;			设置 GPIO 线的驱动模式
		enum gpiod_line_bias		bias;			设置 GPIO 线的偏置
		bool 				active_low;		设置 GPIO 线是否为低电平有效
		enum gpiod_line_clock		event_clock;		设置事件时钟,用于时间戳事件
		long				debounce_period_us;	设置去抖动的时间,以微秒为单位
		enum gpiod_line_value		output_value;		设置 GPIO 线的输出值
	};*/	

	settings = gpiod_line_settings_new();
	if( !settings )
	{
		printf("unable to allocate line settings\n");
		rv = -2;
		goto cleanup;
	}

	/*struct gpiod_line_config
	{
		struct per_line_config	line_configs[LINES_MAX];	配置每条 GPIO 线的特性,如方向、边沿检测、驱动模式、偏置等
		size_t			num_configs;			指示 line_configs 数组中有多少个有效的 GPIO 线配置信息
		enum gpiod_line_value   output_values[LINES_MAX];	设置每条 GPIO 线的输出值,如高电平、低电平
		size_t 			num_output_values;		指示 output_values 数组中有多少个有效的 GPIO 线输出值
		struct settings_node	*sref_list;			用于管理 GPIO 线的设置信息,如方向、边沿检测、驱动模式等
	};*/

	line_cfg = gpiod_line_config_new();
	if( !line_cfg )
	{
		printf("unable to allocate the line config structure");
		rv = -2;
		goto cleanup;
	}

	/*struct gpiod_request_config
	{
		char		consumer[GPIO_MAX_NAME_SIZE];		标识请求 GPIO 引脚的应用程序或模块
		size_t		event_buffer_size;			指定用于存储事件数据的缓冲区大小
	};*/

	req_cfg = gpiod_request_config_new();
	if( !req_cfg )
	{
		printf("unable to allocate the request config structure");
		rv = -2;
		goto cleanup;
	}

	for(i=0; i<leds->count; i++)
	{
		led = &leds->leds[i];

		snprintf(chip_dev, sizeof(chip_dev), "/dev/gpiochip%d", led->chip_num);
		chip = gpiod_chip_open(chip_dev);
		if( !chip )
		{
			printf("open gpiochip failure, maybe you need running as root\n");
			rv = -3;
			goto cleanup;
		}
		
		gpiod_line_settings_reset(settings);
		gpiod_line_settings_set_direction(settings, GPIOD_LINE_DIRECTION_OUTPUT);
		gpiod_line_settings_set_active_low(settings, led->active);
		gpiod_line_settings_set_output_value(settings, GPIOD_LINE_VALUE_ACTIVE);

		gpiod_line_config_reset(line_cfg);
		gpiod_line_config_add_line_settings(line_cfg, &led->gpio_num, 1, settings);
	
		gpiod_request_config_set_consumer(req_cfg, led->name);

		led->request = gpiod_chip_request_lines(chip, req_cfg, line_cfg);

		gpiod_chip_close(chip);
	}

cleanup:
	if( rv < 0 )
		term_led(leds);

	if( line_cfg )
		gpiod_line_config_free(line_cfg);

	if( req_cfg )
		gpiod_request_config_free(req_cfg);
	
	if( settings )
		gpiod_line_settings_free(settings);

	return rv;
}

int term_led(leds_t *leds)
{
	int		i;
	led_t		*led;
	
	printf("terminate RGB LED gpios\n");

	if( !leds )
	{
		printf("Invalid input arguments\n");
		return -1;
	}

	for(i=0; i<leds->count; i++)
	{
		led = &leds->leds[i];

		if( led->request )
		{
			turn_led(leds, i, OFF);
			gpiod_line_request_release(led->request);
		}
	}
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/708181.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

哈喽GPT-4o——对GPT-4o Prompt的思考与看法

目录 一、提示词二、提示词的优势1、提升理解能力2、增强专注力3、提高效率 三、什么样的算无效提示词&#xff1f;1、过于宽泛2、含糊不清3、太过复杂4、没有具体上下文5、缺乏明确目标6、过于开放7、使用专业术语但未定义8、缺乏相关性&#xff1a; 四、提示词正确的编写步骤…

ofd文件预览

文件列表 <template><div><div classfile v-if$myUtils.coll.isNotEmpty(filesList)><div classfile-view><div classfile-view-item :style{justifyContent: align } v-for(item, index) in filesList :keyindex><img classfile-view-item-…

纵深发力 持续推进,富格林平台发展势头喜人

自2024年2月1日正式上线以来,富格林互联网投融资平台已迅速崛起,吸引了业内专家学者的高度认可以及广大投资者的青睐。平台规模持续扩大,目前累计注册用户已超过10万人,总投资额突破50亿美元。这一卓越表现不仅体现了平台的稳健运营和出色的投资项目,也展示了其在互联网投融资领…

产品应用 | 小盒子跑大模型!英码科技基于算能BM1684X平台实现大模型私有化部署

当前&#xff0c;在人工智能领域&#xff0c;大模型在丰富人工智能应用场景中扮演着重要的角色&#xff0c;经过不断的探索&#xff0c;大模型进入到落地的阶段。而大模型在落地过程中面临两大关键难题&#xff1a;对庞大计算资源的需求和对数据隐私与安全的考量。为应对这些挑…

typora+Picgo使用Lsky pro搭建本地服务图床

typoraPicgo使用Lsky pro搭建本地服务图床 Picgo下载lankong插件lankong插件安装Auth token获取 Picgo测试typora测试问题说明 Picgo下载 Picgo下载&#xff1a;https://github.com/Molunerfinn/PicGo/releases&#xff0c;注意&#xff1a;请直接使用尝鲜版&#xff0c;正式版…

一文让你清晰了解医疗行业采购堡垒机的必要性

医疗行业&#xff0c;一个与大家息息相关的行业。随着医疗行业的快速发展和信息化建设的深入推进&#xff0c;传统网络安全防护手段已经难以满足现代医疗信息系统的安全需求&#xff0c;特别是在处理敏感的患者信息和保障医院内部数据安全方面。因此采购堡垒机是非常必要的。 堡…

python310: pip install Could not install packages (HTTPSConnectionPool)问题

一、问题描述 在使用pip install安装包或者升级pip版本&#xff08;pip install --upgrade pip&#xff09;时遇到以下错误&#xff1a; WARNING: Retrying (Retry(total4, connectNone, readNone, redirectNone, statusNone)) after connection broken by ReadTimeoutError(…

github ssh key的SHA256是什么

github ssh key的SHA256是什么 怎么知道github上自己的公钥指纹和本地的公钥是否一致&#xff1f; 计算方法如下&#xff1a; cat .ssh/id_rsa.pub |awk { print $2 } | # Only the actual key data without prefix or commentsbase64 -d | # decode as base64s…

面向对象编程重载

系列文章目录 文章目录 系列文章目录前言一、重载&#xff08;overload&#xff09; 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文章男女通用&#xff0c;看懂了…

现货白银实时交易平台的成长阶段 你出在哪个阶段?

很多人喜欢在现货白银平台上做模拟交易&#xff0c;因为他们认为现货白银实时交易平台上交易太痛苦了&#xff0c;不光随时会面临风险&#xff0c;而且还可能让自己出现大的亏损。如果投资者认为痛苦&#xff0c;那笔者觉得投资者不妨将在现货白银实时交易平台上做交易&#xf…

nodejs 某音douyin网页端搜索接口及x_bogus、a_bogus(包含完整源码)(2024-06-13)

前言 x_bogus或a_bogus算法大概是对数据、ua、时间戳、浏览器的几个指纹进行计算&#xff0c;拿到一个110位大数组&#xff0c;然后转字符&#xff0c;在头部再添加十二位随机字符&#xff0c;再进行魔改的base64加密。 问&#xff1a;抖音的x_bogus、a_bogus值有什么用&#x…

win10 双显卡,双显示器,VGA那个经常出现息屏(待机后无法唤醒),必须重启才能解决,(图文)手把手教你如何处理简单愉快的解决。

一、问题 双显示器&#xff08;双显卡&#xff0c;其中一个是HDMI&#xff0c;一个是VGA&#xff09;window系统&#xff08;本机win10&#xff09;&#xff0c;经常莫名出现&#xff0c;在待机或者主动息屏后&#xff0c;VGA显示器无法唤醒&#xff0c;依然黑屏&#xff0c;不…

蚂蚁集团:2023年科研投入211.9亿元

6月13日&#xff0c;蚂蚁集团发布2023年可持续发展报告。报告显示&#xff0c;2023年蚂蚁集团科研投入达到211.9亿元&#xff0c;再创历史新高&#xff0c;蚂蚁科技投入的重点是人工智能和数据要素技术。 蚂蚁集团董事长兼CEO井贤栋在报告致辞中说&#xff0c;面向未来&#x…

Java项目:110 springboot夕阳红公寓管理系统的设计与实现

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 本系统有管理员&#xff0c;租客 管理员权限操作的功能包括对租客&#xff0c;访客&#xff0c;缴费&#xff0c;维修&#xff0c;留言&#xff0c;公…

如何使用CCS9.3打开CCS3.0工程

如何使用CCS9.3打开CCS3.0工程 点菜单栏上的project&#xff0c;选择Import Legacy CCSv3.3 Porjects…&#xff0c;弹出对话框&#xff0c;通过Browse…按钮导入一个3.3版本的工程项目&#xff1b; 选择.pjt文件&#xff0c;选择Copy projects into worlkspace 右击选择P…

2001-2023年上市公司数字化转型测算数据(含原始数据+处理代码+计算结果)

2001-2023年上市公司数字化转型测算数据&#xff08;含原始数据处理代码计算结果&#xff09;&#xff08;吴非&#xff09; 1、时间&#xff1a;2001-2023年 2、来源&#xff1a;上市公司年报 3、指标:行业代码、行业名称、证券简称、是否发生ST或ST或PT、是否发生暂停上市…

【ARM】MDK出现报错error: A\L3903U的解决方法

【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 解决MDK出现报错error: A\L3903U这样类型的报错 2、 问题场景 电脑或者软件因为意外情况导致崩溃&#xff0c;无法正常关闭&#xff0c;强制电脑重启之后&#xff0c;打开工程去编译出现下面的报错信息&#xff08;…

Node-Red和IOT-Tree中的消息流对软件开发的一点思考

上一篇文章IOT-Tree 1.7.0实现了一个类似Node-Red的流程功能中&#xff0c;我提到了如下文字内容&#xff1a; 通过这样的图形化编程机制把软件开发直接分成了两个层次。 1. 一个是应用层面&#xff0c;给用户、项目实施技术人员或维护人员能够在不需要掌握深入技术的前提下&am…

颈肌筋膜炎怎么治疗

颈肌筋膜炎的症状主要包括&#xff1a; 1、疼痛&#xff1a;疼痛多局限于项部&#xff0c;两侧为重&#xff0c;晨起时明显&#xff0c;活动后减轻&#xff0c;阴雨天时可能加重。疼痛以持续性酸胀疼痛为特点&#xff0c;严重时可能伴有头痛、肩、背痛。 2、压痛&#xff1a;在…

从零开始写 Docker(十八)---容器网络实现(下):为容器插上”网线“

本文为从零开始写 Docker 系列第十八篇&#xff0c;利用 linux 下的 Veth、Bridge、iptables 等等相关技术&#xff0c;构建容器网络模型&#xff0c;为容器插上”网线“。 完整代码见&#xff1a;https://github.com/lixd/mydocker 欢迎 Star 推荐阅读以下文章对 docker 基本实…