1. 从一张原理图到一堆封装这个助手到底在解决什么问题画过ADAltium Designer的人都知道原理图本身其实不难难的是原理图画完之后那一堆封装。一个中等规模的板子七八十个元件每个元件都要对应一个PCB封装电阻电容还好说最怕的是那种异形连接器、模块、传感器引脚间距不规则焊盘尺寸还得自己算。手动一个个建封装一个下午就没了眼睛还容易花。这个“AD原理图模拟操作助手”本质上是一套跑在Altium Designer里的脚本工具集核心目标就一个把原理图里已经画好的元件信息自动转换成对应的PCB封装减少重复劳动。它不是一个独立的软件而是依附于AD的脚本系统通过Delphi Script或者VBScript来操作AD的API读取原理图里的元件参数然后按照预设规则生成封装库文件。适合谁用如果你经常画板子手里有一堆常用元件但懒得一个个建封装或者你团队里有统一的封装规范但每次都要手动对齐这个思路就值得参考。哪怕你不直接用这套脚本理解它的实现逻辑也能帮你理清AD二次开发的基本套路。我最早接触AD脚本是因为一个项目里用了四十多个不同规格的排针和连接器每个都要建封装建到第十个的时候我就想这东西能不能让电脑自己干。后来翻AD的API文档发现它提供了完整的脚本接口可以操作原理图对象、PCB对象、库文件对象于是就有了这套东西的雏形。2. 整体设计思路为什么选择脚本而不是手动建库2.1 手动建封装的痛点在哪里先说手动建封装的流程打开PCB Library新建一个元件放焊盘调间距画丝印设置参考点保存。单个元件大概三到五分钟复杂一点的十几分钟。听起来不多但乘以一百个元件就是五到八个小时。而且手动操作有个致命问题一致性差。今天建的焊盘尺寸和昨天建的差0.1mm丝印线宽今天用0.15明天用0.2最后板子做出来发现有些元件焊盘偏小焊接不良。更麻烦的是原理图里的元件信息和封装是分开管理的。你在原理图里改了元件参数比如把电阻从0603改成0805封装不会自动跟着变得手动去改。项目大了之后这种同步工作极其烦人。脚本方案的核心优势就是批量和一致。你定义好规则比如“所有0603电阻的焊盘尺寸是1.0mm x 0.6mm间距1.6mm”脚本就严格按照这个规则生成一百个和一万个都一样。而且脚本可以读取原理图里的元件参数自动匹配对应的封装模板改一个参数重新跑一遍脚本所有封装同步更新。2.2 脚本方案的技术选型AD支持多种脚本语言最常用的是Delphi Script和VBScript。Delphi Script功能更强能直接调用AD的完整API但语法相对复杂VBScript上手快适合简单操作但有些高级功能受限。这套助手用的是Delphi Script为主因为需要操作PCB库文件的底层对象VBScript在这方面能力不够。脚本的运行方式有两种一种是作为AD的脚本项目Script Project在AD内部直接运行另一种是编译成DLL通过AD的RunScript接口调用。前者适合开发和调试后者适合分发给不熟悉脚本的同事使用。我建议开发阶段用脚本项目稳定之后再考虑打包。注意AD的脚本API在不同版本之间有差异AD 17到AD 23的接口基本兼容但AD 10以前的版本缺少一些关键方法。如果你用的是老版本部分功能可能需要降级处理。2.3 整体架构拆解这套助手的架构分三层第一层是原理图解析层负责读取当前打开的原理图文档遍历所有元件提取元件的位号、注释、参数比如阻值、容值、封装名称。这一层的关键是正确识别元件的类型电阻、电容、IC、连接器不同类型的元件走不同的封装生成逻辑。第二层是规则映射层维护一个映射表把元件参数映射到封装模板。比如“R-0603”映射到“RESC0603”封装模板“C-0805”映射到“CAPC0805”模板。这个映射表可以放在一个独立的配置文件里方便修改而不需要动脚本代码。第三层是封装生成层根据模板和参数在PCB库文件里创建新的封装放置焊盘、绘制丝印、设置3D模型如果有的话。这一层直接调用AD的PCBLib API是技术难度最高的部分。三层之间通过数据结构传递信息原理图解析层输出一个元件列表规则映射层输出一个封装定义列表封装生成层根据定义列表逐个创建封装。这种分层设计的好处是每一层可以独立修改比如你想换一种命名规则只改映射层就行不用动解析和生成逻辑。3. 核心细节解析脚本操作AD的关键技术点3.1 如何读取原理图里的元件信息AD的原理图文档对象模型里元件是通过ISch_Component接口表示的。遍历原理图里所有元件的核心代码如下procedure IterateComponents; var SchDoc : ISch_Document; Iterator : ISch_Iterator; Component : ISch_Component; begin SchDoc : SchServer.GetCurrentSchDocument; if SchDoc nil then Exit; Iterator : SchDoc.SchIterator_Create; Iterator.AddFilter_ObjectSet(MkSet(eSchComponent)); Component : Iterator.FirstSchObject; while Component nil do begin // 处理元件 ShowMessage(Component.Designator.Text); Component : Iterator.NextSchObject; end; SchDoc.SchIterator_Destroy(Iterator); end;这段代码的关键点在于AddFilter_ObjectSet它决定了迭代器只返回元件对象忽略导线、网络标签等其他对象。如果不加过滤迭代器会返回所有对象处理起来很麻烦。元件的参数通过Component.Parameters访问这是一个参数集合每个参数有Name和Value。比如要获取元件的封装名称可以这样写function GetFootprintName(Component : ISch_Component) : String; var Param : ISch_Parameter; Iterator : ISch_Iterator; begin Result : ; Iterator : Component.SchIterator_Create; Iterator.AddFilter_ObjectSet(MkSet(eParameter)); Param : Iterator.FirstSchObject; while Param nil do begin if Param.Name Footprint then begin Result : Param.Value; Break; end; Param : Iterator.NextSchObject; end; Component.SchIterator_Destroy(Iterator); end;实操心得AD里元件的封装信息可能存储在多个地方有的是在Parameters集合里有的是在Component的Footprint属性里。最稳妥的做法是先检查Footprint属性如果为空再去Parameters里找。我踩过这个坑有些元件是从其他工具导入的封装信息藏在参数里直接读属性会漏掉。3.2 封装模板的数据结构设计封装模板是这套脚本的核心数据结构它定义了一个封装应该长什么样。我用一个记录类型来表示type TPadDef record PadName : String; X, Y : Real; Width, Height : Real; Shape : TPadShape; Layer : TLayer; end; TFootprintTemplate record Name : String; Pads : array of TPadDef; SilkLines : array of TSilkLine; CourtyardWidth, CourtyardHeight : Real; end;每个封装模板包含焊盘列表、丝印线列表、 courtyard尺寸。焊盘定义里最重要的是X、Y坐标和宽高这些决定了焊盘的位置和大小。丝印线用来画元件的外框 courtyard用来做布局时的间距检查。模板的来源有两种一种是从现有的PCB库文件里提取另一种是手动定义。我建议先从现有库里提取常用封装的模板存成配置文件然后手动补充那些库里没有的。提取的代码逻辑是遍历PCB库里的所有封装把每个封装的焊盘和丝印信息读出来存成上面的结构。3.3 焊盘尺寸的计算逻辑焊盘尺寸不能随便定得根据元件的引脚尺寸和焊接工艺来算。以0603电阻为例标准尺寸是1.6mm x 0.8mm引脚宽度约0.3mm。焊盘宽度一般取引脚宽度的1.2到1.5倍所以焊盘宽度取0.4mm到0.45mm。焊盘长度取引脚长度的1.5到2倍0603的引脚长度约0.3mm焊盘长度取0.5mm到0.6mm。两个焊盘之间的间距等于元件长度减去两倍焊盘长度即1.6 - 2*0.55 0.5mm。这些计算逻辑可以写成函数根据元件类型和尺寸自动计算焊盘参数procedure CalcChipPadParams(ComponentLength, ComponentWidth, PinWidth : Real; var PadWidth, PadHeight, PadSpacing : Real); begin PadWidth : PinWidth * 1.3; PadHeight : ComponentWidth * 0.9; PadSpacing : ComponentLength - PadWidth * 2; end;注意不同厂家的元件尺寸有细微差异比如同样是0603电阻国巨和村田的尺寸可能差0.05mm。如果板子密度高建议按最大尺寸计算留出余量。我一般会在计算结果上加0.05mm的余量避免因为元件公差导致焊接不良。3.4 丝印和 courtyard 的绘制规则丝印的作用是标注元件的外框和方向方便焊接和维修。丝印线不能压在焊盘上否则焊接时会短路。一般丝印线距离焊盘边缘0.15mm到0.2mm。对于0603电阻丝印画一个矩形框左右两边距离焊盘外侧0.2mm上下两边距离元件边缘0.1mm。courtyard是布局时的占位区域比元件实际尺寸大0.25mm左右用来做间距检查。AD在布局时可以用courtyard来检查元件是否重叠。courtyard一般画在Mechanical Layer或者专门的Courtyard Layer上。procedure DrawSilkRectangle(PCBLib : IPCB_Library; X1, Y1, X2, Y2 : Real; Layer : TLayer); var Track : IPCB_Track; begin // 画四条线组成矩形 Track : PCBServer.PCBObjectFactory(eTrack, eNoDimension, eCreate_Default); Track.X1 : X1; Track.Y1 : Y1; Track.X2 : X2; Track.Y2 : Y1; Track.Layer : Layer; Track.Width : MilsToCoord(6); // 6mil线宽 PCBLib.AddPCBObject(Track); // 重复画另外三条边... end;丝印线宽一般用6mil到8mil太细了印刷不清楚太粗了占空间。我习惯用6mil大部分板厂都能做。4. 实操过程从零跑通一个封装的自动生成4.1 环境准备和脚本加载首先确保你的AD版本在17以上然后新建一个脚本项目File - New - Script Project。在项目里新建一个Delphi Script文件把上面的代码框架放进去。脚本项目需要引用AD的API单元在文件开头加上uses Altium.PCB.BasicObjects, Altium.Sch.DataModel, Altium.PCB.DataModel;这些单元提供了操作原理图和PCB对象的接口。如果编译时报找不到单元检查AD的安装目录下是否有这些文件路径一般是AD安装目录\System\Delphi\。加载脚本的方式在AD里打开脚本项目双击脚本文件然后Run - Run。如果脚本有语法错误AD会在Messages面板里显示错误信息。实操心得AD的脚本调试功能比较弱没有断点调试。我一般用ShowMessage或者写日志文件的方式来调试。日志文件的方式更靠谱因为ShowMessage会阻塞脚本执行批量处理时很烦人。4.2 读取原理图并生成元件列表打开一个原理图文档运行脚本的第一部分读取所有元件并输出到日志文件procedure GenerateComponentList; var SchDoc : ISch_Document; Iterator : ISch_Iterator; Component : ISch_Component; LogFile : TextFile; begin SchDoc : SchServer.GetCurrentSchDocument; if SchDoc nil then begin ShowMessage(请先打开一个原理图文档); Exit; end; AssignFile(LogFile, C:\Temp\ComponentList.txt); Rewrite(LogFile); Iterator : SchDoc.SchIterator_Create; Iterator.AddFilter_ObjectSet(MkSet(eSchComponent)); Component : Iterator.FirstSchObject; while Component nil do begin WriteLn(LogFile, Component.Designator.Text | GetFootprintName(Component) | GetComponentType(Component)); Component : Iterator.NextSchObject; end; SchDoc.SchIterator_Destroy(Iterator); CloseFile(LogFile); end;运行后会生成一个文本文件每行是一个元件的信息用竖线分隔。这个文件就是后续封装生成的输入。4.3 匹配封装模板并生成封装读取元件列表后根据元件类型和封装名称匹配模板。匹配逻辑是先按封装名称精确匹配如果找不到再按元件类型匹配默认模板。function FindTemplate(FootprintName, ComponentType : String) : TFootprintTemplate; var i : Integer; begin // 先精确匹配 for i : 0 to High(Templates) do begin if Templates[i].Name FootprintName then begin Result : Templates[i]; Exit; end; end; // 再按类型匹配 for i : 0 to High(Templates) do begin if Templates[i].Name ComponentType _DEFAULT then begin Result : Templates[i]; Exit; end; end; // 都没找到返回空模板 Result.Name : ; end;匹配到模板后在PCB库文件里创建新封装procedure CreateFootprint(PCBLib : IPCB_Library; Template : TFootprintTemplate); var NewComp : IPCB_LibComponent; Pad : IPCB_Pad; i : Integer; begin NewComp : PCBLib.CreateNewComponent; NewComp.Name : Template.Name; for i : 0 to High(Template.Pads) do begin Pad : PCBServer.PCBObjectFactory(ePad, eNoDimension, eCreate_Default); Pad.Name : Template.Pads[i].PadName; Pad.X : MilsToCoord(Template.Pads[i].X); Pad.Y : MilsToCoord(Template.Pads[i].Y); Pad.TopShape : Template.Pads[i].Shape; Pad.TopXSize : MilsToCoord(Template.Pads[i].Width); Pad.TopYSize : MilsToCoord(Template.Pads[i].Height); Pad.Layer : Template.Pads[i].Layer; NewComp.AddPCBObject(Pad); end; // 画丝印和courtyard... end;4.4 批量生成和验证把所有元件遍历一遍逐个生成封装。生成完成后在PCB库文件里检查每个封装的焊盘位置和尺寸是否正确。我一般会随机抽几个封装用AD的测量工具量一下焊盘间距和元件规格书对比。验证的另一个方法是把生成的封装放到一个测试PCB上用3D视图看一下元件和焊盘的对齐情况。AD的3D视图可以加载元件的3D模型如果焊盘位置偏了3D视图里一眼就能看出来。注意批量生成时要注意内存管理每创建一个封装后要释放临时对象否则元件多了之后AD会变卡。Delphi Script有自动垃圾回收但PCB对象需要手动释放。我一般在循环里加一个NewComp : nil来触发释放。5. 常见问题与排查技巧实录5.1 脚本运行报错“Interface not supported”这是最常见的问题原因是AD的脚本引擎没有正确加载API单元。解决方法检查脚本项目的引用里是否包含了所有需要的单元特别是Altium.PCB.DataModel和Altium.Sch.DataModel。如果引用了但还是报错尝试重启AD有时候是脚本引擎的缓存问题。另一个可能的原因是AD版本不匹配。AD 17和AD 20的API单元名称有变化AD 17里叫PCBAPIAD 20里叫Altium.PCB.DataModel。根据你的版本调整引用。5.2 生成的焊盘位置偏移焊盘位置偏移通常是因为单位换算错误。AD内部使用Coord单位1mil 10000 Coord1mm 393700 Coord。如果你直接用mm数值赋给Coord属性焊盘会跑到很远的地方。正确的做法是用MilsToCoord或MMToCoord函数转换。Pad.X : MMToCoord(1.6); // 正确 Pad.X : 1.6; // 错误焊盘会跑到几乎原点我踩过这个坑第一次生成封装时焊盘全部挤在一起查了半天才发现是单位问题。5.3 丝印压在焊盘上导致DRC报错丝印和焊盘的间距检查是AD的DRC规则之一。如果丝印线距离焊盘太近DRC会报错。解决方法是在绘制丝印时留出足够的间距一般0.15mm以上。如果板子空间紧张可以把丝印线宽改细或者把丝印移到元件本体上方。另一个技巧是在DRC规则里设置丝印到焊盘的间距为0但这样有短路风险不推荐。我一般还是老老实实留间距宁可丝印画小一点。5.4 封装库文件被锁定无法写入如果PCB库文件正在被其他文档引用脚本可能无法写入。解决方法是先关闭所有引用该库的PCB文档或者把库文件另存为一个新文件再操作。AD的库文件锁定机制比较严格有时候即使关闭了文档库文件还是被锁定需要重启AD。5.5 常见问题速查表问题现象可能原因解决方法脚本运行无反应未打开原理图文档先打开一个原理图再运行报错“Interface not supported”API单元引用缺失检查脚本项目引用重启AD焊盘位置偏移单位换算错误使用MMToCoord或MilsToCoord丝印DRC报错丝印距焊盘太近调整丝印位置留0.15mm间距库文件无法写入库文件被锁定关闭引用文档重启AD生成的封装名重复模板匹配逻辑问题检查映射表确保名称唯一脚本运行速度慢未释放临时对象循环内释放PCB对象实操心得脚本开发最耗时的不是写代码而是调试。AD的脚本错误信息很不友好经常只报一个行号不告诉你具体原因。我的经验是每写一小段就运行一次确保没问题再往下写。另外日志文件比ShowMessage好用得多建议养成写日志的习惯。6. 进阶技巧让脚本更智能的几个方向6.1 从元件参数自动推导封装现在的脚本是根据封装名称匹配模板但很多原理图里的元件没有填封装名称只有阻值、容值这些参数。进阶做法是根据参数自动推导封装比如“10k”推导出0603电阻封装“100nF”推导出0402电容封装。推导规则可以写在配置文件里用正则表达式匹配参数值。function InferFootprint(Value : String) : String; begin if Pos(k, Value) 0 then Result : RESC0603 else if Pos(nF, Value) 0 then Result : CAPC0402 else Result : ; end;这个逻辑需要根据你常用的元件系列来定制没有通用规则。我一般会把常用元件的参数和封装对应关系整理成一个CSV文件脚本读取这个文件来做匹配。6.2 自动生成3D模型AD支持在封装里嵌入3D模型但手动添加3D模型很麻烦。进阶做法是脚本根据封装尺寸自动生成简单的3D体Extruded Body比如电阻电容就是一个长方体IC就是一个薄片。虽然不如专业的STEP模型精确但用于布局时的干涉检查足够了。procedure Add3DBody(Comp : IPCB_LibComponent; Width, Height, Depth : Real); var Body : IPCB_ComponentBody; begin Body : PCBServer.PCBObjectFactory(eComponentBody, eNoDimension, eCreate_Default); Body.BodyProjection : eExtruded; Body.ExtrusionHeight : MMToCoord(Depth); // 设置轮廓... Comp.AddPCBObject(Body); end;6.3 与版本控制集成脚本生成的封装库文件可以纳入版本控制每次生成后自动提交。这样团队里每个人用的封装库都是一致的不会出现“你用的0603和我用的0603不一样”的问题。集成方式可以用命令行调用Git在脚本运行结束后自动执行提交命令。procedure CommitToGit(LibPath : String); begin RunApplication(git, add LibPath); RunApplication(git, commit -m Auto-generated footprints); end;注意自动提交前要确保生成的封装没有问题否则会把错误提交到仓库里。我建议先手动检查一遍确认无误后再提交。或者用两个分支一个用于自动生成一个用于人工审核。6.4 支持多原理图文档批量处理现在的脚本一次只处理一个原理图文档如果项目里有多个原理图比如主板和子板分开画需要逐个打开运行。进阶做法是脚本遍历项目里的所有原理图文档自动逐个处理。AD的API提供了IProject接口可以获取项目里的所有文档。procedure ProcessAllSchDocs; var Project : IProject; Doc : IDocument; i : Integer; begin Project : GetWorkspace.DM_FocusedProject; for i : 0 to Project.DM_LogicalDocumentCount - 1 do begin Doc : Project.DM_LogicalDocuments(i); if Doc.DM_DocumentKind SCH then begin // 打开文档并处理 end; end; end;这个功能我还在完善中主要问题是打开文档会改变当前编辑状态处理完后需要恢复原来的文档。另外批量处理时如果某个文档报错要能跳过继续处理下一个不能因为一个文档的问题中断整个流程。7. 一些踩过的坑和实际体会脚本这东西写起来不难难的是处理各种边界情况。我遇到过一个原理图里有个元件的封装名称是空的脚本直接报错退出后来加了空值检查才解决。还有一次原理图里有个元件的位号重复了脚本生成的封装也重复了导致库文件里有两个同名封装AD加载时随机选一个板子做出来发现封装不对。另一个体会是脚本生成的封装一定要人工审核。我一般会随机抽10%的封装用AD的测量工具量一下关键尺寸和元件规格书对比。特别是连接器类的封装引脚间距和焊盘尺寸差一点就焊不上。有一次我生成的FPC连接器封装焊盘宽度比规格书小了0.1mm板子回来发现焊盘吃锡不够返工了一批。还有一点脚本的配置文件要版本化。我一开始把映射表写在脚本代码里后来要改一个规则得重新编译脚本很麻烦。后来把映射表抽出来放到独立的CSV文件里改规则只需要编辑CSV脚本重新读取就行。这个改动虽然小但日常维护效率提升很多。最后分享一个小技巧AD的脚本可以绑定到快捷键上。在AD的Customize菜单里把脚本添加到快捷键列表设置一个不常用的组合键比如CtrlShiftF以后按一下就能运行脚本不用每次都去菜单里找。这个功能在批量处理时特别方便我一般设成CtrlShiftG按一下就开始生成封装然后去倒杯水回来就生成好了。
阅读完成 · 觉得有帮助?