当前位置: 首页 > news >正文

Linux-GPIO应用编程

本章介绍应用层如何控制 GPIO,譬如控制 GPIO 输出高电平、或输出低电平。 只要是用到GPIO的外设,都有可能用得到这些操作方法。

照理说,GPIO的操作应该是由驱动层去做的,使用寄存器操作或者GPIO子系统之类的框架。

但是,应用层直接操作GPIO是为啥?

在听韦东山老师的驱动大全课程时,听他提到过一个“应用层驱动”的说法,也就是直接在应用层操作底层硬件,从而可以将驱动层要做的一些事情,放到应用层来做,这样方便应用层直接调试硬件。不知道这个说法有没有什么用,所以先了解下即可。

使用sys操作硬件和使用设备驱动方式操作硬件有什么区别?

Linux中应用层操作硬件的方式主要有通过sysfs文件系统和设备驱动两种方式。以下是具体分析:

通过sysfs文件系统

  1. 概念:sysfs(System Filesystem)是Linux内核中的一个虚拟文件系统,提供了一种与设备进行交互的接口。

  2. 特点:sysfs允许用户空间程序通过读取和写入/sys目录下的文件来访问设备信息和修改设备设置。这种方式不需要编写驱动程序,但功能有限,主要用于查看设备状态和配置信息。

  3. 优点:使用简单,无需编写复杂的驱动程序代码;适合快速开发和测试。

  4. 缺点:功能受限,不能直接控制硬件;性能较低,不适合高频操作。

通过设备驱动

  1. 概念:设备驱动是操作系统与硬件设备之间的接口和管理器,负责与硬件设备进行通信并提供操作系统与硬件设备之间的接口。

  2. 特点:设备驱动将硬件的复杂操作抽象为操作系统的标准接口,简化了用户对硬件的操作;负责管理硬件资源,如内存、I/O端口、硬件缓冲区等。

  3. 优点:功能强大,能够直接控制硬件;性能高,适合需要高频操作的场景。

  4. 缺点:开发难度较大,需要深入了解硬件和操作系统内核;维护成本高,需要随着硬件和操作系统的更新而不断更新驱动程序。

综上所述,通过sysfs文件系统操作硬件和使用设备驱动方式操作硬件各有优缺点。sysfs方式操作简单但功能有限,适合快速开发和测试;而设备驱动方式功能强大但开发难度大,适合需要高性能和直接控制硬件的场景。

本章将会讨论如下主题内容。

⚫ 应用层 GPIO 编程介绍;

⚫ GPIO 输出测试;

⚫ GPIO 输入测试;

⚫ GPIO 中断测试;

应用层如何操控 GPIO

与 LED 设备一样,GPIO 同样也是通过 sysfs 方式进行操控,进入到/sys/class/gpio 目录下,如下所示:

可以看到该目录下包含两个文件 export、unexport 以及 5 个 gpiochipX(X 等于 0、32、64、96、128)命名的文件夹。

gpiochipX:当前 SoC 所包含的 GPIO 控制器,我们知道 I.MX6UL/I.MX6ULL 一共包含了 5 个 GPIO控制器,分别为 GPIO1、GPIO2、GPIO3、GPIO4、GPIO5,在这里分别对应 gpiochip0、gpiochip32、gpiochip64、gpiochip96、gpiochip128 这 5 个文件夹,每一个 gpiochipX 文件夹用来管理一组 GPIO。

随便进入到其中某个目录下,可以看到这些目录下包含了如下文件:

在这个目录我们主要关注的是 base、label、ngpio 这三个属性文件,这三个属性文件均是只读、不可写。

base:与 gpiochipX 中的 X 相同,表示该控制器所管理的这组 GPIO 引脚中最小的编号。每一个 GPIO引脚都会有一个对应的编号,Linux 下通过这个编号来操控对应的 GPIO 引脚。

label:该组 GPIO 对应的标签,也就是名字。

ngpio:该控制器所管理的 GPIO 引脚的数量(所以引脚编号范围是:base ~ base+ngpio-1)。

对于给定的一个 GPIO 引脚,如何计算它在 sysfs 中对应的编号呢?其实非常简单,譬如给定一个 GPIO引脚为 GPIO4_IO16,那它对应的编号是多少呢?首先我们要确定 GPIO4 对应于 gpiochip96,该组 GPIO 引脚的最小编号是 96(对应于 GPIO4_IO0),所以 GPIO4_IO16 对应的编号自然是 96 + 16 = 112;同理GPIO3_IO20 对应的编号是 64 + 20 = 84。

export:用于将指定编号的 GPIO 引脚导出。在使用 GPIO 引脚之前,需要将其导出,导出成功之后才能使用它。注意 export 文件是只写文件,不能读取,将一个指定的编号写入到 export 文件中即可将对应的 GPIO 引脚导出,譬如:

echo 0 > export //导出编号为 0 的 GPIO 引脚(对于 I.MX6UL/I.MX6ULL 来说,也就是GPIO1_IO0)

导出成功之后会发现在/sys/class/gpio 目录下生成了一个名为 gpio0 的文件夹(gpioX,X 表示对应的编号),如图 16.1.7 所示。这个文件夹就是导出来的 GPIO 引脚对应的文件夹,用于管理、控制该 GPIO 引脚,稍后再给大家介绍。

unexport:将导出的 GPIO 引脚删除。当使用完 GPIO 引脚之后,我们需要将导出的引脚删除,同样该文件也是只写文件、不可读,譬如:

echo 0 > unexport //删除导出的编号为 0 的 GPIO 引脚

删除成功之后,之前生成的 gpio0 文件夹就会消失!

以上就给大家介绍了/sys/class/gpio 目录下的所有文件和文件夹,控制 GPIO 引脚主要是通过 export 导出之后所生成的 gpioX(X 表示对应的编号)文件夹,在该文件夹目录下存在一些属性文件可用于控制 GPIO引脚的输入、输出以及输出的电平状态等。

Tips:需要注意的是,并不是所有 GPIO 引脚都可以成功导出,如果对应的 GPIO 已经在内核中被使用了,那便无法成功导出,打印如下信息:

那也就是意味着该引脚已经被内核使用了,譬如某个驱动使用了该引脚,那么将无法导出成功!

gpioX

将指定的编号写入到 export 文件中,可以导出指定编号的 GPIO 引脚,导出成功之后会在/sys/class/gpio目录下生成对应的 gpioX(X 表示 GPIO 的编号)文件夹,以前面所生成的 gpio0 为例,进入到 gpio0 目录,该目录下的文件如下所示:

我们主要关心的文件是 active_low、direction、edge 以及 value 这四个属性文件,接下来分别介绍这四个属性文件的作用:

direction:配置 GPIO 引脚为输入或输出模式。该文件可读、可写,读表示查看 GPIO 当前是输入还是输出模式,写表示将 GPIO 配置为输入或输出模式;读取或写入操作可取的值为"out"(输出模式)和"in"(输入模式),如下所示:

value:在 GPIO 配置为输出模式下,向 value 文件写入"0"控制 GPIO 引脚输出低电平,写入"1"则控制 GPIO 引脚输出高电平。在输入模式下,读取 value 文件获取 GPIO 引脚当前的输入电平状态。

譬如:

# 获取 GPIO 引脚的输入电平状态 
echo "in" > direction 
cat value 
# 控制 GPIO 引脚输出高电平 
echo "out" > direction 
echo "1" > value

active_low:这个属性文件用于控制极性,可读可写,默认情况下为 0,譬如:

# active_low 等于 0 时 
echo "0" > active_low 
echo "out" > direction 
echo "1" > value #输出高 
echo "0" > value #输出低 
# active_low 等于 1 时 
$ echo "1" > active_low 
$ echo "out" > direction 
$ echo "1" > value #输出低 
$ echo "0" > value #输出高

由此看出,active_low 的作用已经非常明显了,对于输入模式来说也同样适用。

edge:控制中断的触发模式,该文件可读可写。在配置 GPIO 引脚的中断触发模式之前,需将其设置为输入模式:

非中断引脚:echo "none" > edge

上升沿触发:echo "rising" > edge

下降沿触发:echo "falling" > edge

边沿触发:echo "both" > edge

当引脚被配置为中断后可以使用 poll()函数监听引脚的电平状态变化,在后面的示例中将向大家介绍。

GPIO 应用编程之输出

上一小节已经向大家介绍了如何通过 sysfs 方式控制开发板上的 GPIO 引脚,本小节我们编写一个简单地测试程序,控制开发板上的某一个 GPIO 输出高、低不同的电平状态,其示例代码如下所示:

执行程序时需要传入两个参数,argv[1]指定 GPIO 的编号、argv[2]指定输出电平状态(0 表示低电平、1 表示高电平)。

上述代码中首先使用 access()函数判断指定编号的 GPIO 引脚是否已经导出,也就是判断相应的 gpioX目录是否存在,如果不存在则表示未导出,则通过"/sys/class/gpio/export"文件将其导出;导出之后先配置了GPIO 引脚为输出模式,也就是向 direction 文件中写入"out";接着再配置极性,通过向 active_low 文件中写入"0"(不用配置也可以);最后再控制 GPIO 引脚输出相应的电平状态,通过对 value 属性文件写入"1"或"0"来使其输出高电平或低电平。

使用交叉编译工具编译应用程序,如下所示:

GPIO 应用编程之输入

本小节我们编写一个读取 GPIO 电平状态的测试程序,其示例代码如下所示:

本例程源码对应的路径为:开发板光盘->11、Linux C 应用编程例程源码->16_gpio->gpio_in.c。

执行程序时需要传入一个参数,argv[1]指定要读取电平状态的 GPIO 对应的编号。

上述代码中首先使用 access()函数判断指定编号的 GPIO 引脚是否已经导出,若未导出,则通过 "/sys/class/gpio/export"文件将其导出;导出之后先配置了 GPIO 引脚为输入模式,也就是向 direction 文件中写入"in";接着再配置极性、设置 GPIO 引脚为非中断模式(向 edge 属性文件中写入"none")。

最后打开 value 属性文件,读取 GPIO 的电平状态并将其打印出来。

使用交叉编译工具编译应用程序,如下所示:

GPIO 应用编程之中断

在应用层可以将 GPIO 配置为中断触发模式,譬如将 GPIO 配置为上升沿触发、下降沿触发或者边沿触发,本小节我们来编写一个测试程序,将 GPIO 配置为边沿触发模式并监测中断触发状态。其示例代码如下所示:

本例程源码对应的路径为:开发板光盘->11、Linux C 应用编程例程源码->16_gpio->gpio_intr.c。

执行程序时需要传入一个参数,argv[1]指定要读取电平状态的 GPIO 对应的编号。

上述代码中首先使用 access()函数判断指定编号的 GPIO 引脚是否已经导出,若未导出,则通过"/sys/class/gpio/export"文件将其导出。

对 GPIO 进行配置:配置为输入模式、配置极性、将触发方式配置为边沿触发。

打开 value 属性文件,获取到文件描述符,接着使用 poll()函数对 value 的文件描述符进行监视,这里为什么要使用 poll()监视、而不是直接对文件描述符进行读取操作?这里简单的描述一下。

13.2.3 小节给大家详细介绍了 poll()函数,这里不再重述!poll()函数可以监视一个或多个文件描述符上的 I/O 状态变化,譬如 POLLIN、POLLOUT、POLLERR、POLLPRI 等,其中 POLLIN 和 POLLOUT 表示普通优先级数据可读、可写,而 POLLPRI 表示有高优先级数据可读取,中断就是一种高优先级事件,当中断触发时表示有高优先级数据可被读取。当然,除此之外还可使用 13.4 小节所介绍的异步 I/O 方式来监视GPIO 中断触发。

使用交叉编译工具编译应用程序,如下所示:

在开发板上测试

前面我们编写了 3 个测试程序,并编译得到了对应的可执行文件,本小节一个一个进行测试。在测试之前,选择一个测试引脚,这里笔者以板子上的 GPIO1_IO01 引脚为例,该引脚在底板上已经引出,如下所示:

Mini 开发板可以通过背面丝印标注的名称或原理图进行确认。

GPIO 输出测试

将示例代码 16.2.1 编译的到的可执行文件拷贝到开发板 Linux 系统用户家目录下,执行该应用程序控制开发板上的 GPIO1_IO01 引脚输出高或低电平:

./testApp 1 1 #控制 GPIO1_IO01 输出高电平

./testApp 1 0 #控制 GPIO1_IO01 输出低电平

执行相应的命令后,可以使用万用表或者连接一个 LED 小灯进行检验,以验证实验结果!

GPIO 输入测试

将示例代码 16.3.1 编译的到的可执行文件拷贝到开发板 Linux 系统用户家目录下,执行该应用程序以读取 GPIO1_IO01 引脚此时的电平状态,是高电平还是低电平?

首先通过杜邦线将 GPIO1_IO01 引脚连接到板子上的 3.3V 电源引脚上,接着执行命令读取 GPIO 电平状态:

打印出的 value 等于 1,表示读取到 GPIO 的电平确实是高电平;接着将 GPIO1_IO01 引脚连接到板子上的 GND 引脚上,执行命令:

打印出的 value 等于 0,表示读取到 GPIO 的电平确实是低电平;测试结果与实际相符合!

GPIO 中断测试

将示例代码 16.4.1 编译的到的可执行文件拷贝到开发板 Linux 系统用户家目录下,执行该应用程序可以监测 GPIO 的中断触发。

执行应用程序监测 GPIO1_IO01 引脚的中断触发情况,如下所示:

./testApp 1 //监测 GPIO1_IO01 引脚中断触发

当执行命令之后,我们可以使用杜邦线将 GPIO1_IO01 引脚连接到 GND 或 3.3V 电源引脚上,来回切换,使得 GPIO1_IO01 引脚的电平状态发生由高到低或由低到高的状态变化,以验证 GPIO 中断的边沿触发情况;当发生中断时,终端将会打印相应的信息,如上图所示。

Tips:测试完成后按 Ctrl+C 退出程序!

相关文章:

Linux-GPIO应用编程

本章介绍应用层如何控制 GPIO,譬如控制 GPIO 输出高电平、或输出低电平。 只要是用到GPIO的外设,都有可能用得到这些操作方法。 照理说,GPIO的操作应该是由驱动层去做的,使用寄存器操作或者GPIO子系统之类的框架。 但是&#xff0…...

opencvocr识别手机摄像头拍摄的指定区域文字,文字符合规则就语音报警

安装python,pycharm,自行安装。 Python下安装OpenCv 2.1 打开cmd,先安装opencv-python pip install opencv-python --user -i https://pypi.tuna.tsinghua.edu.cn/simple2.2 再安装opencv-contrib-python pip install opencv-contrib-python --user …...

微服务即时通讯系统(5)用户管理子服务,网关子服务

用户管理子服务(user文件) 用户管理子服务也是这个项目中的一个业务最多的子服务,接口多,但是主要涉及的数据表只有user表,Redis的键值对和ES的一个搜索引擎,主要功能是对用户的个人信息进行修改管理&#…...

postgreSQL安装后启动有The application server could not be contacted问题

不得不说pgsql是真的麻烦,找问题找了几个小时才解决.直接步入主题吧 首先问题如下 安装后,双击启动就出现上述问题 首先删除路径为 c:\Users\your_name\AppData\Roaming\pgAdmin 之内的所有文件和文件夹, 如果找不到AppData,就把这个点开 接着找到你安装pgsql的路径,我的是D…...

架构05-架构安全性

零、文章目录 架构05-架构安全性 1、软件架构安全的重要性 **系统安全:**不仅包括防御黑客攻击,还包括安全备份与恢复、安全审计、防治病毒等。**关注重点:**认证、授权、凭证、保密、传输安全、验证。 2、认证(Authenticatio…...

虚幻引擎---材质篇

一、基础知识 虚幻引擎中的材质(Materials) 定义了场景中对象的表面属性,包括颜色、金属度、粗糙度、透明度等等;可以在材质编辑器中可视化地创建和编辑材质;虚幻引擎的渲染管线的着色器是用高级着色语言(…...

NPM镜像详解

NPM镜像详解 什么是NPM镜像 NPM镜像(NPM Mirror)是一个完整的NPM包的副本服务器。由于npm的官方registry服务器部署在国外,国内访问可能会比较慢,因此使用镜像可以加快包的下载速度。 常用的NPM镜像源 npm官方镜像 https://reg…...

从智能合约到去中心化AI:Web3的技术蓝图

Web3正在成为互联网发展的重要方向,其核心理念是去中心化、用户主权和自治。随着区块链技术、智能合约以及人工智能(AI)等技术的发展,Web3不仅重新定义了数据存储和交易方式,还为更智能化、去中心化的数字生态系统铺平…...

STM32进阶 定时器3 通用定时器 案例1:LED呼吸灯——PWM脉冲

功能 它有基本定时器所有功能,还增加以下功能 TIM2、TIM3、TIM4、TIM5 多种时钟源: 外部时钟源模式1: 每个定时器有四个输入通道 只有通道1和通道2的信号可以作为时钟信号源 通道1 和通道2 的信号经过输入滤液和边缘检测器 外部时钟源…...

开源即时通讯与闭源即时通讯该怎么选择,其优势是什么?

在选择即时通讯软件时,应根据企业的经营领域来选择适合自身需求的开源或闭源方案。不同领域对开源和闭源即时通讯的理念存在差异,因此总结两个点简要分析这两种选择,有助于做出更明智的决策。 一、开源与闭源的根本区别在于软件的源代码是否…...

930[water]

算法...

2024论文翻译 | Multi-Review Fusion-in-Context

摘要 接地气的文本生成,包括长篇问答和摘要等任务,需要同时进行内容选择和内容整合。当前的端到端方法由于其不透明性,难以控制和解释。因此,近期的研究提出了一个模块化方法,每个步骤都有独立的组件。具体来说&#…...

(78)MPSK基带调制通信系统瑞利平坦衰落信道传输性能的MATLAB仿真

文章目录 前言一、MATLAB仿真1.仿真代码2.仿真结果 二、子函数与完整代码总结 前言 本文给出瑞利平坦衰落信道上的M-PSK通信系统性能仿真的MATLAB源代码与仿真结果。其中,调制方式M-PSK包括BPSK、QPSK、8-PSK、16-PSK、32-PSK等方式。 一、MATLAB仿真 1.仿真代码 …...

【机器学习】机器学习的基本分类-监督学习-决策树-CART(Classification and Regression Tree)

CART(Classification and Regression Tree) CART(分类与回归树)是一种用于分类和回归任务的决策树算法,提出者为 Breiman 等人。它的核心思想是通过二分法递归地将数据集划分为子集,从而构建一棵树。CART …...

【金猿CIO展】复旦大学附属中山医院计算机网络中心副主任张俊钦:推进数据安全风险评估,防范化解数据安全风险,筑牢医疗数据安全防线...

‍ 张俊钦 本文由复旦大学附属中山医院计算机网络中心副主任张俊钦撰写并投递参与“数据猿年度金猿策划活动——2024大数据产业年度优秀CIO榜单及奖项”评选。 大数据产业创新服务媒体 ——聚焦数据 改变商业 数据要素时代,医疗数据已成为医院运营与决策的重要基石…...

工业机器视觉-基于深度学习的水表表盘读数识别

字轮数字识别、指针读数识别(角度换算)、根据指针角度进行读数修正、根据最高位指针(x0.1)读数对字轮数字进行修正、得到最终读数。 基于深度学习的目标检测技术和OpenCV图像处理技术,可识别所有类型的表盘机械读数。...

基于ZooKeeper搭建Hadoop高可用集群

ZooKeeper搭建Hadoop高可用集群 在之前安装的Hadoop3.3.6集群中HDFS NameNode 和 YARN ResourceManager 都是单节点,集群不具有高可用性。 HDFS 高可用架构 HDFS 高可用架构主要组件: Active NameNode 和 Standby NameNode: 两台 NameNode…...

力扣88题:合并两个有序数组

力扣88题:合并两个有序数组 题目描述 给定两个按非递减顺序排列的整数数组 nums1 和 nums2,以及它们的长度 m 和 n,要求将 nums2 合并到 nums1,使得合并后的数组仍按非递减顺序排列。 输入与输出 示例 1: 输入&am…...

python 笔记之线程同步和死锁

同步: 共享数据: 如果多个线程共同对某个数据修改,则可能出现不可预测的结果,为了保证数据的正确性,需要对多个数据进行同步 同步:一个一个的完成,一个做完另一个才能进来 效率会降低 使用Thre…...

SpringBoot小知识(4):高级配置知识与bean的绑定

一、EnableConfigurationProperties ConfigurationProperties注解在我们之前讲过,他是从配置中读取参数封装给实体类的一个注解。 那么EnableConfigurationProperties是个啥呢? EnableConfigurationProperties 是 Spring Framework 中用于启用基于配置文…...

浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)

✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

Chapter03-Authentication vulnerabilities

文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

django filter 统计数量 按属性去重

在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

MFC 抛体运动模拟:常见问题解决与界面美化

在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...

Web后端基础(基础知识)

BS架构&#xff1a;Browser/Server&#xff0c;浏览器/服务器架构模式。客户端只需要浏览器&#xff0c;应用程序的逻辑和数据都存储在服务端。 优点&#xff1a;维护方便缺点&#xff1a;体验一般 CS架构&#xff1a;Client/Server&#xff0c;客户端/服务器架构模式。需要单独…...