前阵子一个朋友发来一份 300 多页的原理图让我帮忙 review,打开 OrCAD 的那一刻,我整个人是崩溃的。整份图纸从第一页到最后一页完全拉通,电源模块在 page 5,MCU 在 page 64,接口电路在 page 210,不同模块之间的网络就像蜘蛛网一样横跨几十页。这不是个例——很多工程师从接触原理图开始就习惯了"把所有东西铺在一层图上",直到项目大到改一处要翻半天图纸,才意识到问题的根源不是图纸多,而是设计没有分层。
Cadence OrCAD Capture 里的层次化设计(Hierarchical Design),本质上就是把一个大系统拆成若干功能模块:根图管架构,子图管实现,信号通过层级端口连接。说白了,就是给原理图做"目录和章节"。这篇文章我会从概念、实操到避坑,把层次化设计在 OrCAD 里的用法完整过一遍,后面附上我自己踩过的坑和总结的排查思路,希望能帮你少走几段弯路。
1. 为什么层次化设计能治好原理图"烂摊子"
很多人以为层次化设计是 PCB 工程师的专利,其实不对。层次化设计的核心价值在原理图阶段就已经体现了,它解决的问题不是"板子上怎么布局",而是"几百个器件、几千个网络怎么组织才不失控"。
1.1 平坦设计的三宗罪
先说最常见的平坦设计(Flat Design)。所谓平坦,就是不管功能怎么分,所有原理图页都平铺在一个层级里。小项目没事,一旦设计规模上来,问题一个接一个地冒出来。
第一个问题是图纸间逻辑割裂。一个电源管理信号从 source 到 sink 可能要跨七八页图纸,你只能靠 off-page connector 上的页码标注去猜"下一页在哪儿"。改一个上拉电阻,得同时确认它在 page 23 和 page 87 的两个副本是不是同步改了。第二个问题是复用极难。下个项目想复用这个电源模块?复制粘贴一整块区域吧,几十个网络、几十个位号,粘完还得手工改位号、改网络名,稍有不慎就漏一个。第三个问题是团队协作效率低。三个人同时改一份 50 页的图纸,稍微有点交叉就得互相等,合图的时候冲突一堆。
1.2 层次化设计带来的结构性优势
层次化设计解决的就是这些问题。它的思路很朴素:把系统按照功能划分成模块,每个模块放在独立的子图里,根图只负责表达"模块之间怎么连接"。
这样做有几个直接的好处。一是可读性大幅提升。review 原理图的人先看根图,一眼就能看到系统由哪些功能模块组成,看具体细节再逐层下钻,不用在几百页里来回翻。二是复用变成"搭积木"。一个写好的电源子图,在根图里放三次就是三个电源模块,改子图内容,所有实例同步更新。三是多人协作互不干扰。每个人负责一个子图,改自己的模块,最后在根图里把接口对上就行。
从我个人的经验看,项目超过 10 页原理图,或者电路明显分成多个功能域(电源、主控、接口、传感器驱动……),就值得考虑层次化。只画一块小板、几十个元件,用层次化反而显得多余,徒增管理成本。
1.3 一个反直觉的结论
有人会担心:层次化是不是会让原理图变得更复杂?恰恰相反。层次化增加的只是最开始的"架构设计"环节,但省掉的是后面无数次"翻页找网络"的时间。我自己经手的一个项目,从平坦改造成层次化之后,DRC 报错数量直接降了一个量级,因为很多"跨页连接漏了"的问题在结构上就不存在了。这才是层次化设计真正的价值——它不是让图纸变少,而是让图纸上的每个元素都有确定的位置和归属。
2. 核心概念与图纸层级:先搞清楚块、端口和复用块再说实操
在 OrCAD Capture 里做层次化设计,先要弄清楚几个核心概念。这些名词在菜单里经常出现,但手册里的解释偏学术,我说点人话版本。
2.1 Root Schematic 与 Child Schematic
Root Schematic 是根图,也就是整个设计的入口。它就像书的目录页,描述的是"系统由哪几个模块组成"。Child Schematic 是子图,对应根图下方的某个具体模块电路。一个项目可以有多个层级的子图,比如"根图 -> 电源模块 -> 电源模块内部的 DC-DC 部分 -> ...",这个嵌套结构没有硬性限制,但我一般不推荐超过三四层,太深了下钻时容易迷路。
2.2 Hierarchical Block、Hierarchical Pin 与 Hierarchical Port
这是三个最容易混淆的名字,我当年也绕了一阵子。
Hierarchical Block(层次块)是你在根图上放置的矩形块,它就是"指向子图的链接"。一个块对应一个子图,双击这个块,Capture 会把视图推入(push into)到子图内部。块的外框上会显示出一些引脚,这些引脚叫 Hierarchical Pin,它们是子图和父图的接口。
Hierarchical Port(层次端口)是子图里放置的端口符号。你在子图里放一个叫 VOUT 的 Hierarchical Port,回到根图刷新一下,对应块的引脚上就会出现一个叫 VOUT 的 Hierarchical Pin。换句话说,子图里的 Hierarchical Port = 块上的引脚,是一体两面的东西。
用生活化的类比:根图是一栋楼的楼层平面图,每个 Block 是一个房间的门;Hierarchical Port 是房间里的门牌号,你在房间里挂一个"408"的门牌,平面图上的门就会自动标上 408。
2.3 和 Off-Page Connector 的区别
层次化设计里还有一个老熟人:Off-Page Connector(跨页连接符)。很多新手分不清它和 Hierarchical Port 的区别。
Off-Page Connector 的作用范围是"同一层级内的不同图纸之间"。比如你的电源子图内部画了 3 页图纸,页和页之间的信号就靠 Off-Page Connector 连接。而 Hierarchical Port 的作用范围是"父子层级之间"。父图上的 Block 引脚要和子图里的 Hierarchical Port 配对,外部的信号才能进入到子图内部。
这两者本质上都不产生物理连接,只是告诉 Capture "这些网络是同一个网"。但如果混用,比如在子图里用 Off-Page Connector 试图把信号引到父图,Capture 不会认为这个信号连到了父图的网络上,这是很多连接问题的根源。等到了第 5 章讲交叉引用的时候,我再详细展开这个坑。
2.4 Primitive 属性:看起来不起眼,影响却很大
创建 Hierarchical Block 时有一个属性叫 Primitive,可选项是 Default、Yes、No。它控制这个块在后续工具里被看成"一个整体元件"还是"一个可以展开的层次结构"。
我的建议是保持默认的 Default 或直接选 No。如果选了 Yes,Capture 会把这个 Block 当作类似封装好的封闭元件处理,在 PSpice 仿真时不会把它展开成子电路,双击也进不了内部图纸。很多人在做仿真时发现模块内部电路没有参与仿真,十有八九就是这个属性被设错了。
3. 两种搭法,一条主线:层次化原理图的完整创建流程
搞清楚概念之后,实际操作其实就一条主线:先有子图,再在父图放置指向子图的 Block,然后通过端口把信号串起来。区别只在于你是"先画子图"还是"先放块"。这两种方式对应 OrCAD 里的自顶向下(Top-Down)和自下而上(Bottom-Up)。
3.1 自顶向下:先规划架构,再填充细节
这种方式适合设计初期架构已经清晰的情况。在 Project Manager 窗口里,选中工程下的 .dsn 文件,右键选择 New Schematic,给它起个名字,比如 PWR。这一步就创建了一个空子图。
接着打开根图,在菜单栏选择 Place > Hierarchical Block。弹出的对话框里需要填几个关键项:
- Reference:给块起个实例名。这里强烈不建议用默认的 U1、U2,最好用模块缩写,比如 PWR、MCU、IF。后面位号管理那一章我会解释为什么。
- Primitive:保持 Default 或 No。
- Path and filename:这里选择刚才新建的 PWR.dsn。很多人会犯一个错,填成了 .opj 工程文件或者干脆留空,结果是后面双击块根本进不去子图。
放置块之后,双击这个块,Capture 会进入到 PWR 子图内部。这时候子图是空的,先放几个 Hierarchical Port(Place > Hierarchical Port),把它们命名为 VIN、VOUT、GND、EN 等,定义好方向。然后再开始画具体电路。
画完回到根图(工具栏上的 Pop 按钮或者右键选择 Return to Root),你会看到刚才的 Block 上已经自动长出了对应名称的引脚。接下来就是在根图里连线:把电源符号连到 VIN 引脚,把控制信号连到 EN 引脚。
3.2 自下而上:先把模块调通,再做系统集成
另一种情况是模块电路已经验证好了,或者团队分工时各人先画好自己的部分。这时候用 Bottom-Up 更顺手。
先在工程里新建一个 Schematic 作为子图,把内部电路完整画好,包括 Hierarchical Port。然后在根图选择 Place > Hierarchical Block,在 Path and filename 里选择这个已经画好的 .dsn 文件。放置后,Capture 会自动扫描子图里的 Hierarchical Port,生成对应的引脚。省掉了手工建块的步骤。
还有一个更快的技巧:在 Project Manager 里直接把子图拖放到根图图纸上,Capture 会自动创建对应 Block,端口也会自动生成。这个操作很多人不知道,实测非常省事。
3.3 两种方式怎么选
我的习惯是混合着用。系统架构清晰时,先用自顶向下把框架搭好,每个 Block 对应一个子图,子图内部再慢慢填。填的过程中如果发现某个 Block 内部还需要再拆成多个子模块,就继续在子图里创建下一层 Block。
判断标准很简单:子图内部如果预计会画超过一页 A4 的原理图,或者内部明显还有独立功能域,那就继续分层。如果子图很小,保持平坦就行。
3.4 实操中的三个关键细节
第一,放置 Block 时要对齐网格,否则后面连线端口对不齐。第二,Block 的名字不要修改得太随意,因为网表导出时它可能成为模块引用的标识。第三,子图里的 Hierarchical Port 命名要统一规范,大小写也要一致,OrCAD 的网表对某些字符(比如中文、空格)支持不太好,端口名和网络名最好只用字母、数字和下划线。
4. 位号管理:层次化设计里最容易被绕晕的一环
位号问题是我见过大家在做层次化设计时翻车最多的地方。先说一个经典场景:你在根图里放了三份电源模块,都指向同一个 PWR.dsn。进入其中一个子图,元件位号是 U1、R1、R2、C1;进入另一个子图,看到的位号居然也是 U1、R1、R2、C1。是不是出 bug 了?
不是。这正是层次化设计的"逻辑复用"特性——多个实例共享同一个子图定义。在仿真阶段这没问题,因为仿真器能通过实例路径区分它们。但在做 PCB 网表或导出 BOM 时,如果所有实例都带相同的 U1、R1,就必须处理位号冲突。
4.1 锁定位号:别再让 Annotate 乱动你的设计
很多人新加了一个元件,然后跑一遍 Tools > Annotate,结果发现整板位号全被重排了,改过的固定位号也被打乱。根本原因在于 Annotate 对话框里选了 Unconditional Reference Update(无条件更新),它会重置整个设计的位号。
我的处理方式分两种情况。刚画完还没出过图,可以用无条件更新做一次全图编号,但只做这一次。项目进入正常迭代后,新增元件一律用 Incremental Reference Update(增量更新)。增量更新只给那些没有位号(显示为 R?、C?)的元件分配位号,对已有位号完全不动。这比手动一个个改省心得多。
如果你有某些位号必须铁定不变,还有一个保险手段:在属性编辑器里选中对应元件的 Reference 单元格,右键选择 Lock。锁定后的元件即使执行无条件更新也不会被改。这个功能在平坦设计里同样有用,但在层次化里价值更大,因为你要保护的不只是一个元件,而是一整个模块的位号体系。
4.2 位号前缀:每个模块一套字母,排错快十倍
强烈建议给不同模块的元件设置不同的位号前缀。默认情况下,电阻位号都是 R1、R2,电容都是 C1、C2。但你可以把它们改成 RPWR1、CPWR1 这种带模块标记的形式。
操作上不用一个个改。在原理图页面里选中需要修改的元件(可以框选),打开属性编辑器(Edit > Properties),找到 Reference 列,统一把 R? 改成 RPWR?,C? 改成 CPWR?。下次 Annotate 时,这些元件就会自动按 RPWR1、RPWR2 的规律编号。
这个习惯在层次化设计里尤其香。因为不同模块共用一位工程师的思路很常见,如果位号都是 R1、R2,排查问题根本分不清是电源模块的电阻还是接口模块的电阻。加了前缀之后,BOM 和网表一看就知道归属。不过要注意,前缀别太长,Allegro 里的一些符号名有长度限制,太长的前缀可能在导入 PCB 时报错。
4.3 复用模块的位号策略:三个方案怎么选
回到最初的问题:三个实例共享同一子图,位号怎么办?根据项目用途,我通常有三种处理方案。
如果这个原理图只是做方案展示或 PSpice 仿真,三个实例内部位号重复无所谓,仿真器会按"PWR_A/U1"和"PWR_B/U1"来区分实例,不会冲突。如果这个设计后续要出 PCB,那必须在某个阶段把实例"唯理化"。Capture 里可以右键 Block,选择 Uniquify(具体菜单名因版本略有差异,但思路一致),把共享的子图拆成多个独立的物理子图,每个实例拥有自己的位号。执行完 Uniquify 后,不同模块就可以互不干扰地重新编号了。
第三个方案比较偷懒,但实际也有效:先给要复制的 Block 用 4.1 节的锁定功能把位号锁一遍,复制新块后进入新块手工整体重排位号,或者让 Annotate 的增量模式只处理新增部分。这种方式适合模块数量少、位号冲突好处理的场合。
我个人推荐第一、二种组合用:验证阶段保持逻辑复用,确定要出 PCB 前做一次 Uniquify 和全图重排。
5. 层级之间怎么通信:端口规则与交叉引用的坑
层次化设计的连通性完全靠 Hierarchical Port 和 Hierarchical Pin 的配对来保证。这个环节的规则如果不重视,后面 DRC、网表、仿真都会出来一堆莫名其妙的报错。
5.1 端口方向的设置
放置 Hierarchical Port 时,属性面板里有一个 Direction 选项:Input、Output、Bidirectional、Passive。这个方向必须和实际信号方向一致,否则 DRC 会报警,而且在仿真时也会导致信号方向判断错误。
举个例子,电源模块子图里 VIN 这个端口是输入方向的,如果你在子图里把 VIN 定义成了 Output,仿真器会认为电流方向反了,收敛出问题也常见。GND 和 VCC 这类全局电源如果通过端口连接,一般方向设为 Passive 更合适。不过很多老工程师的做法是,电源和地根本不用 Hierarchical Port 传递,直接每个子图里放电源符号的全局网络连接,这样省事且不容易出错。这也符合 OrCAD 里 Power Symbol 的设计逻辑——同名电源符号全局拉通。
5.2 网络命名必须完全一致,别指望"就近连接"
层次化设计里最常见的连接错误,是子图内部用网络别名(Net Alias)连了一个信号,名字和块上的引脚名不一样。很多新手误以为只要物理上挨着或者画个线就应该连上。但在 Capture 里,父图连到 Block 引脚的信号,和子图内部网络名的对应关系是精确匹配的。
也就是说,块上引脚叫 VOUT,子图内部就必须有一根网络名也是 VOUT 的线或者 Net Alias。名字不匹配,电平就断了。这个问题看原理图的时候不容易发现,因为两个内容各自在自己的图纸里看着都很正常,直到导网表时才提示某个网络悬空。所以每次创建或修改端口之后,我建议立刻在根图刷新(菜单 Place > Update Hierarchical Ports,或右键 Block 刷新),视觉确认引脚数量对不对。
5.3 交叉引用报错的完整排查链路
热词里有一条"cadence 添加 intersheet references 报错",这个我在项目里确实踩过。所谓 Intersheet References,就是 off-page connector 附近的页码标注功能——它在每个 off-page 符号旁边生成"连到第几页"的小字,方便纸质阅读。
这个功能本身没问题,但在层次化设计里,它有一个很隐蔽的前提:它只计算同一层级内 off-page connector 的连接关系。如果把跨层级的信号也用 off-page 来表示,或者在一个既有 hierarchical port 又有 off-page connector 的网络里混用,Intersheet References 计算时就会找不到对应关系,然后报错。
我的排查链路是这样的,按顺序走基本 5 分钟内能定位:
- 复制报错信息,定位到出问题的 sheet 和网络名。
- 检查该网络在层级里的角色:它到底是跨子图通信(应该用 Hierarchical Port + Block Pin)还是子图内跨页通信(用 Off-Page Connector)?
- 混用了的话,先把多余且语义不明的 off-page connector 删掉,统一保留一种连接方式。
- 检查 hierarchical port 是否都有对应的 block pin。有时候你删改了子图里的端口,父图的 Block 上还保留着旧引脚没刷新,这时候执行 Update Hierarchical Ports,让块引脚同步。
- 删掉那些确实不再使用的孤立端口和悬空网络(画图过程中很容易残留,名字都改了但老的网络还在)。
- 重新执行 Intersheet References 生成,看报错是否消失。
这个问题的核心原因就一句话:要么是跨层级信号用了 off-page connector,要么是父图 block 引脚没有刷新导致端口不一致。对照这个次序排查,基本都能解决。
5.4 信号命名规范:小细节大作用
最后说一下网络命名。层次化设计的信号跨层流动,命名必须一眼能看出归属和含义。我常用的规范是按功能前缀分组:例如 3V3_MAIN、3V3_IO、I2C_SCL_MCU、USB_DP、PWR_EN、PWR_PG。这样在任何一层子图里看到网络名,就能判断它是哪个域的信号、大概从哪里来。
负逻辑信号建议统一用 RESET# 这种写法(有些团队用 /RESET,但 OrCAD 里#对网表兼容性更好)。网络名不要用中文,尽量避开特殊符号,防止网表阶段报编译类错误。
6. 层次化原理图的检查、输出与 PCB 联动
层次化设计做完,不等于可以直接出图。从 DRC 检查到导出 PDF,再到导入 Allegro,每一步都有一些只属于层次化设计的注意事项。
6.1 层次化 DRC 重点看什么
Tools > Design Rules Check 是每个设计出图前的必选项。在层次化设计里,尤其要关注报告里 HRC 开头的错误,它们专门对应层级相关的问题。常见的有三种:
- Unconnected Hierarchical Port:子图端口定义了但没连到内部的网络。说白了就是有门但没有路,信号进不去。
- Duplicate Reference:两个模块内部位号重复。如果还没有 Uniquify,这属于预期中的提示,可以根据项目阶段决定忽略还是处理。
- Port Direction 不匹配:比如两个模块的块引脚一个方向是 Output、一个是 Input,但你在根图里把两个 Output 直接连在一起,DRC 就会报冲突。
我的习惯是,每次进入一个新设计阶段(比如导网表前、投板前)跑一遍 DRC,跑完把 HRC 相关的错误单独复制到一个文本里逐条看完再清除。别偷懒用"Clear all"一把清掉,很多隐患就是这么被掩盖的。
6.2 导出 PDF 的字体与搜索问题
热词里有"orcad x professional导出的pdf文件无法搜索里面的位号",这个问题的根源几乎都在导出选项上。Capture 默认导出 PDF 时,如果选择了把文字转成曲线或使用系统不支持嵌入的字体,PDF 里的位号文字就变成图形对象,自然没法用搜索功能查询。
在导出 PDF 的选项对话框里,找到字体相关设置,选择嵌入 TrueType 字体而不是转曲线,导出来的 PDF 就能正常搜索位号。另外一个相关技巧:层次化设计导出 PDF 时,可以设置按层级生成书签,这样别人拿到 PDF 可以直接从书签跳到某个模块,不用翻几十页找。
说到 PDF,还有一个细节。在层次化设计中,如果你在某个子图里放了 off-page connector 且生成了交叉引用,导出 PDF 时页码标注在哪里、字号是多少,可能会影响可读性。我一般会在导出前放大图纸预览确认一下页码标注没有挤在一起,再批量输出。
6.3 BOM 与网表:层次化如何"降维"
层次化设计导 BOM 时,Tools > Bill of Materials 对话框会问输出模式。默认平面模式(Flat)会把所有子图里的元件都拉平,导出的 BOM 是一份全板清单。如果你需要按模块分开看,可以考虑按层级导出,或者导完之后在 Excel 里按位号前缀分列。
我一直用平面模式导出全 BOM,然后借助位号前缀做筛选。这比在 Capture 里维护多张 BOM 省心得多。
网表导出到 Allegro(Tools > Create Netlist)的原理类似:最终网表是平面展开的,不会保留层次结构。有些工程师第一次用层次化设计,导完网表发现 Allegro 里所有元件都平铺了,以为哪里设置错了。其实这是正常行为,层次化只是原理图阶段的组织方式,PCB 布线阶段所有元件始终在同一个物理面上。
6.4 与 Allegro 关联失败的常见原因
"We 在设计时默认 Capture 和 Allegro 是同一家,关联应该无缝。但实际中'can't launch Allegro'这类问题很常见,大部分原因是 Capture 里 Allegro 可执行文件路径没有正确设置。在 Capture 的 Options > Preferences 里找到 Allegro 路径配置,把 allegro.exe 的完整路径填进去即可。另一个老生长谈的问题是工程路径不能有中文和空格,所有文件尽量放在纯英文路径下,否则网表传输很容易出怪毛病。"
6.5 常见问题排查速查表
整理了一张速查表,覆盖我在层次化设计里遇到的高频问题,按这个表排查基本能覆盖 80% 的场景。
| 现象 | 最常见原因 | 处理方法 |
|---|---|---|
| 双击 Block 进不去子图 | Path and filename 填错或留空 | 重新指定正确的 .dsn 文件 |
| 子图端口改了,块引脚不变 | Build 未刷新 | 右键块或者菜单更新 Hierarchical Port |
| Annotate 后位号全部乱掉 | 用了 Unconditional Update | 固定位号先 Lock,普通新增用 Incremental |
| 三个复用模块在网表里位号重复 | 还未 Uniquify,物理复用准备不充分 | 对实例执行 Uniquify 后重排 |
| 同一信号在两个模块内名字不同 | Net Alias 命名不一致 | 对标信号命名规范统一网络名 |
| Intersheet References 报错 | off-page 与层次端口混用 | 按 5.3 的流程逐条排查 |
| 导出 PDF 无法搜索位号 | 字体被转成曲线 | 改为嵌入 TrueType 字体 |
| 网表导入 Allegro 报错 | 路径含中文/空格 | 工程和输出路径改为纯英文 |
| Allegro 无法启动 | 可执行文件路径未配置 | Options 里填写 allegro.exe 路径 |
最后再分享一个这些年养成的习惯:每次开始一个层次化设计前,先在纸上画一张模块框图,标清楚每个 Block 的跨模块信号名,然后才打开 OrCAD 动手。这个框图不需要多精细,主要用来统一信号命名和端口方向。等图纸画完,这张纸就成了团队 review 和 debug 时的参照地图。层次化设计真正难的不是操作,而是设计者心里有没有一张清晰的层级地图。