1、概述\x26amp;nbsp; \x26amp;nbsp; \x26amp;nbsp;Aurora 8B/10B协议是一个用于在点对点串行链路间
“热拔插”其实就是带电拔插,对于日常使用的电子产品来说,很多时候我们都是经常性的带电拔插,比如路由器,手机,平板,笔记本电脑等等,你很难做的到,说先把充电线接上设备,然后再去插220V的排插,反正我日常使用不会去刻意纠结这个顺序,咋方便咋来。那“热拔插”由于是带电拔插,所以就会在接触的那一瞬间,会产生尖峰电压,这对板子上的器件是致命的。那该如何改善这一情况呢?(1)加RC缓冲电路,如下图所示:具体的选值,需要先测出电路中尖峰的频率(本质上和LC振荡区别不大),再根据公式:C是电路中的杂散电容。L是电路中的等效电感。详细的计算过程我们后面在反激电源RC吸收电路中再展开讲。 (2)加TVS或者ESD,这个方式是比较简单,具体的选型要求可以翻看下面这两篇文章:TVS管几点选型经验!从SD卡电路中学习如何使用ESD管防静电 (3)复合防护电路,主要由TVS管和压敏,安规电容组成,效果较好,但成本稍高!好了,就先写到这吧!
一、mmap在linux系统哪里? 二、什么是mmap? 通过上图我们可以知道mmap是操作硬件设备的一种方法,所谓操作设备,比如IO端口(点亮一个LED)、LCD控制器、磁盘控制器,实际上就是往设备的物理地址上读写数据。 但是,由于应用程序不能直接操作设备硬件地址,所以操作系统提供了这样一种机制——内存映射,把设备地址映射到进程虚拟地址,mmap就是实现内存映射的接口。 操作设备还有很多方法,如ioctl、ioremap等。 mmap的好处就是,mmap把设备内存映射到虚拟内存,则用户操作虚拟内存相当于在直接操作设备,省去了用户空间到内核空间的复制过程,相对IO操作来说,增加了数据的吞吐量。 三、什么是内存映射? 既然mmap是实现内存映射的接口,那么内存映射是什么呢?如下图所示: 每个进程都有独立的进程地址空间,通过页表和MMU,可以将虚拟地址转换为物理地址,每个进程都有独立的页表数据,这就可以解释为什么两个不同进程相同的虚拟地址却对应着不同的物理地址。 四、mmap在文件内存映射上的应用 在unix/linux平台上读写文件,一般有两种方式。分别为open系统调用函数和mmap内存映射。 1.open系统调用 首先open文件,接着使用read系统调用函数来读取文件。于是内核将文件的内容从磁盘上读取到内核页高速缓存中(主存RAM中),再从内核高速缓存读取到用户进程的地址空间。这么做需要在内核和用户空间之间做多次数据拷贝。而且当多个进程同时读取一个文件时,那么每个进程在自己的页表中都有这个文件的副本并且都对应到物理内存中各自的副本,这样便造成了物理内存的浪费。如下图所示: 2.mmap内存映射 mmap是一种内存映射的方法,就是将一个文件或者其他对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对应关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write等系统调用函数。如下图所示: 五、linux内存描述符 了解了内存映射的概念后,那么内核是怎么管理这些地址空间的呢?任何复杂的理论最终也是通过各种数据结构体现出来的,而这里使用的数据结构就是进程描述符。从内核角度看,进程是分配系统资源(CPU、内存)的载体,为了管理进程,内核必须对每个进程所做的事情进行清楚的描述,这就是进程描述符。内核用task_struct结构体来表示进程,并且维护一个该结构体链表来管理所有进程。该结构体包含一些进程状态、调度信息等上千个成员,我们这里主要关注进程描述符里面的内存描述符(struct mm_struct mm)。内存管理如下图所示: 现在已经知道了内存映射是把设备地址映射到进程空间地址(注意:并不是所有内存映射都是映射到进程地址空间的,ioremap是映射到内核虚拟空间的,mmap是映射到进程虚拟地址上的),实质上是分配了一个vm_area_struct结构体加入到进程的地址空间,也就是说,把设备地址映射到这个结构体,具体到映射的过程就是驱动程序要做的事情了。vm_area_struct结构中包含区域起始和终止地址以及其他相关信息,同时也包含一个vm_ops指针,其内部可引出所有针对这个区域可以使用的系统调用函数。这样,进程对某一虚拟内存区域的任何操作需要用到的信息,都可以从vm_area_struct中获得。并且如上图所示vm_area_struct结构通常是用链表的形式保存以方便进程快速的访问。 六、mmap内存映射原理 1.内存映射的步骤 用open系统调用打开文件,并返回文件描述符fd; 用mmap建立内存映射,并返回映射首地址指针start; 对映射文件进行各种操作,可以用指针偏移的方式进行读写; 用munmap关闭内存映射; 用close系统调用关闭文件描述符fd。 2.mmap内存映射的实现过程,总的来说可以分为三个阶段 (一)进程启动映射过程,并在虚拟地址空间中为映射创建虚拟映射区域 进程在用户空间调用库函数mmap,原型为:void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset); 在当前进程的虚拟地址空间中,寻找一段空闲的满足要求的连续的虚拟地址; 为此虚拟区域分配一个vm_area_struct结构体,接着对这个结构体的各个字段进行初始化; 将新建的虚拟区域结构体(vm_area_struct)插入到进程的虚拟地址区域链表或树中。 (二)调用内核空间的mmap函数(不同于用户空间的mmap函数),实现文件物理地址和进程虚拟地址的一一映射关系 为映射分配了新的虚拟地址区域后,通过待映射的文件指针,在文件描述符表中找到对应的文件描述符,通过文件描述符,链接到内核“已打开文件集”中该文件的文件结构体(struct file),每个文件结构体维护着和这个已打开文件相关的各项信息。 通过该文件的文件结构体,链接到file_operations模块,调用内核函数mmap,其原型为:int mmap(struct file *filp, struct vm_area_struct *vma),非用户空间的mmap函数; 内核mmap函数通过虚拟文件系统inode模块定位到文件磁盘物理地址; 通过remap_pfn_range函数建立页表,即实现了文件地址和虚拟地址区域的映射关系。此时,这片虚拟地址并没有任何数据关联到主存中。(本质上,用户进程的虚拟地址映射到磁盘文件中间还是需要经过物理内存的,也就是说进程操作虚拟地址会对应到物理地址上,物理内存再与磁盘交互数据) (三)进程发起对这片映射空间的访问,引发缺页异常,实现文件内容到物理内存的拷贝 注:前两个阶段仅在于创建虚拟区域并完成地址映射,但是并没有将任何文件数据拷贝至主存,真正的文件读取是当进程发起读或写操作时。 进程的读或写操作访问虚拟地址空间这一段地址映射,通过查询页表,发现这一段地址并不在物理页面上。因为目前只建立了地址映射,真正的硬盘数据还没有拷贝到内存中,因此引发缺页异常。 缺页异常进行一系列判断,确定无非法操作后,内核发起请求调页过程。 调页过程先在交换缓存空间(swap cache)中寻找需要访问的内存页,如果没有则调用nopage函数把所缺的页从磁盘装入到主存中。 之后进程即可对这片主存进行读或写的操作,如果写操作改变了其内容,一定时间后系统会自动回写脏页面到对应的磁盘地址,也即完成了写入文件的过程。 修改过的脏页面并不会立即更新回文件中,而是有一段时间的延迟,可以调用msync()来强制同步,这样所写的内容就能立即保存到文件里了。 3.mmap和常规文件读写的区别 简单介绍一下常规文件系统操作(调用read/fread等函数),函数的调用过程是: 进程发起读写文件请求; 内核通过查找进程文件符表,定位到内核已打开文件集上的文件信息,从而找到此文件的inode; inode在address_space上查找要请求的文件页是否已经缓存在内核页缓存中。如果存在,则直接返回这片文件页的内容; 如果不存在,则通过inode定位到文件磁盘地址,将数据从磁盘复制到内核页缓存。之后再次发起读页面的过程,进而将内核页缓存中的数据发给用户进程。 总结来说,常规文件操作为了提高读写效率和保护磁盘,使用了内核页缓存机制。这样造成读文件时需要先将文件页从磁盘拷贝到内核页缓存中,由于内核页缓存处在内核空间,不能被用户进程直接寻址,所以还需要将内核页缓存中的数据页再次拷贝到用户进程对应的物理内存中。这样,通过了两次数据拷贝过程,才能完成进程对文件内容的获取任务。写操作也是一样,待写入的buffer在内核空间是不能直接访问的,必须要先拷贝至内核空间对应的主存,再写回磁盘中(系统回延迟写脏页面),也是需要两次数据拷贝。 而使用mmap操作文件时,创建新的虚拟内存区域和建立文件磁盘地址和虚拟内存区域映射这两步没有任何文件拷贝操作。而之后访问数据时发现内存中并无数据而发起的缺页异常过程,可以通过已经建立好的映射关系,只使用一次数据拷贝,就从磁盘中将数据传入用户进程的内存中,供进程使用。 总而言之,常规文件操作需要从磁盘到内核页缓存再到用户进程物理内存的两次数据拷贝。而mmap操作文件,只需要从磁盘到用户进程物理内存的一次数据拷贝过程。说白了,mmap的关键点是实现了用户空间到内核空间的数据直接交互而省去了空间不同数据不通的繁琐过程,因此mmap效率更高。 七、mmap函数说明 头文件 #include 创建内存映射mmap void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); 参数说明: addr: 入参,如果这个地址为null那么内核将自己为你指定一个地址,如果不为null,将使用这个地址作为映射区的起始地址 length:映射区的大小(<=文件的大小) prot: 访问属性,一般用PROT_READ、PROT_WRITE、PROT_READ|PROT_WRITE flags:这个参数是确定映射的更新是否对映射相同区域的其他进程可见,以及是否对基础文件进行更新 MAP_SHARED:共享此映射,映射的更新对映射相同区域的其他进程可见 MAP_PRIVATE: 创建写时专用拷贝映射,映射的更新对映射的其他进程不可见,相同的文件,并且不会传递到基 础文件。 我们一般用MAP_SHARED,这两个权限是限制内存的,而不限制文件 fd:被映射的文件句柄 offset:默认为0,表示映射文件全部。偏移未知,需要时4K的整数倍。 返回值:成功:被映射的首地址 失败:MAP_FAILED (void *)-1 释放内存映射 int munmap(void *addr, size_t length); 参数说明: addr: 被映射的首地址 length: 映射的长度 返回值:0:成功 -1:失败 八、mmap的基础使用 #include #include #include #include #include #include int main(int argc, const char *argv[]){ char *p = NULL; int fd = -1; // 打开文件 fd = open("temp", O_RDWR|O_CREAT|O_TRUNC, 0644); if (-1 == fd) { printf("文件打开失败...\n"); return -1; } // 因为我们文件不能是一个0大小的文件,所以我们需要修改文件的大小 // 有两种方式:leek,write,或者ftruncate都可以 /* // 改变一个文件的读写指针 lseek(fd, 1023, SEEK_END); // 写入一个结束符\0 write(fd, "\0", 1); */ // 我们还是用这种,比较方便,直接就修改了,和上面效果一样 ftruncate(fd, 1024); // 创建一个内存映射,让内和指定一个映射地址,大小为1024,可读可写,共享,映射到这个fd上 p = mmap(NULL, 1024, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (p == MAP_FAILED) { printf("mmap failed\n"); close(fd); return -1; } // 拿到地址之后我们就可以像操作普通地址一样写数据,读数据了,例如memcpy,strcpy等等 memcpy(p, "hello world", sizeof("hello world")); // 读数据 printf("p = %s\n",p); // 最后释放这个映射 if (munmap(p, 1024) == -1) { printf("munmap failed\n"); close(fd); return -1; } close(fd); return 0;} gcc mmap.c 进行编译得到可执行文件a.out./a.out 可以得到执行结果p = hello world 然后看当前文件夹下会出现一个temp的文件 我们直接用cat命令进行输出: 我们会发现其实是和程序输出的一样的,到这里,基本使用就结束了。 九、mmap的使用注意事项 1.能使用创建出来的新文件进行映射吗? 答案:能,但是需要修改文件的大小,如果不修改则会出现总线错误,程序如下: #include #include #include #include #include #include int main(int argc, const char *argv[]){ char *p = NULL; int fd = -1; // 打开文件 fd = open("temp", O_RDWR|O_CREAT|O_TRUNC, 0644); if (-1 == fd) { printf("文件打开失败...\n"); return -1; } // 因为我们文件不能是一个0大小的文件,所以我们需要修改文件的大小 // 有两种方式:leek,write,或者ftruncate都可以 /* // 改变一个文件的读写指针 lseek(fd, 1023, SEEK_END); // 写入一个结束符\0 write(fd, "\0", 1); */ // 我们还是用这种,比较方便,直接就修改了,和上面效果一样 // TODO ftruncate(fd, 1024); // 主要修改了这行,我们不进行文件大小调整,那么文件大小就是0 // 创建一个内存映射,让内和指定一个映射地址,大小为1024,可读可写,共享,映射到这个fd上 p = mmap(NULL, 1024, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (p == MAP_FAILED) { printf("mmap failed\n"); close(fd); return -1; } // 拿到地址之后我们就可以像操作普通地址一样写数据,读数据了,例如memcpy,strcpy等等 memcpy(p, "hello world", sizeof("hello world")); // 读数据 printf("p = %s\n",p); // 最后释放这个映射 if (munmap(p, 1024) == -1) { printf("munmap failed\n"); close(fd); return -1; } close(fd); return 0;} 和基础使用例子一样,只是注释了修改文件大小的逻辑ftruncate(fd, 1024),这样新创建的文件大小就是0, 我们编译运行,如下图:Bus error 所以结论就是:创建映射区的文件大小为0,而指定的大小非零的时候会出现总线错误 2.创建映射区的文件大小为0,实际指定映射区的大小为0 得到的结果:无效的参数 3.如果打开文件时flag为O_RDONLY,mmap时PROT参数为PROT_READ|PROT_WRITE会怎样? 得到的结果:无效的参数 4.如果打开文件时flag为O_RDONLY(新文件不行,需要一个有文件大小的文件),mmap时PROT参数为PROT_READ会怎样? 得到的结果:在写数据的时候段错误 5.如果打开文件时flag为O_WRONLY(新文件不行,需要一个有文件大小的文件),mmap时PROT参数为PROT_WRITE会怎样? 得到的结果:没有权限,mmap在创建的时候需要读权限,mmap的读写权限应该小于等于文件的打开权限,文件至少必须要有读权限。(前提是MAP_SHARED 模式下) 6.文件描述符fd,在mmap创建映射区完成即可关闭,后续访问文件,用地址访问。 7.如果offset是1000会怎么样? 得到的结果:无效的参数,必须是4K的整数倍(这个跟MMU有关,MMU映射的最小单位就是4K) 8.对mmap越界操作会怎样? 得到的结果:段错误,mmap映射以页为单位,就是说得到的空间的大小是4096的倍数,举个例子就是你申请了10个字节,但系统会给你申请4096,因为不够一页(4k),如果你申请4097,那么会给你申请两个页,所以才会发现你申请10个空间却能写如20个或者4096以下的字节数也不会崩溃的原因。 9.对mmap++是否还能munmap成功 得到的结果:不能,无效的参数,首地址变了,munmap必须释放申请的地址 十、mmap父子进程间通信 #include #include #include #include #include #include #include #include #include // 全局变量 var int var = 100;int main(int argc, const char *argv[]){ int *p; pid_t pid; int ret = 0; int fd; // 打开一个文件 fd = open("temp", O_RDWR|O_TRUNC, 0644); if (fd < 0) { perror("open error"); exit(1); } // truncate文件大小 ftruncate(fd, 4); // 创建映射区 p = (int *)mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (p == MAP_FAILED) { perror("mmap error"); exit(1); } // 关闭fd,mmap创建成功后就可以关闭了,因为直接使用地址了,不需要fd了 close(fd); // fork一个进程 pid = fork(); if (pid == 0) // 子进程 { *p = 2000; var = 1000; printf("child *p = %d, var = %d\n", *p, var); }else{ // 父进程 sleep(1); // 休眠一秒,让子进程先执行 printf("parent *p = %d, var = %d\n", *p, var); wait(NULL); // 回收子进程 // 释放共享内存 if (munmap(p, 4) == -1) { perror("munmap error"); exit(1); } } return 0;} 结果: 结果发现p指向的地址的内容改掉了,而var没有被改掉(对于父子进程共享的东西是读共享,写复制) 十一、mmap无血缘关系的进程间通信 写进程,循环写这个结构体大小的数据到共享内存 #include #include #include #include #include #include #include #include #include struct student{ int id; char name[256]; int age; }; int main(int argc, const char *argv[]){ int fd; struct student stu = {0, "zhangsan", 18}; struct student *p; fd = open("temp", O_RDWR|O_CREAT|O_TRUNC, 0644); if (fd < 0) { perror("open error"); exit(1); } ftruncate(fd, sizeof(stu)); p = mmap(NULL, sizeof(stu), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (p == MAP_FAILED) { perror("mmap error"); exit(1); } close(fd); while (1) { // 循环写 memcpy(p, &stu, sizeof(stu)); stu.id++; sleep(3); } if (-1 == munmap(p, sizeof(stu))) { perror("munmap error"); exit(1); } return 0; } 读进程,循环从共享内存中读 #include #include #include #include #include #include #include #include #include struct student{ int id; char name[256]; int age; }; int main(int argc, const char *argv[]){ int fd; struct student stu = {0, "zhangsan", 18}; struct student *p; fd = open("temp", O_RDONLY, 0644); if (fd < 0) { perror("open error"); exit(1); } p = mmap(NULL, sizeof(stu), PROT_READ, MAP_SHARED, fd, 0); if (p == MAP_FAILED) { perror("mmap error"); exit(1); } close(fd); while (1) { // 循环读 printf("stu.id = %d, stu.name = %s, stu.age = %d\n", p->id, p->name, p->age); sleep(3); } if (-1 == munmap(p, sizeof(stu))) { perror("munmap error"); exit(1); } return 0; } 一个读端一个写端执行结果如下: 一个写端多个读端执行结果如下: 多个写端一个读端: 十二、匿名映射 前面我们每次使用共享内存时,都会创建一个文件,这样会造成垃圾文件,接下来我们使用unlink把创建的文件删除掉,创建完就删除这个文件:unlink(文件名) #include #include #include #include #include #include #include #include #include // 全局变量 varint var = 100;int main(int argc, const char *argv[]){ int *p; pid_t pid; int ret = 0; int fd; // 打开一个文件 fd = open("temp", O_RDWR|O_TRUNC, 0644); if (fd < 0) { perror("open error"); exit(1); } // TODO 添加了这句删除文件 ret = unlink("temp"); if (ret == -1) { perror("unlink error"); exit(1); } // truncate文件大小 ftruncate(fd, 4); // 创建映射区 p = (int *)mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (p == MAP_FAILED) { perror("mmap error"); exit(1); } // 关闭fd,mmap创建成功后就可以关闭了,因为直接使用地址了,不需要fd了 close(fd); // fork一个进程 pid = fork(); if (pid == 0) // 子进程 { *p = 2000; var = 1000; printf("child *p = %d, var = %d\n", *p, var); }else{ // 父进程 sleep(1); // 休眠一秒,让子进程先执行 printf("parent *p = %d, var = %d\n", *p, var); wait(NULL); // 回收子进程 // 释放共享内存 if (munmap(p, 4) == -1) { perror("munmap error"); exit(1); } } return 0;} 这样执行完成之后,那个临时文件就没了 又要open,又要unlink的好麻烦,有没有更方便的方法。答案是有的。可以直接使用匿名映射来代替,其实linux系统给我们提供了创建匿名映射区的方法,无需依赖一个文件即可创建映射区,同样需要借助标志位flags来指定。 使用MAP_ANONYMOUS(或MAP_ANON),如: int *p = mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); 需要注意的是,MAP_ANONYMOUS和MAP_ANON这两个宏是linux操作系统中特有的,类UNIX系统中无该宏定义,可以使用如下两步来完成匿名映射区的建立 fd = open("/dev/zero", O_RDWR);p = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, fd, 0); linux匿名映射的例子如下:只能用于有血缘关系的进程间通信 #include #include #include #include #include #include #include #include #include // 全局变量 var int var = 100; int main(int argc, const char *argv[]){ int *p; pid_t pid; int ret = 0; // 创建映射区-----TODO 匿名映射,大小随便指定,权限随便指定,fd用-1 p = (int *)mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); if (p == MAP_FAILED) { perror("mmap error"); exit(1); } // fork一个进程 pid = fork(); if (pid == 0) // 子进程 { *p = 2000; var = 1000; printf("child *p = %d, var = %d\n", *p, var); }else{ // 父进程 sleep(1); // 休眠一秒,让子进程先执行 printf("parent *p = %d, var = %d\n", *p, var); wait(NULL); // 回收子进程 // 释放共享内存 if (munmap(p, 4) == -1) { perror("munmap error"); exit(1); } } return 0; } 类unix的例子 #include #include #include #include #include #include #include #include #include // 全局变量 varint var = 100;int main(int argc, const char *argv[]){ int *p; pid_t pid; int ret = 0; int fd; // 打开一个文件 TODO /dev/zero fd = open("/dev/zero", O_RDWR|O_TRUNC, 0644); if (fd < 0) { perror("open error"); exit(1); } if (ret == -1) { perror("unlink error"); exit(1); } // 创建映射区 flags 加 MAP_ANONYMOUS p = (int *)mmap(NULL, 4, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, fd, 0); if (p == MAP_FAILED) { perror("mmap error"); exit(1); } // 关闭fd,mmap创建成功后就可以关闭了,因为直接使用地址了,不需要fd了 close(fd); // fork一个进程 pid = fork(); if (pid == 0) // 子进程 { *p = 2000; var = 1000; printf("child *p = %d, var = %d\n", *p, var); }else{ // 父进程 sleep(1); // 休眠一秒,让子进程先执行 printf("parent *p = %d, var = %d\n", *p, var); wait(NULL); // 回收子进程 // 释放共享内存 if (munmap(p, 4) == -1) { perror("munmap error"); exit(1); } } return 0;}
01电路简化的基本原则 初中物理电学中的复杂电路可以通过如下原则进行简化: ☀第一:不计导线电阻,认定R线≈0。有电流流过的导线两端电压为零,断开时开关两端可以测得电压(电路中没有其他断点)。 ☀第二:开关闭合时等效于一根导线;开关断开时等效于断路,可从电路两节点间去掉。开关闭合有电流流过时,开关两端电压为零,断开时开关两端可以测得电压(电路中没有其他断点)。 ☀第三:电流表内阻很小,在分析电路的连接方式时,有电流表的地方可看作一根导线。 ☀第四:电压表内阻很大,在分析电路的连接方式时,有电压表的地方可视作断路,从电路两节点间去掉. ☀第五:用电器(电阻)短路:用电器(电阻)和导线(开关、电流表)并联时,用电器中无电流通过(如下图示),可以把用电器从电路的两节点间拆除(去掉)。 ☀第六:滑动变阻器Pa段被导线(金属杆)短接不工作,去掉Pa段后,下图a变为图b。 ☀第七:根据串、并联电路电流和电压规律“串联分压、并联分流”分析总电流、总电压和分电流、分电压的关系。 ☀第八:电流表和哪个用电器串联就测哪个用电器的电流,电压表和哪个用电器并联就测哪个用电器的电压。判断电压表所测量的电压可用滑移法和去源法。 ☀第九:电压表原则上要求并联在电路中,单独测量电源电压时,可直接在电源两端。 一般情况下,如果电压表串联在电路中,测得的电压是电源两端电压(具体情况见笔记)。电流表直接接在电源两端会被烧坏,且让电源短路,烧坏电源。 ☀第十:如果导线上(节点之间)没有用电器(开关,电流表除外),那么导线上的各点可以看做是一个点,可以任意合并、分开、增减。(此法又称节点法)例如: 02电路简化步骤 ☀第一步:按照题目要求将断开的开关去掉,将闭合的开关变成导线。 ☀第二步:将电流表变成导线(视具体情况也可保留)。 ☀第三步:去掉电压表。 ☀第四步:合并(或者换位)导线上的节点。(此步骤在电路中用电器比较多,且相互纠结时,采用) ☀第五步:画出等效电路图,判断各用电器是串联还是并联。 ☀第六步:在原电路中利用原则七、八判断电流表和电压表各测量哪个用电器的电流和电压。 ☀第七步:将电压表和电流表添加到等效电路图中,分析各电流表和电压表示数之间的关系。(利用原则七) 03经典例题选讲 ☀例1:在如下电路图中,开关S闭合后,电压表V1的示数是2.5V,V2的示数是1V,如果A2的示数是0.2A,那么A1的示数是多少?试求两只灯泡两端的电压。 分析:第一步:将开关变成导线;第二步:将电流表变成导线;第三步将电压表去掉。第四步(略)第五步:判断用电器连接方式 很显然,电路中两个灯泡是串联的。 第六步:根据原则四,知道电压表V2处断开,所以没有电流从A1流过,示数为零;根据滑移法知道V1和电源并联,测电源两端电压。V2和L2并联,测L2两端电压。 第七步:等效电路图如下: 根据等效电路图,可知所求I1=I2=0.2A U1=2.5V-1V=1.5V U2=1V☀例2 :如图示,开关s闭合后下列各电压表示数的关系是,各电流表示数之间的关系是___。 分析:第一步:把开关变成导线;第二步:把电流表变成导线;第三步:去掉电压表;第四步(略);第五步:判断各用电器的连接方式: 第六步:根据原则七和原则八以及滑移法或去源法判断电流表和电压表各自所测量的对象。①在原电路中,去掉电压表,可以发现电流表A1和A2都与灯泡串联,所以电流表示数相等;②用滑移法可以判断出V1测L1两端的电压,V2测电源两端的电压;V3测L2两端的电压。 第七步:等效电路图如下: ☀例3 : 电路开关闭合后,v1、v2、v3的示数分别是8V、9V、4V,则L1、L2、L3两端的电压各是多少 所求的电压关系式为:U2=U1+U3 I1=I2解:根据“十原则,七步骤”可以得到该电路的等效电路图如下: 从等效图可以得到如下方程组:UL1+UL2=8VUL2+UL3=9VUL3=4V解得:UL1=3v UL2=5v UL3=4V ☀例4:如图所示,已知两只灯泡L1和L2是串联的,则在①、②和③三个电表中(电流表或电压表)判断正确的是( ) A. ①是电流表,②和③是电压表;B. ①和③是电压表,②是电流表;C. ①和②是电流表,③是电压表;D. ①②和③都是电流表 分析:本题可用排除法解答。将A答案的各表填入 三个位置中,根据“十原则,七步骤”电路图简化为: 很明显,不符合题意。 将B答案各表填入图中,电路可简化为: 这种填法符合题意。 把C答案各表填入电路中,电路L1被断路,简化后的电路图和A答案相同,不合题意。把D答案各表填入图中,电源短路,两个灯泡没有电流流过,不合题意。所以选择答案B。 声明 本号所刊发文章仅为学习交流之用,无商业用途,向原作者致敬。因某些文章转载多次无法找到原作者在此致歉,若有侵权请联系小编,我们将及时删文或者付费转载并注明出处,感谢您的支持! (来源:网络,版权归原作者)
引言:天线调谐开关也叫孔径调谐开关,关于什么是孔径调谐,会在后续其余章节讲到。随着消费场景的天线越做越小巧,天线尺寸缩小将导致天线效率降低,更容易受天线周围介质变化的影响,介质变化引起的瞬态响应会造成天线频率响应漂移。
在很多电子产品的电路板中都能经常见到如下的图标:今天核桃就和大伙理一理这些电路板上的图标到底表示啥意思。(1)防静电标志 防静电标志在电子制造业中非常重要,因为静电给电子器件带来的损伤是非常严重的,特别是集成电路,造成的损失是无法估算的,防静电标志旨在提醒工作人员在接触电路板时请做好防范措施。 (2)WEEE 这个WEEE图标的含义主要是提醒用户或者制造商在废弃板卡时需要正确的回收或者处理,不能随手就丢弃在垃圾桶里,以免对环境造成污染。(3)无铅标识 这个图标表示的是电路板在制作的过程中没有加入含铅成分的材料。以减少对环境和人体的危害。很多国家对电路板和器件都明确表示需要不含铅的才能进行销售。(4)FCC,CE FCC是美国联邦通信委员会(Federal Communications Commission)的缩写,负责管理无线电频率的使用和电子产品的电磁兼容性。FC图标表示该电子产品已经通过了FCC的认证,符合电磁兼容性和射频干扰的标准。CE是欧盟对产品进入欧洲市场的基本安全要求。CE标志表示产品符合欧盟的指令和标准,包括低电压指令(LVD)和电磁兼容性指令(EMC)。CE认证确保产品在使用过程中不会对用户和环境造成危害,并且符合安全、健康、环保等要求(5)RoHS、RU RoHS全称是《关于限制在电子电气设备中使用某些有害物质的指令》(Restriction of Hazardous Substances Directive),这是一项由欧盟颁布的强制性环保标准,旨在限制在电子电气设备制造过程中使用10种有害化学物质,包括铅(Pb)、汞(Hg)、镉(Cd)、六价铬(Cr(VI))、多溴联苯(PBB)、多溴二苯醚(PBDE)、邻苯二甲酸二(2-乙基己基)酯(DEHP)、邻苯二甲酸丁苯甾酯(BBP)、邻苯二甲酸二丁酯(DBP)和邻苯二甲酸二异丁酯(DIBP)。PCB上含有这个图标说明该板卡通过了检测,板卡在制作过程中的有害物质控制符合欧盟环保法规要求。RU是美国和加拿大的认可部件标志,主要针对的是电子元器件。这个标志的商业权属于美国保险商实验室(UL)。也就是说你的板子上使用的器件都是要经过UL认证授权之后才能在板卡上打上这个标识。(6)高压图标 很明显,这个图标的意思就是提醒操作人员,电路板此处有高压,注意人身安全。其实这类的图标还有很多很多,以上只是例举出常见的!好了,今天就先写到这吧!