第二个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

完整源代码

文件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.mzph.cn/diannao/69190.shtml

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

相关文章

登山第十七梯:矩形拟合——无惧噪声

文章目录 一 摘要 二 资源 三 内容 (文章末尾提供源代码) 一 摘要 目前,获取点集的矩形拟合结果的主要方法是计算其最小外包直立矩形或者旋转矩形。这些方法简单、易用,在数据质量良好的情况下能够较好的贴合矩形形状。然而,在数据缺失时,最小外包围盒方法将会…

57. Uboot图形化界面配置

一、Uboot图形化配置方法 1、通过终端配置。 2、进入到uboot的源码根目录下。 3、首先默认配置 make mx6ull_alientek_emmc_defconfig //默认配置 4、输入make menuconfig。打开图形化配置界面。 5、注意&#xff0c;新电脑需要安装ncurses库。sudo apt-get install libncurs…

kalman滤波器C++设计仿真实例第三篇

1. 仿真场景 水面上有条船在做匀速直线航行&#xff0c;航行过程中由于风和浪的影响&#xff0c;会有些随机的干扰&#xff0c;也就是会有些随机的加速度作用在船身上&#xff0c;这个随机加速度的均方差大约是0.1&#xff0c;也就是说方差是0.01。船上搭载GPS设备&#xff0c;…

(2025|ICLR,音频 LLM,蒸馏/ALLD,跨模态学习,语音质量评估,MOS)音频 LLM 可作为描述性语音质量评估器

Audio Large Language Models Can Be Descriptive Speech Quality Evaluators 目录 1. 概述 2. 研究背景与动机 3. 方法 3.1 语音质量评估数据集 3.2 ALLD 对齐策略 4. 实验结果分析 4.1 MOS 评分预测&#xff08;数值评估&#xff09; 4.2 迁移能力&#xff08;在不同…

stm32生成hex文件详解

1.产生的map文件干啥的&#xff1f; 2.组成情况&#xff1f;&#xff1f;&#xff1f; 废话少说&#xff0c;直接上代码具体内容况&#xff1a; Component: ARM Compiler 5.06 update 7 (build 960) Tool: armlink [4d3601]Section Cross Referencesstartup_stm32f103xe.o(S…

百度热力图数据获取,原理,处理及论文应用6

目录 0、数据简介0、示例数据1、百度热力图数据日期如何选择1.1、其他实验数据的时间1.2、看日历1.3、看天气 2、百度热力图几天够研究&#xff1f;部分文章统计3、数据原理3.1.1 ** 这个比较重要&#xff0c;后面还会再次出现。核密度的值怎么理解&#xff1f;**3.1.2 Csv->…

[转]Java面试近一个月的面试总结

本文是在学习中的总结&#xff0c;欢迎转载但请注明出处&#xff1a;http://blog.csdn.net/pistolove/article/details/46753275 前言 打算换个工作&#xff0c;近一个月面试了不少的公司&#xff0c;下面将一些面试经验和思考分享给大家。另外校招也快要开始了&#xff0c;为…

学习threejs,tga格式图片文件贴图

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️TGA图片1.2 ☘️THREE.Mesh…

MSPFN 代码复现

1、环境配置 conda create -n MSPFN python3.9 conda activate MSPFN pip install opencv-python pip install tensorflow pip install tqdm pip install matplotlib2、train 2.1 创建数据集 2.1.1 数据集格式 |--rainysamples |--file1&#xff1a; |--file2:|--fi…

20240206 adb 连不上手机解决办法

Step 1: lsusb 确认电脑 usb 端口能识别设备 lsusb不知道设备有没有连上&#xff0c;就插拔一下&#xff0c;对比观察多了/少了哪个设备。 Step 2: 重启 adb server sudo adb kill-serversudo adb start-serveradb devices基本上就可以了&#xff5e; Reference https://b…

《利用原始数据进行深度神经网络闭环 用于光学驻留空间物体检测》论文精读

Deep Neural Network Closed-loop with Raw Data for Optical Resident Space Object Detection 摘要 光学勘测是观测驻留空间物体和空间态势感知的重要手段。随着天文技术和还原方法的应用&#xff0c;宽视场望远镜在发现和识别驻留空间物体方面做出了重大贡献。然而&#x…

2025年前端面试准备html篇

1.对html 语义化标签的理解 html语义化标签简单来说页面有良好的结构&#xff0c;使元素有含义便于理解。 优点可以使页面呈现出清晰的机构&#xff0c;有利于seo和搜索引擎抓取信息&#xff0c;便于团队的开发和管理。 常见的语义化标签有&#xff1a; <header> - 定义页…

【字节青训营-9】:初探字节微服务框架 Hertz 基础使用及进阶(下)

本文目录 一、Hertz中间件Recovery二、Hertz中间件跨资源共享三、Hertz 响应四、Hertz请求五、Hertz中间件Session 一、Hertz中间件Recovery Recovery中间件是Hertz框架预置的中间件&#xff0c;使用server.Default()可以默认注册该中间件&#xff0c;为Hertz框架提供panic回复…

因果推断与机器学习—用机器学习解决因果推断问题

Judea Pearl 将当前备受瞩目的机器学习研究戏谑地称为“仅限于曲线拟合”,然而,曲线拟合的实现绝非易事。机器学习模型在图像识别、语音识别、自然语言处理、蛋白质分子结构预测以及搜索推荐等多个领域均展现出显著的应用效果。 在因果推断任务中,在完成因果效应识别之后,需…

软件设计模式

目录 一.创建型模式 抽象工厂 Abstract Factory 构建器 Builder 工厂方法 Factory Method 原型 Prototype 单例模式 Singleton 二.结构型模式 适配器模式 Adapter 桥接模式 Bridge 组合模式 Composite 装饰者模式 Decorator 外观模式 Facade 享元模式 Flyw…

Linux 零拷贝技术

一、传统做法&#xff0c;经历“四次拷贝” 数据 1.读取到内核缓冲区 2.拷贝到用户缓冲区 3.写入到内核缓冲区 4.拷贝到网卡 使用 DMA&#xff0c;减少2次拷贝&#xff0c;还剩2次拷贝 DMA 负责硬盘到内核缓冲区和内核到网卡的传输。 CPU 仍需处理内核和用户缓冲区之间的数据…

【通俗易懂说模型】线性回归(附深度学习、机器学习发展史)

&#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#xff1a; &#x1f3c0;深度学习_十二月的猫的博客-CSDN博客 &#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 目录 1. 前言 2. …

利用Vue和javascript分别编写一个“Hello World”的定时更新

目录 一、利用Vue编写一个“Hello World”的定时更新&#xff08;1&#xff09;vue编码在Html文件中&#xff08;2&#xff09;vue编码在js文件中 二、利用javascript编写一个“Hello World”的定时更新 一、利用Vue编写一个“Hello World”的定时更新 &#xff08;1&#xff…

蓝桥杯python基础算法(2-1)——排序

目录 一、排序 二、例题 P3225——宝藏排序Ⅰ 三、各种排序比较 四、例题 P3226——宝藏排序Ⅱ 一、排序 &#xff08;一&#xff09;冒泡排序 基本思想&#xff1a;比较相邻的元素&#xff0c;如果顺序错误就把它们交换过来。 &#xff08;二&#xff09;选择排序 基本思想…

洛谷 P4552 [Poetize6] IncDec Sequence C语言

P4552 [Poetize6] IncDec Sequence - 洛谷 | 计算机科学教育新生态 题目描述 给定一个长度为 n 的数列 a1​,a2​,…,an​&#xff0c;每次可以选择一个区间 [l,r]&#xff0c;使这个区间内的数都加 1 或者都减 1。 请问至少需要多少次操作才能使数列中的所有数都一样&#…