用Openness API自动生成PLC程序:从环境配置到实战代码

发布时间:2026/9/2 2:28:24
用Openness API自动生成PLC程序:从环境配置到实战代码 简介以C#与西门子TIA博途Openness API为核心的自动化编程辅助资源面向需要批量生成、维护PLC程序的自动化工程师与二次开发人员。资源通过源码级示例展示如何用C#调用Openness接口实现项目数据读写、程序自动生成、批量更新等任务能显著降低重复组态与编程工作量。包体共272个文件约5.48MB主要包含44个cs源码文件、34个xml配置、19个dll依赖库以及博途工程相关ssk、数据csv、界面图标与xslt样式等结构清晰便于按模块研读和二次扩展。压缩包内还附带C#项目文件sln/csproj可直接打开编译调试。已有1436人学习下载。通过阅读源码与配套示例可掌握博途Openness API的典型调用流程、C#与博途交互的工程实现方法以及Excel联动生成程序的扩展思路适合有一定PLC基础并希望借助编程提升效率的工程师。1. 为什么要用Openness API自动生成PLC程序做自动化这行的谁没被重复性的PLC编程折磨过设备一多工艺段一长动辄几十上百个电机泵阀的启停逻辑、模拟量处理、报警联锁一个一个在博途TIA Portal里拖拽、复制、改地址改到眼花缭乱还得担心哪里改漏了。老实说这种纯体力活早就该交给代码去干了。Openness API就是西门子留给我们的后门。它是TIA Portal官方提供的.NET接口允许我们用C#写程序去操作博途的工程文件打开项目、创建PLC数据类型、生成DB/FB/FC块、写变量、编译、下载甚至生成HMI画面。换句话说只要是你在博途界面里能点出来的操作绝大多数都能通过Openness API脚本化自动完成。我最早接触Openness是给产线做标准化的时候。公司要求所有新设备的PLC程序必须按统一模板来块名、变量名、注释格式、联锁逻辑全都要一致。靠人肉去遵守规范总有漏网之鱼而且审核工作量巨大。后来我干脆写了个小工具把工艺参数表Excel往里面一扔自动生成一套完整的程序骨架连DB块里变量初始值都给你填好。从那以后程序质量和交付效率直接上了一个台阶。这篇文章我就把这套玩法的核心内容和实操细节全盘托出包括环境配置、常见坑点、以及一套能直接改来用的C#代码思路适合有一定C#基础和PLC基础、想提升编程效率的朋友参考。2. 环境准备与前期配置2.1 博途版本与Openness DLL的匹配逻辑Openness API不是独立安装的它随博途软件一起安装到你的电脑上。关键点是博途的版本必须和你的开发环境严格对应。比如你用的是TIA Portal V18那就要用V18对应的Openness DLL不能混用。安装好博途后在安装目录下会有一个Siemens.Engineering.dll文件。以V18为例默认路径一般是C:\Program Files\Siemens\Automation\Portal V18\PublicAPI\V18\Siemens.Engineering.dll注意最外层的PublicAPI目录这个文件夹就是供开发者引用的。如果你的开发机器和博途安装机器是同一台直接引用这个DLL就行。如果分开那就得先把DLL拷贝到开发机配置好引用路径。还有一个细节C#项目的目标框架建议用.NET Framework 4.7.2或更高版本。我试过.NET Core和.NET 5/6也能调用但需要额外处理兼容性问题而且Openness本身是基于.NET Framework构建的用老框架最稳。2.2 开启Openness访问权限博途默认情况下不开放Openness接口必须在博途软件里手动开启。这一步很多人会漏掉结果程序一运行时直接报拒绝访问之类的错其实就是权限没开。具体操作路径打开TIA Portal进入任意项目或新建一个空项目。在左侧项目树中右键点击项目名称选择属性。在弹出的对话框中找到保护选项卡。勾选支持Openness选项。提示勾选后需要重启TIA Portal才能生效。而且注意这个选项是存在项目文件里的不是全局设置。所以每个项目都要单独勾选一次。另外如果你的博途是以管理员权限运行的你的C#程序最好也用管理员权限运行否则UG用户权限可能对不上也会出现权限异常。2.3 创建C#工程并引用核心DLL工具我推荐用Visual Studio社区版就够用。新建一个Windows窗体应用或者控制台应用都可以我习惯用WinForms因为方便加进度条和日志窗口。引用步骤在解决方案资源管理器里右键引用→添加引用。点击浏览找到刚才说的Siemens.Engineering.dll。添加引用后在代码文件头写入using Siemens.Engineering; using Siemens.Engineering.HW; using Siemens.Engineering.SW; using Siemens.Engineering.SW.Blocks; using Siemens.Engineering.SW.Tags;这里要注意DLL文件的复制本地属性最好设为False。因为运行时Openness DLL必须在博途安装目录下查找配套程序集复制到输出目录反而可能引发找不到依赖项的奇怪问题。3. 自动生成的整体思路与架构设计3.1 核心思路把程序生成当成一次数据转换写自动生成程序之前先要理清楚一件事我们不是在写代码而是在做一次数据转换。输入是一张结构化的点表或工艺表输出是一套符合博途工程格式的PLC程序块。为什么这样说因为Openness API不要求我们像写单片机代码那样逐行写指令它提供了块级接口。也就是说我们可以创建好一个函数块然后往里面填变量、填逻辑甚至通过导出→修改→再导入的方式批量生成完整的STL代码。用这种方式程序生成的本质就变成了把Excel中的点表映射成PLC变量和逻辑。这样设计的好处是业务人员只要维护好Excel表代码生成工具完全不关心具体是什么设备通用性极强。拿我自己做的工具举例输入表的结构大概是这样的设备名点类型地址描述联锁条件M1_MotorDII0.0电机1运行反馈急停未触发M1_MotorDOQ0.0电机1启动输出无M1_MotorAIIW64电机1电流无M1_MotorAOQW80电机1转速给定无程序读取这张表根据点类型自动创建对应的PLC变量、生成FB块中的接口参数以及内部逻辑框架。3.2 开发工具架构三步走这套自动生成工具我个人建议按三个层次来设计第一层数据输入层。最常用的是Excel文件用EPPlus或NPOI库读取。也可以用数据库或文本配置看你自己习惯。第二层业务逻辑层。负责解析输入数据映射成Openness API的数据模型。比如把管道的启动条件翻译成梯形图指令的组合。第三层Openness操作层。这一层封装对Siemens.Engineering.dll的调用包括打开项目、创建块、写入变量、编译等操作尽量做到对上层透明。每一层的职责要单一不要混在一起。否则后期想扩展比如从Excel换成从数据库读数据就得动核心逻辑维护起来非常痛苦。3.3 选Openness而不是UAG或者直接改XML说到生成博途程序有几种途径一是直接在博途界面手搓二是用Openness API三是直接操作项目文件内部的XMLTIA项目实质上是一个数据库XML混合体。直接改XML这条路我试过水太深。TIA的项目文件结构非常复杂且不同版本之间格式有差异风险极大。一旦弄错整个项目文件直接损坏打不开。Openness是官方公开接口虽然也有版本变迁但至少是受支持的出问题还能找西门子开Case。UAGUniversal Automation Gateway则是基于OPC UA的方式更多用于运行时数据交互而不是工程数据生成不是同一纬度的事情。所以在离线批量生成程序这个场景Openness API就是最合理的选择。4. 核心代码实现从打开项目到生成程序4.1 连接TIA Portal并打开目标项目所有操作的第一步是实例化TIA Portal并打开工程。这个过程中最常见的坑是只能打开一个TIA实例且无法在博途界面正开着的时候再用Openness打开同一个项目。代码原型如下using Siemens.Engineering; // 实例化TIA Portal TiaPortal tiaPortal new TiaPortal(TiaPortalMode.WithoutUserInterface); // 打开项目 Project project tiaPortal.Projects.Open(D:\MyProject\TestProj.ap17); // 注意如果希望界面显示用 TiaPortalMode.WithUserInterfaceTiaPortalMode.WithUserInterface会带出博途的图形界面适合调试阶段观察生成效果。实际批量跑的时候建议用WithoutUserInterface速度更快资源占用也更低。注意Openness打开项目时需要保证项目没有被其他进程占用。否则报错信息通常是项目无法打开排查思路很简单把博途界面关掉或者换个项目文件测试。4.2 定位PLC设备并创建数据类型项目打开后要定位到具体的PLC设备。TIA的项目结构树是设备→站点→控制器这样一层层嵌套的。用代码遍历设备列表即可using Siemens.Engineering.HW; Device device project.Devices.Find(PLC_1); DeviceItem plcDeviceItem device.DeviceItems.Find(PLC_1);拿到DeviceItem之后就可以操作PLC下面的软硬件资源了。创建PLC数据类型UDT的代码很简单先生成类型名然后添加成员变量using Siemens.Engineering.SW; using Siemens.Engineering.SW.Types; PlcType udt plcTypeGroup.Types.Create(UDT_Motor); udt.Members.Create(RunCmd, Bool); udt.Members.Create(RunFeedback, Bool); udt.Members.Create(Current, Int);这里使用的plcTypeGroup是通过PlcSoftware对象获得的也就是PlcSoftware plcSoftware plcDeviceItem.GetServicePlcSoftware(); PlcTypeGroup plcTypeGroup plcSoftware.TypeGroup;4.3 创建块并生成逻辑代码创建逻辑块是更关键的一步。以生成FB函数块为例using Siemens.Engineering.SW.Blocks; PlcBlockGroup blockGroup plcSoftware.BlockGroup; PLCSmartClass? fbClass PLCSmartClass.FB; PlcBlock fb blockGroup.Blocks.CreateBlock(FB_MotorControl, fbClass, false, null);块创建好之后Openness提供了两种主流的填逻辑方式方式一通过代码逐条添加指令。这种方式细致但非常繁琐适合逻辑简单的场景。方式二导出块接口和代码段修改后再导入。这种方式非常实用。思路是先用Openness生成一个空白块。把块导出成XML文件Export方法。在XML里直接用文本处理的方式插入NETWORK和指令。再用Import方法导回工程。我大量采用的是方式二。原因是Openness的逐条指令API写起来太啰嗦而且一旦碰到复杂的梯级结构代码量会爆炸式增长。而XML文件是可读的文本用字符串模板拼接反而更直接。4.4 编译与错误检查生成完块之后一定要做一次编译确保没有语法和逻辑错误。调用方式CompilationResult result plcSoftware.Compile(); Console.WriteLine(result.State);编译结果中有State属性一般会有Success、Error、Warning等状态。如果报错我建议你在调试阶段先用WithUserInterface模式跑这样可以直接在博途界面看到报错位置比看编译日志更直观。5. 实操案例一个电机启停块的自动生成全流程5.1 数据准备和模板设计以一个实际项目为例生成一套电机启停控制块包含启动命令、停止命令、运行反馈、故障复位、电流监视以及报警输出。我在Excel里维护一张表每一行代表一个电机列包括电机名称、DI起始地址、DO起始地址、AI电流地址、额定电流值、是否参与联锁等。程序运行时会先读取Excel然后按照模板规则生成全套程序。下面是一个模板参数的示例public class MotorConfig { public string Name { get; set; } public string DiStart { get; set; } public string DoStart { get; set; } public string AiCurrent { get; set; } public double RatedCurrent { get; set; } public bool Interlock { get; set; } }5.2 创建DB与FB并填充逻辑拿到配置后程序执行的核心流程如下在PLC中创建一个FB块命名为FB_Motor如果已存在则复用。在FB的接口区添加输入输出参数。在每个电机的DB块中创建一个多重实例对应一个电机。生成逻辑启停锁存、故障复位、电流超限报警。代码流程简化如下// 创建电机DB块 PlcBlock dbBlock blockGroup.Blocks.CreateBlock($DB_Motor_{motor.Name}, PLCSmartClass.DB, false, null); // 多重实例引用 // 注意这里生成的嵌套调用可以通过Openness API的方式完成对于逻辑填充我实际操作中更推荐用模板字符串拼接的XML方式。我会准备一个标准的Network模板里面预设好规则的STL代码然后替换地址和变量名。比如一个最简单的启动/保持/停止逻辑在XML里长这样简化版SW.Blocks.Network xmlnshttp://www.siemens.com/automation/Openness/SW/Network NameStarStop Members Member NamestartCmd/ Member NamestopCmd/ Member NamerunOut/ /Members /SW.Blocks.Network然后用STL助记符填写逻辑完成后再导入。这样批量生成几十个电机块的速度非常快。5.3 生成后的检查与验证生成完毕后光看编译通过还远远不够。我在实际项目中遇到过这种情况编译零错误但程序跑起来逻辑不对后来发现是地址分配和模板里的偏移量算错了。所以建议你在生成代码之后做几个检查动作抽查几个块确认FB/DB内部的变量定义与Excel点表一致。用博途的程序比较功能和手工编写的标准块做对照。如果有仿真器跑一遍时序逻辑看看有没有不该有的输出。6. 常见问题与排查技巧实录6.1 Openness API调用时报拒绝访问这个是最常见的坑多数时候不是代码问题而是权限没开。按照前面2.2的步骤确认一下项目是否勾选支持Openness是否以管理员权限运行C#程序是否有多余的TIA Portal界面进程占用了项目6.2 打开项目时提示项目已被锁定或无法打开大概率是TIA Portal界面正开着或者上次程序崩溃后残留了进程。打开任务管理器把Siemens.Automation.Portal.exe及其子进程全杀掉再重新运行程序。再不行就把电脑上临时目录里的TIAP*缓存文件清理一下。6.3 生成块时版本不一致导致类型不兼容不同博途版本生成的Openness DLL不同如果你开发机上装了多个版本的博途比如V17和V18一定要检查引用的DLL路径是否真的指向了目标版本。我的习惯是开发机上只装一个博途版本避免踩坑。6.4 编译报未知错误或缺少权限这种问题多数出在生成块时某个生成块内部的成员变量类型引用了不存在的UDT。建议在Openness代码中创建块的顺序上先创建UDT再创建FB/DB最后再往块的接口里添加变量引用。顺序颠倒的话博途的编译机制会识别到悬空引用。6.5 耗时过长批量生成几十分钟生成大批量程序时Openness跑得非常慢主要是每个块的创建和编译都是重量级操作。这里有几个提速技巧尽量用WithoutUserInterface模式运行省去界面渲染时间。不要每个块都单独调用Compile全部块生成完再统一编译一次。如果只是生成DB块的变量使用XML导入方式比逐条API快10倍以上。7. 进阶数据驱动生成与版本管理的延伸7.1 从Excel到程序的完整数据流一个成熟的自动生成系统其实是把点表管理、版本对比、程序生成、文档输出整个串起来。我这边现在的流程是工艺工程师维护Excel点表发布到共享目录后我这边写了一个小监控程序检测到文件变更就自动触发生成任务。生成之后自动执行一次编译然后把结果通过邮件发出来。如果能通过打一个快照到Git仓库。7.2 与版本管理的结合很多工程师没意识到PLC程序也是代码也应该纳入版本管理。Openness生成过程中我们可以把生成的XML块文件、项目源文件全部纳入Git。这样每次变更都能追溯。我用Git管理TIA项目源文件的方式是每次生成后用Git commit打标签写清楚工艺版本号。这样哪怕程序出错也能快速回滚到上一个稳定版本。提示TIA项目文件本身是二进制格式直接入Git不太友好但块导出XML后文本化非常适合diff。所以我只把导出的XML块文件放入Git库TIA项目本体仍然在共享盘上。7.3 扩展方向HMI画面自动生成Openness不仅支持PLC侧的块生成还支持HMI画面的自动生成。创建画面、添加IO域、关联变量都是可以脚本化的。我目前已经在试点通过Openness生成设备HMI画面把设备启停按钮、电流显示、报警灯等元素按模板自动排布。确实省去了大量重复的HMI组态时间。我个人的体会是Openness这套自动化的核心价值不在于省掉写程序的时间而在于把工程师从重复劳动中解放出来把精力投入到真正需要判断力的工艺逻辑和调试工作中。数据驱动方式让程序结构更标准、更一致也更容易维护。最后再分享一个实用技巧刚开始接触Openness时不要一上来就想搞大而全的工具。找一个反复出现的小场景比如批量生成设备的启停块从这个小切口入手走通一遍环境配置、API调用、生成验证的闭环熟悉了这套流程之后再逐步扩展功能和范围这条路会顺畅很多。本文还有配套的精品资源点击获取