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 libgpiodwget https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git/snapshot/libgpiod-2.0.tar.gztar -xzf libgpiod-2.0.tar.gzcd 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}stripunset CFLAGS
unset LDFLAGSecho "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.cachemakemake 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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DDei在线设计器-属性编辑器

DDei-Core-属性编辑器 DDei-Core-属性编辑器插件包含了文本、大文本、数值、下拉、单选、勾选以及颜色等属性编辑。 图形和属性共同构成一个完整的定义&#xff0c;属性编辑器就是编辑属性值的控件。当选中图形实例时&#xff0c;属性面板就会展现当前实例的所有属性以及属性编…

m4s转mp3——B站缓存视频提取音频

前言 しかのこのこのここしたんたん&#xff08;鹿乃子乃子虎视眈眈&#xff09;非常之好&#xff0c;很适合当闹钟&#xff0c;于是缓存了视频&#xff0c;想提取音频为mp3 直接改后缀可乎&#xff1f;格式转换工具&#xff1f; 好久之前有记录过转MP4的&#xff1a; m4s转为…

美国空军发布类ChatGPT产品—NIPRGPT

6月11日&#xff0c;美国空军研究实验室&#xff08;AFRL&#xff09;官网消息&#xff0c;空军部已经发布了一款生成式AI产品NIPRGPT。 据悉&#xff0c;NIPRGPT是一款类ChatGPT产品&#xff0c;可生成文本、代码、摘要等内容&#xff0c;主要为为飞行员、文职人员和承包商提…

文件没有权限问题:cannot create /opt/apollo/neo/data/log/monitor.log: Permission denied

问题描述 执行 aem bootstrap start --plus 命令启动 Dreamview 提示错误&#xff1a; /bin/sh: 1: cannot create /opt/apollo/neo/data/log/monitor.log: Permission denied [ERROR] Failed to start Dreamview. Please check /opt/apollo/neo/data/log/dreamview.log or /op…

ArrayList和LinkedList的区别!!!

总结&#xff1a; 1、数据结构的实现 ArrayList&#xff1a;动态数组。 LinkedList&#xff1a;双向链表。 2、时间复杂度不同 ArrayList&#xff1a;O(1) LinkedList: O(n) ①&#xff1a;随机访问---- ArrayList > LinkedList &#xff08;ArrayList采用下标&#xff0…

ARM-V9 RME(Realm Management Extension)系统架构之调试

安全之安全(security)博客目录导读 本节中&#xff0c;“RMSD外部调试”一词用于描述任何系统或PE的外部调试功能&#xff0c;这些功能能够实现以下目的&#xff1a; 监控或修改RMSD行为。对Realm PAS或Realm安全状态的外部访问。 本节中&#xff0c;“Root外部调试”一词用于…

C++ 实现HTTP的客户端、服务端demo和HTTP三方库介绍

本文使用C模拟实现http的客户端请求和http的服务端响应功能&#xff0c;并介绍几种封装HTTP协议的三方库。 1、实现简单HTTP的服务端功能 本程序使用C tcp服务端代码模拟HTTP的服务端&#xff0c;服务端返回给客户端的消息内容按照HTTP协议的消息响应格式进行了组装。 demo如…

PC端剪映6.0免vip版本,功能随便用

下载解压后点击“JianyingPro.exe”图标即可使用&#xff0c;使用过程中无需登陆账号。操作很简单。 链接&#xff1a;https://pan.baidu.com/s/14bon1Ta9GOUFyUZDa2X3TA?pwd8h2b 提取码&#xff1a;8h2b

采用ava+B/S架构开发的工业级UWB(Ultra-Wideband)室内定系统源码UWB定位系统技术接口及技术特点

采用avaB/S架构开发的工业级UWB&#xff08;Ultra-Wideband&#xff09;室内定系统源码UWB定位系统技术接口及技术特点 UWB&#xff08;Ultra-Wideband&#xff09;定位技术本身并不直接连接蓝牙或其他无线通信技术进行定位。然而&#xff0c;在实际应用中&#xff0c;UWB定位技…

怎么用住宅代理IP?使用住宅代理IP有哪些好处?

如何使用住宅代理IP&#xff1a; 使用住宅代理IP主要涉及以下几个步骤&#xff1a; 选择合适的代理IP供应商&#xff1a; 考虑供应商的可靠性、代理IP的质量、速度、稳定性以及价格。选择信誉良好且服务稳定的供应商&#xff0c;确保获得高质量的代理IP服务。配置代理IP&#…

代理IP常见问题解答,新手必看手册

代理IP在互联网数据收集和业务开展中发挥着重要作用&#xff0c;它充当用户客户端和网站服务器之间的“屏障”&#xff0c;可以保护用户的真实IP地址&#xff0c;并允许用户通过不同的IP地址进行操作。然而&#xff0c;在使用代理IP的过程中&#xff0c;用户经常会遇到一些问题…

vue 中多个表单元素控一个校验规则

1. 场景一 <el-form-itemlabel"确认时长方式"prop"preSubResourceDurationDay" ><div class"confirmDurationDay">最晚使用日期前<el-input-numberv-model"form.preSubResourceDurationDay":precision"0"cla…

axure使用中继器画柱状图

源文件在顶部。 在axure通过读取中继器中的数据来画柱状图&#xff0c;如下图&#xff1a; 1&#xff09;创建一个中继器&#xff0c;在里面创建两列&#xff1a;1列是柱状图底部的名称、2列是柱的高度&#xff0c;如下图&#xff1a; 2&#xff09;双击中继器&#xff0c;画一…

ansible安装wordpress

1.回顾 yum安装wordpress 查看别名 [rootlocalhost ~]# type ll ll 是 ls -l --colorauto 的别名设置别名 aliasyum install -y alias ymyum install -y# 使用别名 ym nginx# 取消别名 unalias ym# 基于LNMP做一个wordpressnginx mysql 5.7 PHP 7.4#1、初始化过程 修改主机名…

【code-server】Code-Server 安装部署

Code-Server 安装部署 1.环境准备 可以参考 https://coder.com/docs/code-server/install code-server的安装流程进行安装&#xff0c;主机环境是 Centos7 建议使用 docker 方式进行安装&#xff0c;可能会出现如下报错&#xff0c;需要升级 GNC 的版本&#xff0c;由于影响交…

派能协议,逆变器测试问题记录

问题一&#xff1a;逆变器无法进行逆变 通过抓取逆变器与bms的通讯报文&#xff0c;如下&#xff1a; 根据派能协议&#xff0c;报文标黄的对应充放电状态&#xff0c;30 30对应的数据为0 0&#xff0c;说明充放电状态全部置0&#xff0c;导致逆变器无法逆变。 问题二&#xf…

推荐系统三十六式学习笔记:原理篇.近邻推荐09|协同过滤中的相似度计算方法有哪些?

目录 相似度的本质相似度的计算方法&#xff1a;1、欧式距离2、余弦相似度3、皮尔逊相关度4 、杰卡德&#xff08;Jaccard&#xff09;相似度 总结 相似度的本质 推荐系统中&#xff0c;推荐算法分为两个门派&#xff0c;一个是机器学习派&#xff0c;一个是相似度门派。机器学…

【记录】ChatGLM3-6B大模型部署、微调(一):部署

ChatGLM3介绍 源码连接&#xff1a; ChatGLM3 是智谱AI和清华大学 KEG 实验室联合发布的对话预训练模型。ChatGLM3-6B 是 ChatGLM3 系列中的开源模型&#xff0c;在保留了前两代模型对话流畅、部署门槛低等众多优秀特性的基础上&#xff0c;ChatGLM3-6B 引入了如下特性&#xf…

算法:模拟题目练习

目录 题目一&#xff1a;替换所有的问号 题目二&#xff1a;提莫攻击 题目三&#xff1a;N字形变换 题目四&#xff1a;外观数列 题目五&#xff1a;数青蛙 首先先解释一下模拟算法是什么&#xff0c;其实模拟算法就是题目让我们干什么我们就干什么&#xff0c;思路比较简…

noVNC 小记

1. 怎么查看Ubuntu版本