第二个Qt开发实例:在Qt中利用GPIO子系统和sysfs伪文件系统实现按钮(Push Button)点击控制GPIO口(效果为LED2灯的灭和亮)

引言

本文承接博文 https://blog.csdn.net/wenhao_ir/article/details/145420998 里的代码,在那里面代码的基础上添加上利用sysfs伪文件系统实现按钮(Push Button)点击控制GPIO口的代码,进而实现LED2灯的灭和亮。
最终的效果是点击下面的LED按钮实现LED2的灭和亮。
在这里插入图片描述
本文使用了GPIO子系统和sysfs伪文件系统去操控GPIO口,
关于GPIO子系统的详细介绍见:https://blog.csdn.net/wenhao_ir/article/details/145444452
关于sysfs伪文件系统的详细介绍见:https://blog.csdn.net/wenhao_ir/article/details/145453877

完整源代码

文件mainwindow.ui 中的代码

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>MainWindow</class><widget class="QMainWindow" name="MainWindow"><property name="geometry"><rect><x>0</x><y>0</y><width>800</width><height>600</height></rect></property><property name="windowTitle"><string>MainWindow</string></property><widget class="QWidget" name="centralwidget"><widget class="QPushButton" name="pushButton"><property name="geometry"><rect><x>90</x><y>130</y><width>89</width><height>25</height></rect></property><property name="text"><string>LED</string></property></widget><widget class="QLabel" name="label"><property name="geometry"><rect><x>260</x><y>80</y><width>71</width><height>41</height></rect></property><property name="text"><string>TextLabel</string></property></widget><widget class="QLabel" name="label_2"><property name="geometry"><rect><x>260</x><y>160</y><width>71</width><height>31</height></rect></property><property name="text"><string>TextLabel</string></property></widget></widget><widget class="QMenuBar" name="menubar"><property name="geometry"><rect><x>0</x><y>0</y><width>800</width><height>22</height></rect></property></widget><widget class="QStatusBar" name="statusbar"/></widget><resources/><connections/>
</ui>

文件led.h中的代码

#ifndef LED_H
#define LED_Hvoid led_init(void);
void led_control(int on);#endif // LED_H

文件mainwindow.h中的代码

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void on_pushButton_clicked();private:Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

文件led.cpp中的代码

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <QDebug>void led_init(void)
{/** echo 131 > /sys/class/gpio/export* echo out > /sys/class/gpio/gpio131/direction*/int fd;fd = open("/sys/class/gpio/export", O_WRONLY);if (fd < 0){qDebug()<<"open /sys/class/gpio/export err";return ;}write(fd, "131\n", 4);close(fd);fd = open("/sys/class/gpio/gpio131/direction", O_WRONLY);if (fd < 0){qDebug()<<"open /sys/class/gpio/gpio131/direction err";return ;}write(fd, "out\n", 4);close(fd);
}void led_control(int on)
{/** echo 1 > /sys/class/gpio/gpio131/value* echo 0 > /sys/class/gpio/gpio131/value*/static int fd = -1;if (fd == -1){fd = open("/sys/class/gpio/gpio131/value", O_RDWR);}if (fd < 0){qDebug()<<"open /sys/class/gpio/gpio131/value err";return ;}if (on){write(fd, "0\n", 2);}else{write(fd, "1\n", 2);}
}

文件main.cpp中的代码

#include "mainwindow.h"
#include "led.h"
#include <QApplication>int main(int argc, char *argv[])
{/* 1. init LED */led_init();QApplication a(argc, argv);MainWindow w;w.show();return a.exec();
}

文件mainwindow.cpp中的代码

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "led.h"
#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::on_pushButton_clicked()
{static int status = 1;if (status)qDebug()<<"LED clicked on";elseqDebug()<<"LED clicked off";/* 2. control LED */led_control(status);status = !status;
}

书写LED的初始化函数led_init()

在工程中新建一个名为led.cpp的文件:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

然后在其中写出LED的初始化函数led_init()
代码如下:

void led_init(void)
{/** echo 131 > /sys/class/gpio/export* echo out > /sys/class/gpio/gpio131/direction*/int fd;fd = open("/sys/class/gpio/export", O_WRONLY);if (fd < 0){qDebug()<<"open /sys/class/gpio/export err";return ;}write(fd, "131\n", 4);close(fd);fd = open("/sys/class/gpio/gpio131/direction", O_WRONLY);if (fd < 0){qDebug()<<"open /sys/class/gpio/gpio131/direction err";return ;}write(fd, "out\n", 4);close(fd);
}

上面这段代码如果把下面两篇博文:
https://blog.csdn.net/wenhao_ir/article/details/145444452
https://blog.csdn.net/wenhao_ir/article/details/145453877
认真看了一遍,那就很好理解了,所以这里就不再赘述。
如果时间紧的话,那就看:
第1篇博文中的“终端中如何利用GPIO子系统(gpiolib)操作GPIO口”
第2篇博文中的第1个标题中的内容。
不过强烈建议把两篇博文浏览一遍。

另外,关于文件描述符的相关知识,可以参考我的另一篇博文 https://blog.csdn.net/wenhao_ir/article/details/144931005

这里附一张下面这条命令运行结果:
在这里插入图片描述
注意,上面截图中的gpio131是运行了下面这条代码后才有的:

write(fd, "131\n", 4);

具体的过程我在博文 https://blog.csdn.net/wenhao_ir/article/details/145453877 中有描述,打开博文搜索“请求使用 GPIO 131”

书写LED的控制函数led_control()

在文件led.cpp里书写LED的控制函数led_control(),代码如下:

void led_control(int on)
{/** echo 1 > /sys/class/gpio/gpio131/value* echo 0 > /sys/class/gpio/gpio131/value*/static int fd = -1;if (fd == -1){fd = open("/sys/class/gpio/gpio131/value", O_RDWR);}if (fd < 0){qDebug()<<"open /sys/class/gpio/gpio131/value err";return ;}if (on){write(fd, "0\n", 2);}else{write(fd, "1\n", 2);}
}

如果理解了初始化函数led_init()里的代码,那么这段代码也就很简单了,这里就不再赘述了。

这里附一张下面这条命令运行结果:
在这里插入图片描述
注意,上面截图中的gpio131是运行了下面这条代码后才有的:

write(fd, "131\n", 4);

具体的过程我在博文 https://blog.csdn.net/wenhao_ir/article/details/145453877 中有描述,打开博文搜索“请求使用 GPIO 131”

解决led.cpp因缺少头文件而导致的各种报错

上面的函数led_init()led_control()写到文件led.cpp后,会有很多报错:
在这里插入图片描述
这些报错本质上都是因为工程的代码编辑器没有正确设置头文件目录,具体的设置方法见 https://blog.csdn.net/wenhao_ir/article/details/145479279

注意:这些报错只是代码编辑器的报错,并不是编译时的报错,我实测过,不解决这个问题,也能成功编译,因为Makefile中有相关的路径设置。

新建头文件led.h并书写头文件的内容

初始化函数led_init()和控制函数led_control()已经写完了,接下来我们要写个头文件对这两个函数声明,以便其它文件中的代码能引用这两个函数。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
写入led.h的代码如下:

#ifndef LED_H
#define LED_Hvoid led_init(void);
void led_control(int on);#endif // LED_H

在这里插入图片描述

main函数里调用初始化函数led_init()

在这里插入图片描述

类MainWindow的成员函数on_pushButton_clicked里调用控制函数led_control()

代码如下:

void MainWindow::on_pushButton_clicked()
{static int status = 1;if (status)qDebug()<<"LED clicked on";elseqDebug()<<"LED clicked off";/* 2. control LED */led_control(status);status = !status;
}

这段代码很简单,没啥好说的。

值得注意的是哪里与按钮事件联结起来的?这涉及到Qt的信号槽机制,就是下面这些东西:
在这里插入图片描述
上面红框中的东西我已经在博文 https://blog.csdn.net/wenhao_ir/article/details/145420998 中介绍过了,这里就不再赘述了。

编译工程

编译方法

在这里插入图片描述
成功编译,顺利生成ELF可执行文件:test_01
在这里插入图片描述
把生成的这个ELF可执行文件test_01复制到NFS网络文件目录中,备用。

这里要说明下,其实在 led.cpp中,用到了Linux系统的很多用户空间的函数,但是似乎我在配置QtCreator时没有去配置用户空间编译时需要的头文件和库呀,配置QtCreator的博文链接 https://blog.csdn.net/wenhao_ir/article/details/145367198

那是怎么回事呢?其实只要有sysroot位置就能有这些需要的头文件和库,关于sysroot的详细介绍,见 https://blog.csdn.net/wenhao_ir/article/details/145468785
这里QtCreator能根据qmake的位置找到sysroot的位置,所以自然就能编译啦。
我们查看QtCreator工程中的Makefile文件:
在这里插入图片描述
能发现sysroot的路径为:

/home/book/100ask_imx6ull-sdk/Buildroot_2020.02.x/output/host/arm-buildroot-linux-gnueabihf/sysroot

如下图所示:
在这里插入图片描述
所以是能正确构建的。

重要概念:Qt程序是运行于用户空间的

这里要注意:其实Qt工程中的代码都是运行于用户空间的,Qt本身就是在用户空间运行的程序,所以只需要提供sysroot,就能正常编译啦。

上板测试

复制可执行文件到NFS网络文件目录

把之前编译生成个ELF可执行文件test_01复制到NFS网络文件目录中。
在这里插入图片描述
打开串口终端→打开开发板→挂载网络文件系统:

mount -t nfs -o nolock,vers=3 192.168.5.11:/home/book/nfs_rootfs /mnt

关掉开发板上自带的QT的GUI

经实测,如果不关闭开发板自带的QT的GUI,虽然你自己写的Qt界面能加载出来,但是当你用手划动屏幕时,开发板上自带的QT的GUI有可能会弹出来。

参考博文 https://blog.csdn.net/wenhao_ir/article/details/144591685 用一次性有效的方法(即不是永久有效的方法)关掉自带的QT的GUI界面。

这里用一次性的方法,即不是永久有效的方法:
执行下面这条命令:

/etc/init.d/S99myirhmi2 stop

执行完成后再用手去操作屏幕上的UI界面,UI界面就没有任何反应了,说明QT的GUI界面被关掉了

设置Qt环境变量

export QT_QPA_GENERIC_PLUGINS=tslib:/dev/input/event1
export QT_QPA_PLATFORM=linuxfb:fb=/dev/fb0
export QT_QPA_FONTDIR=/usr/lib/fonts/

这三条命令的详细解释见 https://blog.csdn.net/wenhao_ir/article/details/145433648

运行编译生成的Qt程序

注意:运行前请确保Qt运行的环境变量设置好了。
注意:运行前请确保Qt运行的环境变量设置好了。

/mnt/qt_sys_led/test_01

屏幕如下图所示:
在这里插入图片描述
点击LED按钮1次:
终端运行结果如下:
在这里插入图片描述
此时LED2灯是亮着的。

再点LED按钮1次:
终端运行结果如下:
在这里插入图片描述
此是LED2灯灭了。

这样测试就成功了。

附编译完成后完整的工程目录

https://pan.baidu.com/s/1j7DVGZaZj0WtK3J-K2xnsQ?pwd=h5sp
注意:QtCreator的工程换位置后一定要更换一下Build directory的位置,因为在QtCreator中Build directory是一个绝对路径,详情见 https://blog.csdn.net/wenhao_ir/article/details/145458743

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

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

相关文章

Unity 2D实战小游戏开发跳跳鸟 - 记录显示最高分

上一篇文章中我们实现了游戏的开始界面,在开始界面中有一个最高分数的UI,本文将接着实现记录最高分数以及在开始界面中显示最高分数的功能。 添加跳跳鸟死亡事件 要记录最高分,则需要在跳跳鸟死亡时去进行判断当前的分数是否是最高分,如果是最高分则进行记录,如果低于之前…

2025.2.5——五、[网鼎杯 2020 青龙组]AreUSerialz 代码审计|反序列化

题目来源&#xff1a;BUUCTF [网鼎杯 2020 青龙组]AreUSerialz 目录 一、打开靶机&#xff0c;整理信息 二、解题思路 step 1&#xff1a;代码审计 step 2&#xff1a;开始解题 突破protected访问修饰符限制 三、小结 一、打开靶机&#xff0c;整理信息 直接得到一串ph…

芯科科技的BG22L和BG24L带来应用优化的超低功耗蓝牙®连接

全新的BG22L为常见蓝牙设备提供强大的安全性和处理能力&#xff0c;而BG24L支持先进的AI/ML加速和信道探测功能 2025年2月6日 – 致力于以安全、智能无线连接技术&#xff0c;建立更互联世界的全球领导厂商Silicon Labs&#xff08;亦称“芯科科技”&#xff0c;NASDAQ&#x…

iOS 音频录制、播放与格式转换

iOS 音频录制、播放与格式转换:基于 AVFoundation 和 FFmpegKit 的实现 在 iOS 开发中,音频处理是一个非常常见的需求,比如录音、播放音频、音频格式转换等。本文将详细解读一段基于 AVFoundation 和 FFmpegKit 的代码,展示如何实现音频录制、播放以及 PCM 和 AAC 格式之间…

区块链技术:Facebook 重塑社交媒体信任的新篇章

在这个信息爆炸的时代&#xff0c;社交媒体已经成为我们生活中不可或缺的一部分。然而&#xff0c;随着社交平台的快速发展&#xff0c;隐私泄露、数据滥用和虚假信息等问题也日益凸显。这些问题的核心在于传统社交媒体依赖于中心化服务器存储和管理用户数据&#xff0c;这种模…

STM32的HAL库开发---高级定时器---输出比较模式实验

一、高级定时器输出比较模式实验原理 定时器的输出比较模式总共有8种&#xff0c;本文使用其中的翻转模式&#xff0c;当TIMXCCR1TIMXCNT时&#xff0c;翻转OC1REF的电平&#xff0c;OC1REF为输出参考信号&#xff0c;高电平有效&#xff0c;OC1REF信号连接到0C1上面&#xff…

Games104——游戏引擎Gameplay玩法系统:基础AI

这里写目录标题 寻路/导航系统NavigationWalkable AreaWaypoint NetworkGridNavigation Mesh&#xff08;寻路网格&#xff09;Sparse Voxel Octree Path FindingDijkstra Algorithm迪杰斯特拉算法A Star&#xff08;A*算法&#xff09; Path Smoothing Steering系统Crowd Simu…

Nginx进阶篇 - nginx多进程架构详解

文章目录 1. nginx的应用特点2. nginx多进程架构2.1 nginx多进程模型2.2 master进程的作用2.3 进程控制2.4 worker进程的作用2.5 worker进程处理请求的过程2.6 nginx处理网络事件 1. nginx的应用特点 Nginx是互联网企业使用最为广泛的轻量级高性能Web服务器&#xff0c;其特点是…

grafana面板配置opentsdb

新增面板&#xff1a; 这里add-panel: 如果不是想新增面板而是想新增一行条目&#xff0c;则点击convert to row: 在新增的面板这里可以看到选择数据源 Aggregator&#xff1a;聚合条件&#xff0c;区分下第一行和第二行的aggregator&#xff0c;第一个是对指标值的聚合&…

记一次golang环境的变化

前两天编译打包了了个文件&#xff0c;把env的 goos 搞坏了 导致运行项目一直报错 先是这样 go: unsupported GOOS/GOARCH pair windows/amd64再是这样 /amd64supported GOOS/GOARCH pair linux咱就说&#xff0c;咱也是知道环境配置的有问题 &#xff08; go env GOOS &…

ARM嵌入式学习--第十三天(I2C)

I2C --介绍 I2C&#xff08;Inter-intergrated Circuit 集成电路&#xff09;总线是Philips公司在八十年代初推出的一种串行、半双工的总线&#xff0c;主要用于近距离、低速的芯片之间的通信&#xff1b;I2C总线有俩根双向的信号线&#xff0c;一根数据线SDA用于收发数据&…

(10) 如何获取 linux 系统上的 TCP 、 UDP 套接字的收发缓存的默认大小,以及代码范例

&#xff08;1&#xff09; 先介绍下后面的代码里要用到的基础函数&#xff1a; 以及&#xff1a; &#xff08;2&#xff09; 接着给出现代版的 读写 socket 参数的系统函数 &#xff1a; 以及&#xff1a; &#xff08;3&#xff09; 给出 一言的 范例代码&#xff0c;获取…

kafka消费端之消费者协调器和组协调器

文章目录 概述回顾历史老版本获取消费者变更老版本存在的问题 消费者协调器和组协调器新版如何解决老版本问题再均衡过程**第一阶段CFIND COORDINATOR****第二阶段&#xff08;JOINGROUP&#xff09;**选举消费组的lcader选举分区分配策略 第三阶段&#xff08;SYNC GROUP&…

Redis --- 使用Feed流实现社交平台的新闻流

要实现一个 Feed 流&#xff08;类似于社交媒体中的新闻流&#xff09;&#xff0c;通常涉及以下几个要素&#xff1a; 内容发布&#xff1a;用户发布内容&#xff08;例如文章、状态更新、图片等&#xff09;。内容订阅&#xff1a;用户可以订阅其他用户的内容&#xff0c;获…

6 maven工具的使用、maven项目中使用日志

文章目录 前言一、maven&#xff1a;一款管理和构建java项目的工具1 基本概念2 maven的安装与配置&#xff08;1&#xff09;maven的安装&#xff08;2&#xff09;IDEA集成Maven配置当前项目工程设置 maven全局设置 &#xff08;3&#xff09;创建一个maven项目 3 pom.xml文件…

Visual Studio(VS)没有显示垂直滚轮or垂直滚轮异常显示

前言&#xff1a; 前段时间&#xff0c;我换上了新电脑。满心欢喜地安装好 VS&#xff0c;准备大干一场时&#xff0c;却发现了一个小麻烦 —— 垂直滚轮显示异常&#xff08;如图 1&#xff09;。这种显示方式实在让我难以适应&#xff0c;每一次操作都觉得别扭。 于是&#…

Fiddler Classic(HTTP流量代理+半汉化)

目录 一、关于Fiddler (一) Fiddler Classic (二) Fiddler Everywhere (三) Fiddler Everywhere Reporter (四) FiddlerCore (五) 总结 二、 软件安全性 1. 软件安装包 2. 软件汉化dll 三、安装与半汉化 1. 正常打开安装包点击下一步安装即可&#xff0c;安装路径自…

时序数据库:Influxdb详解

文章目录 一、简介1、简介2、官网 二、部署1、安装2、配置&#xff08;1&#xff09;用户初始化 三、入门&#xff08;Web UI&#xff09;1、加载数据&#xff08;1&#xff09;上传数据文件&#xff08;2&#xff09;代码接入模板 2、管理存储桶&#xff08;1&#xff09;创建…

android 适配 api 35(android 15) 遇到的问题

首先升级 targetSdkVersion 和 compileSdkVersion 到 35&#xff0c;升级后发生的报错 一、 解决方案: 升级 gradle 和 gradle 插件版本 com.android.tools.build:gradle -> 8.3.0-alpha02 gradle-wrapper.properties : distributionUrl -> gradle-8.6-bin.zip htt…

【万字详细教程】Linux to go——装在移动硬盘里的Linux系统(Ubuntu22.04)制作流程;一口气解决系统安装引导文件迁移显卡驱动安装等问题

Linux to go制作流程 0.写在前面 关于教程Why Linux to go&#xff1f;实际效果 1.准备工具2.制作步骤 下载系统镜像硬盘分区准备启动U盘安装系统重启完成驱动安装将系统启动引导程序迁移到移动硬盘上 3.可能出现的问题 3.1.U盘引导系统安装时出现崩溃3.2.不影响硬盘里本身已有…