news 2026/2/2 10:38:45

基于wiringPi库写的一些代码(二)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于wiringPi库写的一些代码(二)

1. linux的热拔插udev机制

1.1 热拔插:在开机和运行的状态下,可以安全地安装或者转移硬件,不需要关闭电源或者重启。

1.2 udev

udev是一个设备管理工具,udev以守护进程的形式运行,通过侦听内核发出来的event(事件)来管理/dev目录下的设备文件。udev在用户空间运行,而不在内核空间 运行。它能够根据系统中的硬件设备的状态,动态更新设备文件包括设备文件的创建,删除等。设备文件通常放在/dev目录下。使用udev后,在/dev目录下就只包含系统中真正存在的设备。

1.3 例子

例如,在上述的实验中:

手机刚刚插进去开发板之后,应用程序是不能使用手机的(因为adb(应用层)找不到对应usb设备文件(应用层是没有权限使用这个设备文件)),例如执行adb会不成功。

一开始,当有usb设备(手机)接入开发板的时候,是内核先知道usb设备的(这里把设备接入开发板,仅仅只是实现了让内核知道而已,可以使用dmesg可以知道设备的信息,但是在应用层是不认识这个设备的,应用层是没法访问到设备的(没权限),怎样才能认识这个设备并为这个设备创建文件 --> udev机制)。

但是在应用层(应用程序adb)是没法访问到usb设备的,虽然此时在dev目录下还有对应的usb设备文件(找不到对应的手机设备文件),但是在应用层就没法访问到usb设备的(没权限)。怎样可以让应用层认识设备并创建设备文件 -->使用udev规则。

只有当udev检测到内核中有侦听到usb设备接入的信息并且添加了对应的udev规则,才会在/dev/bus/usb/001那里动态创建设备文件(并且这这个文件的权限是0666),之后adb程序(应用层)能访问到usb设备(手机)。

但是前提必须要有下面对应的规则才能配置对应的设备文件,如果没有这条规则,就不会为新接入的设备配置对应的设备文件权限(usb设备)。

当在/etc/udev/rules.d这个目录下创建vivo-android.rules(赋予usb设备可读可写权限)这个文件给 udev服务和使用之后,应用层可以访问usb设备了(可以使用adb去访问了)。

简单说:没有udev规则,udev机制就不知道如何管理设备,没有udev机制,规则就只是一堆文本文件。两者紧密结合,共同实现 Linux 的动态设备管理。

2. 守护进程

2.1 概念:

Linux Daemon(守护进程)是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行
某种任务或等待处理某些发生的事件。它不需要用户输入就能运行并且能提供某种服务,不是对整个系统就是对某个用户程序提供服务。Linux系统的大多数服务器就是通过守护进程实现的。常见的守护进程包括系统日志进程syslogdweb服务器httpd、邮件服务器sendmail和数据库服务器
mysqld等。守护进程的名称通常以d结尾。
例如:udev守护进程,它能够根据系统中的硬件设备的状态动态来更新设备文件,包括设备文件的创建,删除等。

2.2 基本特点

• 生存周期长[非必须],一般操作系统启动的时候就启动,关闭的时候关闭。
• 守护进程和终端无关联,也就是他们没有控制终端,所以当控制终端退出,也不会导致守护进程退出。
• 守护进程是在后台运行,不会占着终端,终端可以执行其他命令。
• 一个守护进程的父进程是init进程,因为它真正的父进程在fork出子进程后就先于子进程exit退出
了,所以它是一个由init继承的孤儿进程。
• 如图:
• ppid = 0:内核进程,跟随系统启动而启动,生命周期贯穿整个系统。
• cmd列名带[]这种,叫内核守护进程。
• 老祖init:也是系统守护进程,它负责启动各运行层次特定的系统服务,所以很多进程的PPIDinit,也负责收养孤儿进程。
• cmd列中名字不带[]的普通守护进程(用户守护进程)。

2.3守护进程开发方式

• 直接借助damon()函数完成。
#include <unistd.h> /* int daemon(int nochdir, int noclose); 函数参数: nochdir:为0时表示将当前目录更改至“/”,转换工作目录和脱离终端 noclose:为0时表示将标准输入、标准输出、标准错误重定向至“/dev/null” 返回值:成功则返回0,失败返回-1 */ #include <unistd.h> #include <signal.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <sys/stat.h> #include <time.h> #include <stdio.h> //C 库函数 char *asctime(const struct tm *timeptr) 返回一个指向字符串的指针,它代表了结构 //struct timeptr 的日期和时间。 //C 库函数 struct tm *localtime(const time_t *timer) 使用 timer 的值来填充 tm 结构。 //timer 的值被分解为 tm 结构,并用本地时区表示。 /* struct tm { int tm_sec; 秒,范围从 0 到 59 int tm_min; 分,范围从 0 到 59 int tm_hour; 小时,范围从 0 到 23 int tm_mday; 一月中的第几天,范围从 1 到 31 int tm_mon; 月份,范围从 0 到 11 int tm_year; 自 1900 起的年数 int tm_wday; 一周中的第几天,范围从 0 到 6 int tm_yday; 一年中的第几天,范围从 0 到 365 int tm_isdst; 夏令时 }; */ static bool flag = true; void handler(int sig) { printf("I got a signal %d\nI'm quitting.\n", sig); flag = false; } int main() { time_t t; int fd; //创建守护进程 if(-1 == daemon(0, 0)){ printf("daemon error\n"); exit(1); } //设置信号处理函数 struct sigaction act; act.sa_handler = handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; if(sigaction(SIGQUIT, &act, NULL)){ printf("sigaction error.\n"); exit(0); } //进程工作内容 while(flag){ fd = open("/home/orangepi/daemon.log", O_WRONLY | O_CREAT | O_APPEND,0644); if(fd == -1){ printf("open error\n"); } t = time(0);//获取当前时间戳 char *buf = asctime(localtime(&t)); write(fd, buf, strlen(buf)); close(fd); sleep(10); } return 0; } //sudo vi /etc/rc.local 开机自启动,绝对路径加程序名字,一开机就能启动这个守护进程了。

3. 守护进程的应用

3.1守护进程不让控制程序退出

#include <unistd.h> #include <signal.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <sys/stat.h> #include <time.h> #include <stdio.h> #include <stdbool.h> static bool flag = true; void handler(int sig){ printf("I got a signal %d\nI'm quitting.\n", sig); flag = false; } int judMent(){ FILE *file; char buffer[128] = {'\0'}; char *cmd = "ps -elf |grep douyinUtils|grep -v grep"; file = popen(cmd, "r"); fgets(buffer, 128, file); if(strstr(buffer, "douyinUtils") != NULL){ return 0; }else{ return -1; } printf("BUFFER:%s\n",buffer); } int main(){ time_t t; int fd; //创建守护进程 if(-1 == daemon(0, 0)){ printf("daemon error\n"); exit(1); } //设置信号处理函数 struct sigaction act; act.sa_handler = handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; if(sigaction(SIGQUIT, &act, NULL)){ printf("sigaction error.\n"); exit(0); } //进程工作内容 while(flag){ if( judMent() == -1){ system("/home/orangepi/hardwareSoft/douyin/douyinUtils /dev/ttyS5 &"); } sleep(2); } return 0; } //开机启动: // /home/orangepi/hardwareSoft/douyin/douyinUtils /dev/ttyS5 & 添加了&变成后台程序。 // /home/orangepi/hardwareSoft/douyin/shouhuDouyin

3.2守护进程和后台进程的区别

• 守护进程和终端不挂钩,后台进程能往终端上输出东西(和终端挂钩)。
• 守护进程关闭终端时不受影响,守护进程不会随着终端的退出而退出。

4. udev规则的补充

• 规则文件是 udev里最重要的部分,默认是存放在/etc/udev/rule.d/ 下。所有的规则文件必须以 ".rules" 为后缀名。这是一个简单的规则:KERNEL=="sda", NAME="my_root_disk", MODE="0660"

• KERNEL 是匹配键,NAMEMODE是赋值键。这条规则的意思是:如果有一个设备的内核名称为sda,则该条件生效,执行后面的赋值:在/dev下产生一个名为my_root_disk的设备文件,并把设备文件的权限设为 0660
• udevadm info --attribute-walk --name=/dev/设备名字 这个指令可以查设备的所有信息。

4.1 udev匹配键

ACTION:事件(uevent)的行为,例如:add(添加设备)、remove(删除设备); KERNEL:内核设备名称,例如:sda,cdrom; DEVPATH:设备的 devpath 路径; SUBSYSTEM:设备的子系统名称,例如:sda 的系统为 block; BUS:设备在 devpath 里的总线名称,例如:usb; DRIVER:设备在 devpath 的设备驱动名称,例如:ide-cdrom; ID:设备在 devpath 里的识别号; SYSFS{filename}:设备的 devpath 路径下,设备的属性文件 "filename" 里的内容; ENV{key}:环境变量。在一条规则中,可以设定最多五条环境变量的 匹配键; PROGRAM:调用外部命令; RESULT:外部命令 PROGRAM 的返回结果。
• 例如,自动挂载U盘的规则:
ACTION=="add", SUBSYSTEMS=="usb", SUBSYSTEM=="block", RUN{program}+="/bin/mkdir
/media/%k" ,RUN{program}+="/usr/bin/systemd-mount --no-block --collect $devnode
/media/%k
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/1 8:33:32

AI写教材怎么做到低查重?专业工具与方法大公开!

编写教材的过程离不开丰富的资料支持&#xff0c;但传统的资料收集方式已无法满足当前的需求。以往&#xff0c;我们需要从众多渠道&#xff0c;如课标文件、学术论文和教学示例中&#xff0c;去认真筛选有用的信息&#xff0c;这个过程往往要耗费好几天的时间。即便把这些信息…

作者头像 李华
网站建设 2026/2/1 8:21:29

当金融市场熔断与球场逆转同频:测试工程师的风险预判艺术

2026年2月1日&#xff0c;比特币单日暴跌9.55%创40年最大跌幅&#xff0c;伦敦金价同步重挫引发连锁爆仓&#xff1b;同一时空下&#xff0c;英超赛场利物浦0-1落后时4球逆转纽卡&#xff0c;切尔西更上演让二追三的极限翻盘。这些看似无关的事件&#xff0c;恰好揭示了软件测试…

作者头像 李华
网站建设 2026/2/1 8:18:48

揭秘AI教材编写技巧!低查重AI写教材工具助你轻松搞定

传统教材编写问题与AI工具的解决方案 在编写教材时&#xff0c;资料的整合是至关重要的&#xff0c;但传统方式早已无法适应现代的需求。以往&#xff0c;我们需要从课标文件、学术文章和教学案例中逐一寻找信息&#xff0c;这个过程不仅耗时&#xff0c;还需要在知网、教研平…

作者头像 李华
网站建设 2026/2/1 8:15:07

WPF数据绑定入门:从传统事件到5种绑定模式

在WPF开发中&#xff0c;数据绑定是核心特性&#xff0c;能让Slider、TextBox等控件间的数值同步无需手写事件代码&#xff0c;彻底解决传统方式的代码冗余、强耦合问题。本文以滑块和文本框数值同步为案例&#xff0c;先讲传统事件实现&#xff0c;再用全注释代码演示WPF绑定&…

作者头像 李华
网站建设 2026/2/1 7:55:24

C语言对话-17.匈牙利命名

徐波 翻译 “突破&#xff01;”一个官员大叫道&#xff0c;她的脑袋探入杂乱的大厅。 好几个人&#xff0c;包括珍妮和我都抬起了头。“什么&#xff1f;”“谁的突破&#xff1f;”“怎么回事&#xff1f;” 这突然的兴奋是显而易见的&#xff0c;而且可以理解&#xff…

作者头像 李华
网站建设 2026/2/1 7:39:54

社会网络仿真软件:Pajek_(8).子群与社区检测方法

子群与社区检测方法 在社会网络分析中&#xff0c;子群与社区检测是一个非常重要的任务。通过对网络中的子群或社区进行识别&#xff0c;可以揭示网络的结构特征&#xff0c;理解网络中的信息传播机制&#xff0c;以及挖掘网络中的潜在关系。Pajek 提供了多种子群与社区检测方…

作者头像 李华