Linux——进程信号(一)

1.信号入门

1.1生活中的信号

什么是信号?

结合实际红绿灯、闹钟、游戏中的"!"等等这些都是信号。

以红绿灯为例子:

一看到红绿灯我们就知道:红灯停、绿灯行;我们不仅知道它是一个红绿灯而且知道当其出现不同的状况时我们应该做出怎么样的行为去应对。

识别=认识+行为产生

对于红绿灯:

我们之前受过的教育,让我们能够识别这个红绿灯(即使它还未出现在我们眼前),也就是说你能识别"红绿灯"

当绿灯量了后我们不一定要直接走,也可以等一会再走(也就是说接收信号后我们不一定要立刻产生对应的行为)

当红灯亮了之后,我们可以玩手机,要记得这个时候还是红灯

当红或绿灯亮时我们可以做出其他行为,也可以忽略红绿灯

对于信号来说(进程看待信号的方式)

  1. 在没有发生的时候,进程已经知道发生的时候该怎么处理了
  2. 信号进程能够认识,在遇见信号之前有人在"大脑"中设置了识别特定信号的方式(进程能够识别一个信号并处理)
  3. 信号到来的时候,进程正在处理更重要的事情,这时进程暂时不能立即处理到来的信号,进程必须暂时将到来的信号进行临时保存
  4. 信号到了进程可以不立即处理,等在合适的时候处理
  5. 信号的产生是随时产生的,进程无法准确预料,所以信号是异步发送的(信号的产生是由别人(用户、进程)产生的,在进程收到信号之前,进程一直在忙自己的事情,并发在跑的)

 为什么?

停止、删除...系统要求进程要有随时响应外部信号的能力,随后做出反应

我们学习信号是学习它的整个生命周期,在进程运行期间信号的生命周期分为以下几个阶段:

准备、信号的产生、信号的保存、信号的处理

1.2Linux中的信号

用户输入命令,在Shell下启动一个前台进程
用户按下 Ctrl-C ,这个键盘输入产生一个硬件中断,被OS获取,解释成信号,发送给目标前台进程
前台进程因为收到信号,进而引起进程退出

#include<iostream>
#include<unistd.h>using namespace std;int main()
{while(1){cout<<"i am main process..."<<endl;sleep(1);}return 0;
}

  1. Ctrl-C 产生的信号只能发给前台进程。一个命令后面加个&可以放到后台运行,这样Shell不必等待进程结束就可以接受新的命令,启动新的进程。
  2. Shell可以同时运行一个前台进程和任意多个后台进程,只有前台进程才能接到像 Ctrl-C 这种控制键产生的信号。
  3. 前台进程在运行过程中用户随时可能按下 Ctrl-C 而产生一个信号,也就是说该进程的用户空间代码执行到任何地方都有可能收到 SIGINT 信号而终止,所以信号相对于进程的控制流程来说是异步(Asynchronous)的。 

1.3信号的概念

信号是进程之间事件异步通知的一种方式,属于软中断

在Linux操作系统中命令:kill -l可以查看系统定义的信号列表 

上面的数字和名字都可以标识信号,名字其实就是宏;总共62个信号(没有0、32、33信号)

其中:1~31号是普通信号                                        34~64是实时信号

我们这里只学普通信号

上面我们说到:每个信号都有一个编号和一个宏定义名称,这些宏定义名称可以在signal.h中找到,这些信号各自在什么条件下产生,默认的处理动作是什么,在signal(7)中都有详细说明: man 7 signal 

根据我们对Linux的了解,信号存放在哪呢?既然信号是给进程的,而进程又是通过内核数据结构来管理的,那么我们可以推断出,信号是放在进程的task_struct结构体中

既然他是在PCB中,如果创建31变量把信号全存进去,那就太浪费了;进程中信号的状态分为有或者没有,那么我们可以大胆的推断:把31个信号存放在一个只有32位整型变量中,每一个比特位都代表一个信号。

比特位的位置,代表信号的编号

比特位的内容:代表进程是否收到信号,1表收到,0表没收到

那么问题来了,内核数据结构的修改,这是由谁来完成的?

毫无疑问,是操作系统,毕竟task_struct就是由它来维护的,只有OS才有权利去修改它

所以说,无论哪个信号,最后都是经由OS之手发送给进程的(发送指的是修改进程PCB中存放信号那个变量的比特位)

信号发送的本质就是:在修改进程PCB中信号位图

 信号处理常见方式概览:

1. 忽略此信号。
2. 执行该信号的默认处理动作。
3. 提供一个信号处理函数,要求内核在处理该信号时切换到用户态执行这个处理函数,这种方式称为捕捉(Catch)一个信号。

2.信号的产生

kill系统调用接口

kill -9 pid //杀死进程
kill -2 pid //终止进程

 

2.1通过按键产生信号

通过键盘上按一些热键,来给进程发送相应的信号,比如上面的ctrl c,它产生的是2号信号;ctrl \产生的则是3号信号

如何进行自定义处理信号呢?

信号捕捉

signal

sighandler_t 返回值        signum几号信号       

handler自定义方法 typedef void (*sighandler_t)(int)

#include<iostream>
#include<unistd.h>
#include<signal.h>
#include<sys/types.h>
using namespace std;void handler(int signo)
{cout<<"get a sig,number is:"<<signo<<endl;
}int main()
{signal(SIGINT,handler);while(1){cout<<"I am activing...,pid:"<<getpid()<<endl;sleep(1);}return 0;
}

设置信号捕捉只需要一次

signal调用完了handler方法不会被立即执行,这里只是设置对应的信号的处理方法  

这时候我们发现Ctrl C杀不了这个进程了,这是因为我们捕捉信号后(信号的处理方式是自定义处理信号)对于2号信号的处理动作变成执行handler方法

2.2调用系统函数向进程发信号

系统调用和命令的名字一样,man 2 kill 查看

pid_t pid :要给发信号的pid 

int sig:要发送的信号编号

返回值:发送成功返回0,失败返回-1 

该系统调用是一个进程给另一个进程发送指定信号,可以向任意进程发送任意信号

#include<iostream>
#include<unistd.h>
#include <string.h>
#include<signal.h>
#include<sys/types.h>
using namespace std;int main(int argc, char *argv[])
{if(argc != 3){cout << "Usage: " << argv[0] << " -signumber pid" << endl;return 1;}int signumber = stoi(argv[1]+1);int pid = stoi(argv[2]);int n = kill(pid, signumber);if(n < 0){cerr << "kill error, " << strerror(errno) << endl;}return 0;
}

raise给自己发送任意信号

 

#include<iostream>
#include<unistd.h>
#include<signal.h>using namespace std;
int main()
{cout<<"开始运行..."<<endl;sleep(1);int n = raise(2);cout<<"运行结束"<<endl;return 0;
}

 

abort发信号终止自己(指定信号 6号:SIGABRT) 

 

 2.3软件条件产生信号

比如管道那时候,把读端关闭(没有了写的条件),那么写端也会收到信号关闭(SIGPIPE)

再举个闹钟的例子:

alarm

unsigned int 返回值 :上一个闹钟剩余秒数

#include<iostream>
#include<unistd.h>
#include <string.h>
#include<signal.h>
#include<sys/types.h>
using namespace std;
int g_cnt = 0;
void handler(int sig)
{std::cout << "get a sig: " << sig << " g_cnt: " << g_cnt << std::endl;unsigned int n = alarm(5);cout << "还剩多少时间: " << n << endl;exit(0);
}int mian()
{//设定一个闹钟signal(SIGALRM,handler);alarm(5);while(true){g_cnt++;}int cnt = 0;while(true){sleep(1);cout << "cnt : " << cnt++ << ", pid is : "<< getpid() << endl; //IO其实很慢if(cnt == 2){int n = alarm(0); // alarm(0): 取消闹钟cout << " alarm(0) ret : " << n << endl;}}return 0;
}

 

2.4硬件异常产生信号 

最后一种产生信号的方式:异常

硬件异常被硬件以某种方式被硬件检测到并通知内核,然后内核向当前进程发送适当的信号。例如当前进程执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释 为SIGFPE信号发送给进程。再比如当前进程访问了非法内存地址,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给进程。

除零错误引发异常 8)SIGFPE

void handler(int sig)
{cout<<"get a sig:"<<sig<<endl;exit(1);
}int main()
{signal(SIGFPE,handler);int a = 10;a /= 0;while(1){sleep(1);}return 0;
}

 

野指针                  11)SIGSEGV

void handler(int sig)
{cout<<"get a sig:"<<sig<<endl;exit(1);
}
int main()
{signal(SIGSEGV, handler);sleep(1);int *p = NULL;*p = 100;while(1){sleep(1);}return 0;
}

 2.5关于信号产生的各种情况的理解

2.5.1键盘产生信号——硬件中断

键盘产生信号:

a.按键按下了         b.哪些按键按下了         c.字符输入(字符设备),组合键输入

字符输入:abcd         组合键输入:CTRL C                键盘驱动和OS联合解释的

OS怎么知道键盘输入了什么数据呢?        硬件中断的技术

键盘 将电信号传到CPU的针脚上 通过硬件中断转化位软信号电流,CPU再传给OS,OS通过中断向量表中以中断号去检索解释 判定是字符就放到缓冲区里面,是命令(ctrl+c)解释为信号

2.5.2异常(硬件)产生信号——除零、解引用空指针

除零

void handler(int sig)
{cout<<"get a sig:"<<sig<<endl;
}int main()
{signal(SIGFPE,handler);int a = 10;a /= 0;while(1){sleep(1);}return 0;
}

如果捕捉除零产生的信号不用exit退出进程的话,随着CPU时间片的轮转就会再次被调到

CPU中只有一份寄存器,但是寄存器的内容属于当前进程的硬件上下文

当进程被切换的时候,就有无数次的状态寄存器被保存和恢复的过程

而除0操作导致溢出位置一的数据还会被恢复到CPU中

所以每次恢复的时候,操作系统就会识别到,并且给对应的进程发送SIGFPE信号,这就导致了上面不停调用自定义处理函数,不停地打印

如何理解除0?

进行计算的是CPU这个硬件

CPU内部有寄存器,状态寄存器(位图)有对应的状态标记位、溢出标记位,OS会自动进行计算完后的检测,如果溢出标记位是1,CPU会告诉OS有溢出的问题,OS就会来查看问题并且找到出问题的那个进程,并且将所识别到的硬件错误包装成信号发送给目标进程,本质就是操作系统去直接找到这个进程的task_struct并向该进程写入8信号

野指针异常

 对于野指针异常来说,实际上也是CPU、OS共同配合的结果

我们所说的野指针指的是虚拟地址,虚拟地址和物理地址的转化如果是成功的,那么就不会抛出野指针异常,如果是失败的,那么CPU就会告诉OS出问题了,OS就会找到那个进程并发出11号信号,让他终止

虚拟地址与物理地址之间的映射是由一个叫MMU的硬件完成的,他是一种负责处理CPU的内存访问请求的计算机硬件

页表实际上是页表和MMU的结合,而MMU位于CPU中。在讨论中一般会简化称为页表。

当对空指针解引用的时候,MMU会拒绝这种操作,从而产生异常标志

操作系统拿到MMU产生的异常以后就会给对应的进程发送SIGSEGV信号

3.信号的保存

上面我们提到:如果当前进行更重要的工作,那么它会将信号进行保存,等到合适的时候再做处理,那么信号的保存机制是怎么实现的呢?

3.1信号常见概念

  • 实际执行信号的处理动作称为信号递达(Delivery)
  • 信号从产生到递达之间的状态,称为信号未决(Pending)。
  • 进程可以选择阻塞 (Block )某个信号
  • 被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作

 注意: 阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作

进程PCB中有一张位图:用来表示有无收到指定信号

还有一张位图:比特位的位置依然是信号编号,比特位的内容表示是否阻塞该信号

如:1号位图4号信号位置为1,2号位图4号信号位置为0,4号信号无阻塞通畅递达

1号位图6号信号位置为1,2号位图6号信号位置为1,6号信号阻塞,不递达(除非未来解除阻塞)

3.2在内核中的表示

记住三张表 

block表:位图        pending表:位图        handler表:函数指针数组 

每个信号都有两个标志位分别表示阻塞(block)和未决(pending),还有一个函数指针表示处理动作。信号产生时,内核在进程控制块中设置该信号的未决标志,直到信号递达才清除该标志。在上图的例子中,SIGHUP信号未阻塞也未产生过,当它递达时执行默认处理动作。

SIGINT信号产生过,但正在被阻塞,所以暂时不能递达。虽然它的处理动作是忽略,但在没有解除阻塞之前不能忽略这个信号,因为进程仍有机会改变处理动作之后再解除阻塞。

SIGQUIT信号未产生过,一旦产生SIGQUIT信号将被阻塞,它的处理动作是用户自定义函数sighandler。
如果在进程解除对某信号的阻塞之前这种信号产生过多次,将如何处理?POSIX.1允许系统递送该信号一次或多次。Linux是这样实现的:常规信号在递达之前产生多次只计一次,而实时信号在递达之前产生多次可以依次放在一个队列里。本章不讨论实时信号。 

3.3三张表匹配的操作和系统调用 

在此之前,了解一下sigset_t

从上图来看,每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的。
因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集,这个类型可以表示每个信号的“有效”或“无效”状态,在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态。 阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask),这里的“屏蔽”应该理解为阻塞而不是忽略。

 sigset_t类型对于每种信号用一个bit表示“有效”或“无效”状态,至于这个类型内部如何存储这些bit则依赖于系统实现,从使用者的角度是不必关心的,使用者只能调用以下函数来操作sigset_ t变量,而不应该对它的内部数据做任何解释,比如用printf直接打印sigset_t变量是没有意义的

3.3.1信号集操作函数

man sigemptyset:

sigset_t set:信号集变量

int signum:信号编号

返回值:成功返回0,失败返回-1。 

函数sigemptyset:

初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含 任何有效信号
函数sigfillset:

初始化set所指向的信号集,使其中所有信号的对应bit置位,表示 该信号集的有效信号包括系统支持的所有信号。


注意,在使用sigset_ t类型的变量之前,一定要调 用sigemptyset或sigfillset做初始化,使信号集处于确定的状态。

初始化sigset_t变量之后就可以在调用sigaddsetsigdelset在该信号集中添加或删除某种有效信号

sigismember是一个布尔函数,用于判断一个信号集的有效信号中是否包含某种信号

3.3.2sigprocmask

调用函数sigprocmask可以读取或更改进程的信号屏蔽字(阻塞信号集)。

man sigprocmask

int how: 修改方式,有三个选项

set:

我们设置号的sigset_t变量

oldset:

输出型参数,将修改之前的信号屏蔽字保存到oldset

返回值:sigprocmask函数调用成功返回0,出错返回-1

3.3.3pending的系统调用sigpending

读取当前进程的未决信号集,通过set参数传出。调用成功则返回0,出错则返回-1。

man sigpending

 

 4.代码

#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <cassert>
#include <sys/wait.h>
using namespace std;void PrintSig(sigset_t &pending)
{cout<<"Pending bitmap:"<<endl;for(int i=31;i>0;i--)//i为比特位,也是信号编号{if(sigismember(&pending,i)){cout<<"1";}else{cout<<"0";}}cout<<endl;
}
void handler(int sig)
{sigset_t pending;sigemptyset(&pending);int n = sigpending(&pending);//正在处理2号信号assert(n==0);cout<<"递达中..."<<endl;PrintSig(pending);cout<<sig<<"号信号被递达处理"<<endl;}int main()
{//对2号信号进行自定义捕捉signal(2,handler);sigset_t block,o_block;//屏蔽2号信号sigemptyset(&block);sigemptyset(&o_block);sigaddset(&block,2);//进入内核int n = sigprocmask(SIG_SETMASK,&block,&o_block);assert(n==0);cout<<"block 2 signal success"<<"pid:"<<getpid()<<endl;int cnt = 0;while(1){sigset_t pending;sigemptyset(&pending);n = sigpending(&pending);assert(n == 0);//打印pending位图中收到的信号PrintSig(pending);cnt++;//解除对2号信号的屏蔽if(cnt==10){n = sigprocmask(SIG_UNBLOCK,&block,&o_block);assert(n==0);}sleep(1);}return 0;
}

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

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

相关文章

半导体测试基础 - AC 参数测试

AC 测试确保 DUT 的时特性序满足其规格需求。 基本 AC 参数 建立时间(Setup Time) 建立时间指的是在参考信号(图中为 WE)发生变化(取中间值 1.5V)前,为了确保能被正确读取,数据(图中为 DATA IN)必须提前保持稳定不变的最短时间。在最小建立时间之前,数据可以随意变…

C语言游戏实战(12):植物大战僵尸(坤版)

植物大战僵尸 前言&#xff1a; 本游戏使用C语言和easyx图形库编写&#xff0c;通过这个项目我们可以深度的掌握C语言的各种语言特性和高级开发技巧&#xff0c;以及锻炼我们独立的项目开发能力&#xff0c; 在开始编写代码之前&#xff0c;我们需要先了解一下游戏的基本规则…

OSPF路由聚合

原理概述 与RIP不同&#xff0c;OSPF不支持自动路由聚合&#xff0c;仅支持手动路由聚合。OSPF的路由聚合有两种机制&#xff1a;区域间路由聚合和外部路由聚合。区域间路由聚合必须配置在ABR路由器上&#xff0c;指的是ABR在把与自己直接相连区域&#xff08;Area&#xff09…

Dijkstra算法在《庆余年》中的应用:范闲的皇宫之旅

❤️❤️❤️ 欢迎来到我的博客。希望您能在这里找到既有价值又有趣的内容&#xff0c;和我一起探索、学习和成长。欢迎评论区畅所欲言、享受知识的乐趣&#xff01; 推荐&#xff1a;数据分析螺丝钉的首页 格物致知 终身学习 期待您的关注 导航&#xff1a; LeetCode解锁100…

【探索数据结构】线性表之双链表

&#x1f389;&#x1f389;&#x1f389;欢迎莅临我的博客空间&#xff0c;我是池央&#xff0c;一个对C和数据结构怀有无限热忱的探索者。&#x1f64c; &#x1f338;&#x1f338;&#x1f338;这里是我分享C/C编程、数据结构应用的乐园✨ &#x1f388;&#x1f388;&…

MT3041 多项式变换求值

注意点&#xff1a; 1.使用单调栈 2.用ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);避免超时 3.此题除了ans最好不要用long long&#xff0c;如果a[]和b[]都是long long 类型&#xff0c;可能会超内存 4.ans (ans % p p) % p;防止负数 5.使用秦九韶算法计算指数…

【Linux】语言级文件接口与系统级文件接口

目录 前言 一、回顾C语言中的文件操作 二、认识文件缓冲区 三、Linux系统提供的文件接口 四、文件描述符fd简介 Linux下C语言文件接口简单模拟实现 前言 每个编程语言都有自己的文件操作方法&#xff0c;在不同的操作系统下相同的语言有相同的文件操作方法。这是如何实现…

声音转文本(免费工具)

声音转文本&#xff1a;解锁语音技术的无限可能 在当今这个数字化时代&#xff0c;信息的传递方式正以前所未有的速度进化。从手动输入到触控操作&#xff0c;再到如今的语音交互&#xff0c;技术的发展让沟通变得更加自然与高效。声音转文本&#xff08;Speech-to-Text, STT&…

git拉取项目前需要操作哪些?

1.输入 $ ssh-keygen -t rsa -C "秘钥说明" 按enter键 2.出现 ssh/id_rsa&#xff1a;(输入也可以不输入也可以) 然后按enter键 3.出现empty for no passphrase&#xff1a;(输入也可以不输入也可以) 然后按enter键 4.出现same passphrase again: (输入也可以不输入也…

异常检测 | PCA马氏距离异常值检测(Matlab)

异常检测 | PCA马氏距离异常值检测&#xff08;Matlab&#xff09; 目录 异常检测 | PCA马氏距离异常值检测&#xff08;Matlab&#xff09;效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab Pca 马氏距离异常值检测&#xff0c;剔除异常样本&#xff0c;置信椭圆可…

15:00面试,15:08就出来了,问的问题有点变态。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到8月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…

4. C++入门:内联函数、auto关键字、范围for及nullptr

内联函数 概念 以inline修饰的函数叫做内联函数&#xff0c;编译时C编译器会在调用内联函数的地方展开&#xff0c;没有函数调用建立栈帧的开销&#xff0c;内联函数提升程序运行的效率 对比C的宏 C语言不足&#xff1a;宏 #define ADD(x, y) ((x)(y))int main() {int ret…

OpenFeign高级用法:缓存、QueryMap、MatrixVariable、CollectionFormat优雅地远程调用

码到三十五 &#xff1a; 个人主页 微服务架构中&#xff0c;服务之间的通信变得尤为关键。OpenFeign&#xff0c;一个声明式的Web服务客户端&#xff0c;使得REST API的调用变得更加简单和优雅。OpenFeign集成了Ribbon和Hystrix&#xff0c;具有负载均衡和容错的能力&#xff…

期权策略交易怎么做?怎么选择期权策略?

今天期权懂带你了解期权策略交易怎么做&#xff1f;怎么选择期权策略&#xff1f;期权交易是一种金融衍生品交易方式&#xff0c;它给予购买者在未来特定时间内以特定价格购买&#xff08;或出售&#xff09;标的资产的权利。 期权策略交易怎么做&#xff1f; 配对看跌期权&am…

vue+springboot实现echarts数据图统计

①vue项目修改配置 安装依赖&#xff1a; npm i echarts -S 修改路由index.js&#xff1a; import Vue from vue import VueRouter from vue-router import Manager from ../views/Manager.vue // 解决导航栏或者底部导航tabBar中的vue-router在3.0版本以上频繁点击菜单报错…

00.OpenLayers快速开始

00OpenLayers快速开始 官方文档&#xff1a; 快速开始&#xff1a;https://openlayers.org/doc/quickstart.html 需要node环境 一、设置新项目 npm create ol-app my-app cd my-app npm start第一个命令将创建一个名为 my-app​ 的目录&#xff08;如果您愿意&#xff0c;…

Python筑基之旅-MySQL数据库(一)

目录 一、MySQL数据库 1、简介 2、优点 2-1、开源和免费 2-2、高性能 2-3、可扩展性 2-4、易用性 2-5、灵活性 2-6、安全性和稳定性 2-7、丰富的功能 2-8、结合其他工具和服务 2-9、良好的兼容性和移植性 3、缺点 3-1、对大数据的支持有限 3-2、缺乏全文…

前端面试:项目细节重难点问题分享

面试官提问&#xff1a;我现在给你出一个项目实际遇到的问题&#xff1a;由于后端比较忙&#xff0c;所以我们这边的列表数据排序需要前端最近实现&#xff0c;那你会怎么实现排序呢&#xff1f; 答&#xff1a;我的回答&#xff1a;确实&#xff0c;数据都是由后端实现的&…

正点原子[第二期]Linux之ARM(MX6U)裸机篇学习笔记-19讲 串口实验UART

前言&#xff1a; 本文是根据哔哩哔哩网站上“正点原子[第二期]Linux之ARM&#xff08;MX6U&#xff09;裸机篇”视频的学习笔记&#xff0c;在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。…

嵌入式硬件中PCB走线与过孔的电流承载能力分析

简介 使用FR4敷铜板PCBA上各个器件之间的电气连接是通过其各层敷着的铜箔走线和过孔来实现的。 由于不同产品、不同模块电流大小不同,为实现各个功能,设计人员需要知道所设计的走线和过孔能否承载相应的电流,以实现产品的功能,防止过流时产品烧毁。 文中介绍设计和测试FR4敷…