Linux学习笔记(应用篇三)

基于I.MX6ULL-MINI开发板

  • LED学习
  • GPIO应用编程
  • 输入设备

开发板中所有的设备(对象)都会在/sys/devices 体现出来,是 sysfs 文件系统中最重要的目录结构

/sys下的子目录说明
/sys/devices这是系统中所有设备存放的目录,也就是系统中的所有设备在 sysfs 中的呈现、表达,也是 sysfs 管理设备的最重要的目录结构。
/sys/block块设备的存放目录,这是一个过时的接口,按照 sysfs 的设计理念,系统所有的设备都存放在/sys/devices 目录下,所以/sys/block 目录下的文件通常是链接到/sys/devices 目录下的文件。
/sys/bus这是系统中的所有设备按照总线类型分类放置的目录结构,/sys/devices 目录下每一种设备都是挂在某种总线下的,譬如 i2c 设备挂在 I2C 总线下。同样,/sys/bus 目录下的文件通常也是链接到了/sys/devices 目录。
/sys/class这是系统中的所有设备按照其功能分类放置的目录结构,同样该目录下的文件也是链接到了/sys/devices 目录。按照设备的功能划分组织在/sys/class 目录下,譬如/sys/class/leds目录中存放了所有的 LED 设备,/sys/class/input 目录中存放了所有的输入类设备。
/sys/dev这是按照设备号的方式放置的目录结构,同样该目录下的文件也是链接到了/sys/devices 目录。该目录下有很多以主设备号:次设备号(major:minor)命名的文件,这些文件都是链接文件,链接到/sys/devices 目录下对应的设备。
/sys/firmware描述了内核中的固件。
/sys/fs用于描述系统中所有文件系统,包括文件系统本身和按文件系统分类存放的已挂载点。
/sys/kernel这里是内核中所有可调参数的位置。
/sys/module这里有系统中所有模块的信息。
/sys/power这里是系统中电源选项,有一些属性可以用于控制整个系统的电源状态。

应用层想要对底层硬件进行操控,通常可以通过两种方式

  1. /dev/目录下的设备文件(设备节点);
  2. /sys/目录下设备的属性文件。

LED学习

led设备路径

/sys/class/leds/sys-led

在这里插入图片描述

brightness:LED亮度,可读可写,0亮,非0灭
max_brightness:LED最大亮度,只读
trigger:触发模式,可读可写,模式如下:
none(无触发)、mmc0(当对 mmc0 设备发起读写操作的时候 LED 会闪烁)、timer(LED 会有规律的一亮一灭,被定时器控制住)、heartbeat(心跳呼吸模式,LED 模仿人的心跳呼吸那样亮灭变化)。

代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>#define LED_TRIGGER "/sys/class/leds/sys-led/trigger"
#define LED_BRIGHTNESS "/sys/class/leds/sys-led/brightness"
/*
在 C 语言中,反斜杠 \ 的作用是 行连接符(line continuation character)。
它允许你在多个行中编写一条连续的语句,而不需要写成一行。
具体来说,反斜杠告诉编译器:下一行是当前行的延续,继续合并在一起,而不加上额外的换行符。
*/
#define USAGE()     fprintf(stderr,"usage:\n" \"    %s<on|off>\n"   \"    %s<trigger><type>\n",argv[0],argv[0])  //argv[0]存放程序的名称或路径int main(int argc, char *argv[])//argc参数个数,argv[]参数
{int fd1, fd2;//校验传参if(2>argc){USAGE();return 1;}// 打开sysfs中的trigger和brightness文件fd1 = open(LED_TRIGGER, O_RDWR);if (0 > fd1) {perror("open LED_TRIGGER error");return 1;}fd2 = open(LED_BRIGHTNESS, O_RDWR);if (0 > fd2) {perror("open LED_BRIGHTNESS error");close(fd1);return 1;}//根据传参控制LEDif(!strcmp(argv[1],"on")){//判断传入的第一个参数是否是onwrite(fd1,"none",4);//往trigger写入none,共4个字节,trigger设置为无触发write(fd2,"1",1);//点亮LED}else if(!strcmp(argv[1],"off")){//判断传入的第一个参数是否是offwrite(fd1,"none",4);write(fd2,"0",1);//熄灭LED}else if(!strcmp(argv[1],"trigger")){//如果传入的第一个参数是trigger但是参数个数不是三个,提示用法if(3!=argc){USAGE();return 1;}if(0 > write(fd1,argv[2],strlen(argv[2]))){//判断写入是否正确,将第三个参数即触发模式传给fd1 (none、mmc0、timer、heartbeat)perror("write error");return 1;}}elseUSAGE();return 0;
}

在这里插入图片描述

GPIO应用编程

GPIO目录

/sys/class/gpio

一共包含了 5 个 GPIO控制器,分别为 GPIO1、GPIO2、GPIO3、GPIO4、GPIO5,在这里分别对应 gpiochip0、gpiochip32、gpiochip64、gpiochip96、gpiochip128 这 5 个文件夹,每一个 gpiochipX 文件夹用来管理一组 GPIO

在这里插入图片描述
每一个gpiochipX文件夹里面有以下内容

在这里插入图片描述

base:与 gpiochipX 中的 X 相同,表示该控制器所管理的这组 GPIO 引脚中最小的编号,如gpiochip32的base就是32
label:该组 GPIO 对应的标签,也就是名字
ngpio:该控制器所管理的 GPIO 引脚的数量,引脚编号范围是:base ~ base+ngpio-1

GPIO5_IO10在sysfs中对应的编号:128+10=138

export

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

如下图,这个文件夹就是导出来的 GPIO 引脚对应的文件夹,用于管理、控制该 GPIO 引脚

在这里插入图片描述

unexport

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

在这里插入图片描述

gpioX文件夹里的文件
在这里插入图片描述

direction:配置 GPIO 引脚为输入或输出模式。该文件可读、可写,读表示查看 GPIO 当前是输入还是输出模式,写表示将 GPIO 配置为输入或输出模式;读取或写入操作可取的值为"out"(输出模式)和"in"(输入模式)
在这里插入图片描述
value:在 GPIO 配置为输出模式下,向 value 文件写入"0"控制 GPIO 引脚输出低电平,写入"1"则控制 GPIO 引脚输出高电平。在输入模式下,读取 value 文件获取 GPIO 引脚当前的输入电平状态。
active_low:这个属性文件用于控制极性,可读可写,默认情况下为 0,如果设置为1,则逻辑1为低电平,逻辑0为高电平
edge:控制中断的触发模式,该文件可读可写。在配置 GPIO 引脚的中断触发模式之前,需将其设置为输入模式
非中断引脚echo "none" > edge
上升沿触发echo "rising" > edge
下降沿触发echo "falling" > edge
边沿触发 echo "both" > edge

输出代码

#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>static char gpio_path[100];//存放gpio设备文件路径//修改GPIO的状态
static int gpio_config(const char *attr, const char *value)//attr:修改的选项(direction、active_value、value)value:传入的值
{char file_path[100];int fd;int len;sprintf(file_path, "%s/%s", gpio_path, attr);//将/sys/class/gpio/gpiox/(direction或active_value或value)传给file_pathif(0 > (fd = open(file_path,O_WRONLY))){perror("open error");return fd;}len = strlen(value);if(len!= write(fd,value,len))//向file_path写入value,即修改gpio的状态{perror("write error");close(fd);return 1;}close(fd);return 0;
}int main(int argc, char *argv[])
{//判断传参是否正确if(3!=argc){fprintf(stderr,"usage: %s<gpio><value>\n", argv[0]);return 1;}//判断gpiox文件是否导出sprintf(gpio_path,"/sys/class/gpio/gpio%s",argv[1]);if(access(gpio_path,F_OK))//判断路径是否存在,不存在则创建,F_OK参数用于判断文件是否存在{int fd;int len;if(0 > (fd = open("/sys/class/gpio/export",O_WRONLY)))//打开export文件并将路径存放在fd,准备写入{perror("open error");return 1;}len = strlen(argv[1]);if(len != write(fd,argv[1],len))//向export写入gpio号,即导出gpio文件{perror("write error");close(fd);return 1;}close(fd);//关闭文件}//修改gpio的状态if(gpio_config("direction","out"))//配置为输出模式{return 1;}if(gpio_config("active_low","0"))//默认极性{return 1;}if(gpio_config("value",argv[2]))//控制GPIO高低电平{return 1;}//退出程序return 0;}

中断输入代码

#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <poll.h>static char gpio_path[100];//存放gpio设备文件路径//修改GPIO的状态
static int gpio_config(const char *attr, const char *value)//attr:修改的选项(direction、active_low、value)value:传入的值
{char file_path[100];int fd;int len;sprintf(file_path, "%s/%s", gpio_path, attr);//将/sys/class/gpio/gpiox/(direction或active_low或value)传给file_pathif(0 > (fd = open(file_path,O_WRONLY))){perror("open error");return fd;}len = strlen(value);if(len!= write(fd,value,len))//向file_path写入value,即修改gpio的状态{perror("write error");close(fd);return 1;}close(fd);return 0;
}int main(int argc, char *argv[])
{struct pollfd pfd;//用于poll调用来监视文件描述符的事件,记得包含头文件poll.hchar file_path[100];//存储/sys/class/gpio/gpiox/value的路径int ret;            //poll函数的返回值char value;         //从GPIO引脚读取的值//判断传参是否正确if(2!=argc){fprintf(stderr,"usage: %s<gpio> <value>\n", argv[0]);return 1;}//判断gpiox文件是否导出sprintf(gpio_path,"/sys/class/gpio/gpio%s",argv[1]);if(access(gpio_path,F_OK))//判断路径是否存在,不存在则创建,F_OK参数用于判断文件是否存在{int fd;int len;if(0 > (fd = open("/sys/class/gpio/export",O_WRONLY)))//打开export文件并将路径存放在fd,准备写入{perror("open error");return 1;}len = strlen(argv[1]);if(len != write(fd,argv[1],len))//向export写入gpio号,即导出gpio文件{perror("write error");return 1;}close(fd);//关闭文件}//修改gpio的状态if(gpio_config("direction","in"))//配置为输入模式{return 1;}if(gpio_config("active_low","0"))//默认极性{return 1;}if(gpio_config("edge","both"))//设置中断触发方式,both是边沿触发{return 1;}//打开value属性文件sprintf(file_path,"%s/%s",gpio_path,"value");if(0 > (pfd.fd = open(file_path,O_RDONLY)))//用pfd.fd存储vlaue的文件路径{perror("open error");return 1;}/*调用pollstruct pollfd{int fd;         //文件描述符short events;   //等待的事件short revents;  //返回的事件}*/pfd.events = POLLPRI;//只关心高优先级数据可读(中断)read(pfd.fd,&value, 1);//在进入循环之前,先读取一次GPIO状态,以清除先前的状态for( ; ; ){ret = poll(&pfd,1,-1);//调用poll,阻塞直到事件发生if(0 > ret){perror("poll error");return 1;}else if(0 == ret){fprintf(stderr,"poll timeout.\n");continue;}//校验高优先级数据是否可读if(pfd.revents & POLLPRI){if(0 > lseek(pfd.fd,0,SEEK_SET))//使用lseek重置文件指针,确保每次读取最新的GPIO状态{perror("lseek error");return 1;}if(0 > read(pfd.fd,&value,1)){perror("read error");return 1;}printf("gpio中断触发<value=%c\n",value);}}//退出程序return 0;
}

poll函数复习

int poll(struct pollfd *fds, nfds_t nfds, int timeout);
/*
fds:指向一个 struct pollfd 类型的数组,储存关心的文件描述符
nfds:fds数组中元素的个数
timeout:决定poll函数的阻塞行为-1:一直阻塞,直到有信号来0:不阻塞>0:阻塞时间上限
*///struct pollfd 结构体
struct pollfd {int fd;        /* 文件描述符 */short events;  /* 等待的事件 */short revents; /* 返回的事件 */
};

在这里插入图片描述

输入设备

读取输入设备时,应用程序打开输入设备对应的设备文件,向其发起读操作,每一次 read 操作获取的都是一个 structinput_event 结构体类型数据,该结构体定义在<linux/input.h>头文件中

struct input_event {struct timeval time;__u16 type;		//描述发生了哪一种类型的时间__u16 code;		//该类事件具体是哪个事件,如键盘上不同的按键1、2、3...__s32 value;		
/*
内核每次上报事件都会向应用层发送一个数据 value,对 value 值的解释随着 code 的变化而变化。譬如对于按键事件(type=1)来说,如果 code=2(键盘上的数字键 1,也就是 KEY_1),那么如果 value 等于 1,则表示 KEY_1 键按下;value 等于 0 表示 KEY_1 键松开,如果 value 等于 2则表示 KEY_1 键长按。再比如,在绝对位移事件中(type=3),如果 code=0(触摸点 X 坐标 ABS_X),那么 value 值就等于触摸点的 X 轴坐标值;同理,如果 code=1(触摸点 Y 坐标 ABS_Y),此时value 值便等于触摸点的 Y 轴坐标值;所以对 value 值的解释需要根据不同的 code 值而定
*/
};

type
在这里插入图片描述

code
Key

在这里插入图片描述

相对位移

在这里插入图片描述

绝对位移

在这里插入图片描述

通过数据同步使得应用程序得知本轮已经读取到完整的数据同步类事件有如下,所有的输入设备都需要上报同步事件,上报的同步事件通常是SYN_REPORT,而 value 值通常为 0
在这里插入图片描述

查看输入设备是哪个设备节点

cat /proc/bus/input/devices

在这里插入图片描述

输入设备代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>int main(int argc, char *argv[])
{struct input_event in_ev = {0};int fd = -1;int value = -1;//校验传参if(2 != argc){fprintf(stderr, "Usage: %s <input_dev>\n", argv[0]);return 1;}// 打开输入事件文件if(0 > (fd = open(argv[1], O_RDONLY))){perror("open error");return 1;}for( ; ; ){// 读取输入事件if(sizeof(struct input_event) != (read(fd, &in_ev, sizeof(struct input_event)))){perror("read error");break;}// 按键输入的类型if(EV_KEY == in_ev.type){switch (in_ev.value){case 0:printf("code<%d>:松开\n", in_ev.code);break;case 1:printf("code<%d>:按下\n", in_ev.code);break;  case 2:printf("code<%d>:长按\n", in_ev.code);break;                       }}}
}

开发板KEY0按键测试

在这里插入图片描述
键盘测试

接入键盘,我使用的是2.4G连接方式
在这里插入图片描述

查看设备时发现有两个

在这里插入图片描述

event3是键盘上的按键

在这里插入图片描述

event4是键盘上的旋钮
由此可知这两个东西不是同一个设备

在这里插入图片描述

鼠标测试

在这里插入图片描述
在这里插入图片描述

只能读取鼠标的左、右和滚轮的按下和松开

在这里插入图片描述

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

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

相关文章

【图论】网络流算法入门

&#xff08;决定狠狠加训图论了&#xff0c;从一直想学但没启动的网络流算法开始。&#xff09; 网络流问题 • 问题定义&#xff1a;在带权有向图 G ( V , E ) G(V, E) G(V,E) 中&#xff0c;每条边 e ( u , v ) e(u, v) e(u,v) 有容量 c ( u , v ) c(u, v) c(u,v)&am…

递归、搜索与回溯第四讲:floodfill算法

递归、搜索与回溯第四讲&#xff1a;floodfill算法 1.Floodfill算法介绍2.图像渲染3.岛屿数量4.岛屿的最大面积5.被围绕的区域6.太平洋大西洋水流问题7.扫雷游戏8.衣橱整理 1.Floodfill算法介绍 2.图像渲染 3.岛屿数量 4.岛屿的最大面积 5.被围绕的区域 6.太平洋大西洋水流问题…

【深度学习与实战】2.3、线性回归模型与梯度下降法先导案例--最小二乘法(向量形式求解)

为了求解损失函数 对 的导数&#xff0c;并利用最小二乘法向量形式求解 的值‌ 这是‌线性回归‌的平方误差损失函数&#xff0c;目标是最小化预测值 与真实值 之间的差距。 ‌损失函数‌&#xff1a; 考虑多个样本的情况&#xff0c;损失函数为所有样本的平方误差之和&a…

气象可视化卫星云图的方式:方法与架构详解

气象卫星云图是气象预报和气候研究的重要数据来源。通过可视化技术,我们可以将卫星云图数据转化为直观的图像或动画,帮助用户更好地理解气象变化。本文将详细介绍卫星云图可视化的方法、架构和代码实现。 一、卫星云图可视化方法 1. 数据获取与预处理 卫星云图数据通常来源…

浏览器渲染原理与优化详解

一、浏览器渲染基础原理 浏览器渲染流程主要包括以下步骤&#xff08;也称为"关键渲染路径"&#xff09;&#xff1a; 构建DOM树&#xff1a;将HTML解析为DOM&#xff08;文档对象模型&#xff09;树构建CSSOM树&#xff1a;将CSS解析为CSSOM&#xff08;CSS对象模…

基于Spring Boot的成绩管理系统后台实现

下面是一个完整的成绩管理系统后台实现&#xff0c;使用Spring Boot框架&#xff0c;包含学生管理、课程管理和成绩管理功能。 1. 项目结构 src/main/java/com/example/grademanagement/ ├── config/ # 配置类 ├── controller/ # 控制器 ├── dto/ …

实现极限网关(INFINI Gateway)配置动态加载

还在停机更新 Gateway 配置&#xff0c;OUT 了。 今天和大家分享一个 Gateway 的功能&#xff1a;动态加载配置&#xff08;也称热更新或热加载&#xff09;。 这个功能可以在 Gateway 不停机的情况下更新配置并使之生效。 配置样例如下&#xff1a; path.data: data path.…

Mean Shift 图像分割与 Canny 边缘检测教程

1. Mean Shift 简介 Mean Shift 是一种聚类算法&#xff0c;通过寻找图像中颜色相似的区域来实现分割。它非常适合用于场景分割或物体检测等任务。本教程将它与 Canny 边缘检测结合&#xff0c;突出分割区域的边界。 2. 图像分割流程 我们将按照以下步骤完成图像分割和边缘检…

Day15 -实例 端口扫描工具 WAF识别工具的使用

一、端口扫描工具 1、zenmap 我这里user是汉字名&#xff0c;没有解析成功。等后续换一个英文账户试一试。 魔改kali的nmap nmap -p8000-9000 8.140.159.19 2、masscan cmd启动&#xff0c;拖入exe文件。然后先写ip&#xff0c;会报错给提示 寻路犬系统 我们去找一下他的…

如何解决高并发场景下的性能瓶颈?实践分享

解决高并发性能瓶颈的核心方法包括优化系统架构、合理使用缓存技术、数据库优化及扩展策略、负载均衡设计。 其中&#xff0c;优化系统架构是根本解决性能问题的关键所在。良好的系统架构能够有效支撑业务高效稳定运行&#xff0c;避免性能瓶颈带来的损失。企业可通过微服务架构…

自动驾驶背后的数学:ReLU,Sigmoid, Leaky ReLU, PReLU,Swish等激活函数解析

随着自动驾驶技术的飞速发展&#xff0c;深度学习在其中扮演着至关重要的角色。而激活函数作为神经网络中的关键组件&#xff0c;直接影响着模型的性能和效果。前面几篇博客 自动驾驶背后的数学&#xff1a;特征提取中的线性变换与非线性激活 , 「自动驾驶背后的数学&#xff1…

性能测试、负载测试、压力测试的全面解析

在软件测试领域&#xff0c;性能测试、负载测试和压力测试是评估系统稳定性和可靠性的关键手段。​它们各自关注不同的测试目标和应用场景&#xff0c;理解这些差异对于制定有效的测试策略至关重要。 本文对性能测试、负载测试和压力测试进行深入分析&#xff0c;探讨其定义、…

责任链模式-java

1、spring依赖注入模式 @Configuration public class ChainConfig {@Beanpublic ChainSpringFactory chainSpringFactory(List<IHandler<DemoOne,Boolean>> handlerList){return new ChainSpringFactory(handlerList);}} public class DemoOne { }public abstract…

学习本地部署DeepSeek的过程(基于LM Studio)

除了使用Ollama部署DeepSeek&#xff0c;还可以使用LM Studio部署DeepSeek&#xff0c;后者是一款允许用户在本地计算机上运行大型语言模型&#xff08;LLMs&#xff09;的桌面应用程序&#xff0c;旨在简化本地模型的使用&#xff0c;无需云端连接或复杂配置即可体验 AI 功能。…

CSS 尺寸 (Dimension)

CSS 尺寸 (Dimension) 在网页设计中&#xff0c;CSS&#xff08;层叠样式表&#xff09;的尺寸属性是控制元素大小和位置的关键。本文将详细介绍CSS尺寸相关的概念、属性及其应用。 1. CSS 尺寸概述 CSS尺寸主要包括宽度和高度&#xff0c;这些属性可以应用于各种HTML元素&a…

【自学笔记】ELK基础知识点总览-持续更新

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 ELK基础知识点总览1. ELK简介2. Elasticsearch基础Elasticsearch配置示例&#xff08;elasticsearch.yml&#xff09; 3. Logstash基础Logstash配置示例&#xff08…

等差数列公式推导

前言&#xff1a; 通过实践而发现真理&#xff0c;又通过实践而证实真理和发展真理。从感性认识而能动地发展到理性认识&#xff0c;又从理性认识而能动地指导革命实践&#xff0c;改造主观世界和客观世界。实践、认识、再实践、再认识&#xff0c;这种形式&#xff0c;循环往…

【MySQL】用户账户、角色、口令、PAM

目录 查看用户账户设置 连接 1.本地连接 2.远程连接 账户 角色 操作用户账户和角色 配置口令和账户有效期限 手工使口令过期 配置口令有效期限 PAM身份验证插件 客户端连接&#xff1a;使用 PAM 账户登录 在连接到MySQL服务器并执行查询时&#xff0c;会验证你的身…

5种生成模型(VAE、GAN、AR、Flow 和 Diffusion)的对比梳理 + 易懂讲解 + 代码实现

目录 1 变分自编码器&#xff08;VAE&#xff09;​ 1.1 概念 1.2 训练损失 1.3 VAE 的实现 2 生成对抗网络&#xff08;GAN&#xff09;​ 2.1 概念 2.2 训练损失 a. 判别器的损失函数 b. 生成器的损失函数 c. 对抗训练的动态过程 2.3 GAN 的实现 3 自回归模型&am…

印刷电路板 (PCB) 的影响何时重要?在模拟环境中导航

我和我的同事们经常被问到关于 PCB 效应的相同问题&#xff0c;例如&#xff1a; 仿真何时需要 PCB 效果&#xff1f; 为什么时域仿真需要 PCB 效应&#xff1f; 当 PCB 效应必须包含在仿真中时&#xff0c;频率是否重要&#xff1f; 设计人员应该在多大程度上关注 VRM 模型中包…