基础命名空间为必引项,可根据HMI/PLC/硬件操作场景按需扩展:
using System; using System.IO; using System.Collections.Generic; // 核心基础 using Siemens.Engineering; // HMI专属 using Siemens.Engineering.Hmi; using Siemens.Engineering.Hmi.TextGraphicList; using Siemens.Engineering.Hmi.Screen; using Siemens.Engineering.Hmi.Communication; using Siemens.Engineering.Hmi.RuntimeScripting; using Siemens.Engineering.Hmi.Tag; // 硬件专属 using Siemens.Engineering.HW; using Siemens.Engineering.HW.Features; using Siemens.Engineering.HW.Utilities; // PLC专属 using Siemens.Engineering.SW; using Siemens.Engineering.SW.Blocks; using Siemens.Engineering.SW.Tags; using Siemens.Engineering.SW.Types; using Siemens.Engineering.SW.ExternalSources;
所有操作均基于以下核心对象,是与TIA Portal交互的入口,获取方式为固定语法:
| 对象类型 | 核心作用 | 获取方式 |
|---|---|---|
| TiaPortal | TIA Portal进程实例,所有操作的根入口 | TiaPortal(TiaPortalMode.WithUserInterface) / TiaPortal.Attach().FirstOrDefault() |
| Project | 已打开的TIA项目对象 | tiaPortal.Projects[0] / tiaPortal.Projects.Open(文件路径) |
| Device | 项目中的PLC/HMI硬件设备 | project.Devices.Find("设备名称") |
| DeviceItem | 设备下的模块/CPU/HMI目标 | device.DeviceItems[0] |
| HmiTarget | HMI软件容器,所有HMI操作核心 | deviceItem.GetService<SoftwareContainer>().Software as HmiTarget |
| PlcSoftware | PLC软件容器,所有PLC操作核心 | deviceItem.GetService<SoftwareContainer>().Software as PlcSoftware |
////// 连接TIA Portal并打开指定项目,无进程则新建 /// /// 项目全路径,如@"D:ProjectMyProject.ap16" ///打开的项目对象 public static Project ConnectAndOpenProject(string projectPath) { try { // 附加到已运行的TIA Portal进程,无则新建(WithUserInterface为带UI,WithoutUserInterface为无UI) TiaPortal tiaPortal = TiaPortal.Attach().FirstOrDefault() ?? new TiaPortal(TiaPortalMode.WithUserInterface); // 打开项目 Project project = tiaPortal.Projects.Open(new FileInfo(projectPath)); Console.WriteLine($"项目打开成功:{project.Name}"); return project; } catch (Exception ex) { Console.WriteLine($"操作失败:{ex.Message}"); return null; } }
////// 获取HMI设备的HmiTarget对象 /// public static HmiTarget GetHmiTarget(Project project, string hmiDeviceName) { Device hmiDevice = project.Devices.Find(hmiDeviceName); if (hmiDevice == null) return null; // 遍历设备项获取软件容器 foreach (DeviceItem deviceItem in hmiDevice.DeviceItems) { SoftwareContainer container = deviceItem.GetService(); if (container?.Software is HmiTarget hmiTarget) return hmiTarget; } return null; } /// /// 获取PLC设备的PlcSoftware对象 /// public static PlcSoftware GetPlcSoftware(Project project, string plcDeviceName) { Device plcDevice = project.Devices.Find(plcDeviceName); if (plcDevice == null) return null; foreach (DeviceItem deviceItem in plcDevice.DeviceItems) { SoftwareContainer container = deviceItem.GetService(); if (container?.Software is PlcSoftware plcSoftware) return plcSoftware; } return null; }
操作完成后必须释放TIA Portal资源,避免后台进程残留:
////// 释放TIA Portal资源 /// public static void DisposeTiaResources(TiaPortal tiaPortal) { tiaPortal?.Dispose(); }
所有对项目的修改操作(创建/删除/修改块、画面、变量等)必须在独占访问+事务框架内执行,避免API与TIA Portal界面同时操作导致冲突,且支持操作回滚。
// 安全修改操作的标准模板
using (TiaPortal tiaPortal = new TiaPortal(TiaPortalMode.WithUserInterface))
{
Project project = tiaPortal.Projects.Open(new FileInfo(projectPath));
// 1. 申请独占访问,锁定TIA Portal界面
using (ExclusiveAccess exclusiveAccess = tiaPortal.ExclusiveAccess())
{
// 2. 开启事务,绑定项目与操作描述
using (Transaction transaction = exclusiveAccess.Transaction(project, "修改PLC程序块"))
{
try
{
// 3. 执行所有修改操作(示例:创建FC块)
PlcSoftware plc = GetPlcSoftware(project, "PLC_1");
// 后续章节的创建/修改代码写在此处
// 4. 提交事务,操作生效
transaction.CommitOnDispose();
Console.WriteLine("操作执行成功,事务已提交");
}
catch (Exception ex)
{
// 5. 异常时事务自动回滚,所有修改失效
Console.WriteLine($"操作失败,事务已回滚:{ex.Message}");
throw;
}
}
}
// 保存项目
project.Save();
}
核心规则:先创建独占访问,再创建事务,释放时按逆序销毁;V13 SP1及更早版本使用 StartTransaction/CommitTransaction ,V14及以上已废弃。
↑ 返回顶部////// 创建全新TIA Portal项目 /// /// 项目保存目录 /// 项目名称 ///创建后的项目对象 public static Project CreateNewProject(string projectSavePath, string projectName) { using TiaPortal tiaPortal = new TiaPortal(TiaPortalMode.WithoutUserInterface); DirectoryInfo projectDir = new DirectoryInfo(Path.Combine(projectSavePath, projectName)); if (!projectDir.Exists) projectDir.Create(); Project newProject = tiaPortal.Projects.Create(projectDir, projectName); Console.WriteLine($"项目创建成功:{newProject.Path.FullName}"); return newProject; }
////// 项目覆盖保存 /// public static void SaveProject(Project project) { if (project.IsModified) { project.Save(); Console.WriteLine("项目已保存"); } } ////// 项目另存为 /// public static void SaveProjectAs(Project project, string newSavePath, string newProjectName) { DirectoryInfo newDir = new DirectoryInfo(Path.Combine(newSavePath, newProjectName)); if (!newDir.Exists) newDir.Create(); project.SaveAs(newDir, newProjectName); Console.WriteLine($"项目已另存为:{newDir.FullName}"); }
////// 遍历项目内所有设备,并重命名指定设备 /// public static void RenameDevice(Project project, string oldDeviceName, string newDeviceName) { Device targetDevice = project.Devices.Find(oldDeviceName); if (targetDevice == null) { Console.WriteLine($"未找到设备:{oldDeviceName}"); return; } targetDevice.Name = newDeviceName; Console.WriteLine($"设备已重命名:{oldDeviceName} -> {newDeviceName}"); }
支持对PLC软件、硬件配置分别编译,获取编译结果与错误信息:
// 编译PLC软件 PlcSoftware plcSoftware = GetPlcSoftware(project, "PLC_1"); ICompilable compilablePlc = plcSoftware.GetService(); CompilerResult plcResult = compilablePlc.Compile(); // 编译硬件配置 Device device = project.Devices.Find("S7-1500_Station"); ICompilable compilableHw = device.GetService (); CompilerResult hwResult = compilableHw.Compile();
HMI导入导出的通用选项,所有HMI对象操作均适用:
// 导出选项
public enum ExportOptions
{
None = 0,
WithDefaults = 1,
ReadOnly = 2
}
// 导入选项
public enum ImportOptions
{
None = 0,
Override = 1
}
private static void ExportTextLists(HmiTarget hmiTarget, string exportFolder)
{
if (!Directory.Exists(exportFolder))
Directory.CreateDirectory(exportFolder);
TextListComposition textListComposition = hmiTarget.TextLists;
foreach (TextList textList in textListComposition)
{
string filePath = Path.Combine(exportFolder, $"{textList.Name}.xml");
textList.Export(new FileInfo(filePath), ExportOptions.WithDefaults);
Console.WriteLine($"文本列表导出成功:{textList.Name}");
}
}
private static void ImportSingleGraphicList(HmiTarget hmiTarget, string importFilePath)
{
FileInfo importFile = new FileInfo(importFilePath);
if (!importFile.Exists)
{
Console.WriteLine("导入文件不存在!");
return;
}
GraphicListComposition graphicListComposition = hmiTarget.GraphicLists;
IList importedGraphicLists = graphicListComposition.Import(importFile, ImportOptions.Override);
foreach (var graphicList in importedGraphicLists)
Console.WriteLine($"图形列表导入成功:{graphicList.Name}");
}
仅支持自定义通信连接的导出导入,集成连接不支持;导入时若同名集成连接存在,会引发异常。
////// 导出HMI所有通信连接 /// private static void ExportConnectionsFromHMITarget(HmiTarget hmiTarget, string exportFolder) { if (!Directory.Exists(exportFolder)) Directory.CreateDirectory(exportFolder); ConnectionComposition connectionComposition = hmiTarget.Connections; foreach (Connection connection in connectionComposition) { string filePath = Path.Combine(exportFolder, $"{connection.Name}.xml"); connection.Export(new FileInfo(filePath), ExportOptions.WithDefaults); Console.WriteLine($"连接导出成功:{connection.Name}"); } }
支持常规画面、全局画面、画面模板、永久性区域、弹出画面、滑入画面、带面板实例的画面,核心限制为导入画面的宽高必须与目标HMI设备尺寸一致、画面编号唯一、仅同类型设备兼容。
public static void ExportScreensOfDevice(string rootPath, HmiTarget hmiTarget)
{
DirectoryInfo rootDir = new DirectoryInfo(rootPath);
rootDir.Create();
string screenPath = Path.Combine(rootPath, "Screens");
Directory.CreateDirectory(screenPath);
ExportScreens(screenPath, hmiTarget);
Console.WriteLine("所有画面导出完成");
}
private static void ExportScreens(string screenPath, HmiTarget target)
{
// 导出根目录画面
foreach (Screen screen in target.ScreenFolder.Screens)
{
string filePath = Path.Combine(screenPath, $"{screen.Name}.xml");
screen.Export(new FileInfo(filePath), ExportOptions.WithDefaults);
Console.WriteLine($"画面导出成功:{screen.Name}");
}
// 递归导出子文件夹
foreach (ScreenUserFolder subFolder in target.ScreenFolder.Folders)
{
string subFolderPath = Path.Combine(screenPath, subFolder.Name);
Directory.CreateDirectory(subFolderPath);
ExportScreenUserFolder(subFolderPath, subFolder);
}
}
private static void ExportScreenUserFolder(string folderPath, ScreenUserFolder folder)
{
foreach (Screen screen in folder.Screens)
{
string filePath = Path.Combine(folderPath, $"{screen.Name}.xml");
screen.Export(new FileInfo(filePath), ExportOptions.WithDefaults);
Console.WriteLine($"画面导出成功:{folder.Name}\{screen.Name}");
}
foreach (ScreenUserFolder subFolder in folder.Folders)
{
string subFolderPath = Path.Combine(folderPath, subFolder.Name);
Directory.CreateDirectory(subFolderPath);
ExportScreenUserFolder(subFolderPath, subFolder);
}
}
private static void ImportScreensToHMITarget(HmiTarget hmiTarget, string folderName, string[] importFilePaths)
{
ScreenFolderBase targetFolder;
if (string.IsNullOrEmpty(folderName))
{
targetFolder = hmiTarget.ScreenFolder;
}
else
{
targetFolder = hmiTarget.ScreenFolder.Folders.Find(folderName);
if (targetFolder == null)
{
targetFolder = hmiTarget.ScreenFolder.Folders.Create(folderName);
Console.WriteLine($"创建文件夹:{folderName}");
}
}
foreach (string filePath in importFilePaths)
{
FileInfo importFile = new FileInfo(filePath);
if (!importFile.Exists)
{
Console.WriteLine($"文件不存在:{filePath}");
continue;
}
targetFolder.Screens.Import(importFile, ImportOptions.Override);
Console.WriteLine($"画面导入成功:{importFile.Name}");
}
}
周期包含执行间隔、优先级、关联脚本等配置,每个周期导出为独立XML:
////// 导出HMI所有周期 /// private static void ExportCycles(HmiTarget hmiTarget, string exportFolder) { if (!Directory.Exists(exportFolder)) Directory.CreateDirectory(exportFolder); CycleComposition cycleComposition = hmiTarget.Cycles; foreach (Cycle cycle in cycleComposition) { string filePath = Path.Combine(exportFolder, $"{cycle.Name}.xml"); cycle.Export(new FileInfo(filePath), ExportOptions.WithDefaults); Console.WriteLine($"周期导出成功:{cycle.Name}"); } }
脚本按系统文件夹/用户文件夹分级,支持递归遍历子文件夹:
private static void ExportAllVBScripts(HmiTarget hmiTarget, string rootPath)
{
string scriptPath = Path.Combine(rootPath, "VBScripts");
Directory.CreateDirectory(scriptPath);
ExportVBScripts(scriptPath, hmiTarget.VBScriptFolder);
}
private static void ExportVBScripts(string path, VBScriptFolder folder)
{
// 导出当前文件夹脚本
foreach (VBScript script in folder.VBScripts)
{
FileInfo file = new FileInfo(Path.Combine(path, $"{script.Name}.xml"));
script.Export(file, ExportOptions.WithDefaults);
}
// 递归子文件夹
foreach (VBScriptUserFolder subFolder in folder.Folders)
{
string subPath = Path.Combine(path, subFolder.Name);
Directory.CreateDirectory(subPath);
ExportVBScripts(subPath, subFolder);
}
}
V14版本后,变量量程属性由RangeMaximum/RangeMinimum 替换为LimitUpper1/LimitLower1/LimitUpper2/LimitLower2,低版本导出的XML无法直接在 高版本导入。
支持全局图形的批量导出导入,每个图形为独立文件;图形列表中引用的全局图形以OpenLink形式存储,导入时若目标项目存在对应图形,会自动恢复引用。
↑ 返回顶部覆盖PLC的程序块、变量表、UDT、数据块的全生命周期操作,包含高级导入、快照导出、在线操作、工艺对象等深度功能,所有操作要求PLC设备处于离线状态。
PLC专属的导入选项,解决引用缺失、结构变更的导入场景:
[Flags]
public enum SWImportOptions
{
None = 0,
IgnoreStructuralChanges = 1,
IgnoreMissingReferencedObjects = 2
}
支持所有块类型的创建、查询、重命名、属性修改、接口编辑、代码读写、删除、导入导出,专有技术保护的块仅能导出可见属性,无法导出核心代码。
以FC块和全局DB块为例,OB/FB块创建语法类似:
////// 创建FC块(函数) /// public static FC CreateFCBlock(PlcSoftware plcSoftware, string blockName, int blockNumber, ProgrammingLanguage programmingLanguage) { PlcBlockSystemFolder blockSystemFolder = plcSoftware.BlockGroup; FC newFC = blockSystemFolder.Blocks.Create(blockName, blockNumber, programmingLanguage); Console.WriteLine($"FC块创建成功:{blockName},编号:{blockNumber}"); return newFC; } /// /// 创建全局数据块(GlobalDB),支持优化访问 /// public static GlobalDB CreateGlobalDB(PlcSoftware plcSoftware, string blockName, int blockNumber, bool isOptimized = true) { PlcBlockSystemFolder blockSystemFolder = plcSoftware.BlockGroup; GlobalDB newDB = blockSystemFolder.Blocks.Create(blockName, blockNumber); // 设置优化访问属性 newDB.MemoryLayout = isOptimized ? MemoryLayout.Optimized : MemoryLayout.Standard; Console.WriteLine($"全局DB创建成功:{blockName},编号:{blockNumber},优化访问:{isOptimized}"); return newDB; }
支持为块的Input/Output/InOut/Static/Temp/Constant段添加/删除变量:
////// 为块添加接口变量 /// public static void AddBlockInterfaceVariable(PlcBlock block, string sectionName, string varName, string dataType, string comment = "", string startValue = "") { IEngineeringObject interfaceObj = block.GetService(); IEngineeringComposition sections = interfaceObj.GetComposition("Sections"); // 查找目标接口段 IEngineeringObject targetSection = null; foreach (IEngineeringObject section in sections) { if (section.GetAttribute("Name").ToString().Equals(sectionName, StringComparison.OrdinalIgnoreCase)) { targetSection = section; break; } } if (targetSection == null) throw new Exception($"未找到接口段:{sectionName}"); // 创建变量并设置属性 IEngineeringObject newMember = targetSection.CreateMember("Member", varName); newMember.SetAttribute("Datatype", dataType); if (!string.IsNullOrEmpty(comment)) newMember.SetAttribute("Comment", comment); if (!string.IsNullOrEmpty(startValue)) newMember.SetAttribute("StartValue", startValue); Console.WriteLine($"块{block.Name}接口变量添加成功:{sectionName}.{varName}"); }
仅支持SCL编程语言的块代码直接修改,其他语言(LAD/FBD/STL)需通过XML导入导出:
////// 读取SCL块的程序代码 /// public static string ReadSCLBlockCode(PlcBlock block) { if (block.ProgrammingLanguage != ProgrammingLanguage.SCL) throw new Exception("仅支持SCL编程语言的块"); IEngineeringObject codeUnit = block.GetComposition("CompileUnits")[0]; string sclCode = codeUnit.GetAttribute("Text").ToString(); Console.WriteLine($"块{block.Name}代码读取成功"); return sclCode; } ////// 写入/修改SCL块的程序代码 /// public static void WriteSCLBlockCode(PlcBlock block, string newSclCode) { if (block.ProgrammingLanguage != ProgrammingLanguage.SCL) throw new Exception("仅支持SCL编程语言的块"); IEngineeringObject codeUnit = block.GetComposition("CompileUnits")[0]; codeUnit.SetAttribute("Text", newSclCode); Console.WriteLine($"块{block.Name}代码写入成功"); }
解决引用缺失、结构变更的导入场景,通过SWImportOptions 实现:
////// 导入单个PLC块,支持忽略缺失引用/结构变更 /// public static void ImportBlocks(PlcSoftware plcSoftware, string importFilePath, bool ignoreMissingReference = false, bool ignoreStructuralChange = false) { FileInfo importFile = new FileInfo(importFilePath); if (!importFile.Exists) { Console.WriteLine("导入文件不存在!"); return; } // 构建导入选项 SWImportOptions swOptions = SWImportOptions.None; if (ignoreMissingReference) swOptions |= SWImportOptions.IgnoreMissingReferencedObjects; if (ignoreStructuralChange) swOptions |= SWImportOptions.IgnoreStructuralChanges; // 执行导入 PlcBlockComposition blockComposition = plcSoftware.BlockGroup.Blocks; IListimportedBlocks = blockComposition.Import(importFile, ImportOptions.Override, swOptions); foreach (var block in importedBlocks) { Console.WriteLine($"块导入成功:{block.Name}"); } }
DB变量的操作基于块接口的Static段,支持设置保持性:
////// 为全局DB添加变量并设置保持性 /// public static void AddDBVariable(GlobalDB dbBlock, string varName, string dataType, string comment = "", string startValue = "", bool retain = false) { // 向Static段添加变量 AddBlockInterfaceVariable(dbBlock, "Static", varName, dataType, comment, startValue); // 设置保持性 if (retain) { IEngineeringObject interfaceObj = dbBlock.GetService(); IEngineeringComposition sections = interfaceObj.GetComposition("Sections"); foreach (IEngineeringObject section in sections) { if (section.GetAttribute("Name").ToString() == "Static") { IEngineeringObject targetVar = section.Find(varName); targetVar?.SetAttribute("Remanence", "Retain"); break; } } } }
为FB块创建关联的背景数据块,自动继承FB的接口结构:
////// 为FB块创建背景数据块 /// public static InstanceDB CreateInstanceDB(FB fbBlock, string dbName, int dbNumber) { PlcBlockSystemFolder blockSystemFolder = fbBlock.Parent.Parent as PlcBlockSystemFolder; if (blockSystemFolder == null) throw new Exception("无法获取块系统文件夹"); InstanceDB instanceDB = blockSystemFolder.Blocks.CreateInstanceDB(dbName, dbNumber, fbBlock); Console.WriteLine($"背景DB创建成功:{dbName},关联FB:{fbBlock.Name}"); return instanceDB; }
通过InterfaceSnapshot 服务导出DB的实际值/快照值为XML,仅支持导出,不支持导入,用于 数据备份与对比:
////// 导出数据块的快照值(全局/背景/数组DB均支持) /// private static void ExportDataBlockSnapshot(PlcSoftware plcSoftware, string dbName, string exportFilePath) { PlcBlock dataBlock = plcSoftware.BlockGroup.Blocks.Find(dbName); if (dataBlock == null || !(dataBlock is GlobalDB || dataBlock is InstanceDB || dataBlock is ArrayDB)) { Console.WriteLine("数据块不存在或类型不支持!"); return; } InterfaceSnapshot interfaceSnapshot = dataBlock.GetService(); interfaceSnapshot.Export(new FileInfo(exportFilePath), ExportOptions.None); Console.WriteLine("数据块快照导出成功"); }
////// 创建PLC变量表 /// public static PlcTagTable CreateTagTable(PlcSoftware plcSoftware, string tableName) { PlcTagTableSystemFolder tagSystemFolder = plcSoftware.TagTableGroup; PlcTagTable newTagTable = tagSystemFolder.TagTables.Create(tableName); Console.WriteLine($"变量表创建成功:{tableName}"); return newTagTable; } ////// 为变量表添加PLC变量,支持绝对地址与保持性 /// public static PlcTag AddTagToTable(PlcTagTable tagTable, string tagName, string dataType, string logicalAddress = "", string comment = "", bool retain = false) { PlcTag newTag = tagTable.Tags.Create(tagName); newTag.DataTypeName = dataType; if (!string.IsNullOrEmpty(logicalAddress)) newTag.LogicalAddress = logicalAddress; newTag.Comment.Text = comment; newTag.Retain = retain; Console.WriteLine($"变量添加成功:{tagName},地址:{logicalAddress}"); return newTag; }
V14 SP1后,PLC常量拆分为用户常量(PlcUserConstant)和系统常量(PlcSystemConstant), 仅用户常量支持手动操作:
////// 为变量表添加用户常量 /// public static void AddUserConstantToTable(PlcTagTable tagTable, string constName, string dataType, string value, string comment = "") { PlcUserConstant newConst = tagTable.UserConstants.Create(constName); newConst.DataTypeName = dataType; newConst.Value = value; newConst.Comment.Text = comment; Console.WriteLine($"常量添加成功:{constName} = {value}"); }
支持UDT的创建、结构定义、成员增删改、导入导出,导入时支持忽略结构变更/缺失引用:
////// 创建UDT并添加结构成员 /// public static PlcType CreateUDTWithMember(PlcSoftware plcSoftware, string udtName, string memberName, string memberType) { PlcTypeSystemFolder typeSystemFolder = plcSoftware.TypeGroup; PlcType newUDT = typeSystemFolder.Types.Create(udtName); // 为UDT添加成员(UDT成员位于None段) IEngineeringObject interfaceObj = newUDT.GetService(); IEngineeringComposition sections = interfaceObj.GetComposition("Sections"); IEngineeringObject noneSection = null; foreach (IEngineeringObject section in sections) { if (section.GetAttribute("Name").ToString() == "None") { noneSection = section; break; } } if (noneSection == null) throw new Exception("UDT结构段未找到"); IEngineeringObject newMember = noneSection.CreateMember("Member", memberName); newMember.SetAttribute("Datatype", memberType); Console.WriteLine($"UDT创建成功并添加成员:{udtName}.{memberName}"); return newUDT; }
V14 SP1后重构,支持将块/UDT批量生成SCL/STL源文件,便于版本管理:
////// 生成PLC块的SCL源文件 /// private static void GenerateBlockSource(PlcSoftware plcSoftware, Listblocks) { PlcExternalSourceSystemGroup sourceGroup = plcSoftware.ExternalSourceGroup; FileInfo sourceFile = new FileInfo(@"D:SourcesBlocks.scl"); sourceGroup.GenerateSource(blocks, sourceFile); }
将PLC数据导出为标准OPC UA XML格式,用于第三方OPC UA客户端集成:
private static void OpcUaExport(Project project, DeviceItem plcDeviceItem, string exportFilePath)
{
OpcUaExportProvider opcUaExportProvider = project.HwUtilities.Find("OPCUAExportProvider") as OpcUaExportProvider;
if (opcUaExportProvider == null)
{
Console.WriteLine("OPC UA导出服务不可用!");
return;
}
opcUaExportProvider.Export(plcDeviceItem, new FileInfo(exportFilePath));
Console.WriteLine("OPC UA XML导出成功");
}
支持通过API控制PLC的在线/离线状态,查询运行状态、诊断信息:
// PLC离线操作 DeviceItem plcDevice = plcSoftware.Parent.Parent as DeviceItem; OnlineProvider onlineProvider = plcDevice.GetService(); onlineProvider.GoOffline(); // PLC在线连接 onlineProvider.GoOnline();
覆盖S7-1200/1500的运动控制、PID、计数、测量等工艺对象:
硬件配置以AutomationML(AML)格式导入导出(基于CAEX 2.15标准),支持项目级/设备级导出,包含子网、拓扑、GSD设备等高级操作。
CAx导入的冲突处理选项,解决设备名称重复问题:
// CAx导入冲突处理选项
public enum CaxImportOptions
{
MoveToParkingLot = 0,
RetainTiaDevice = 1,
OverwriteTiaDevice = 2
}
////// 项目级CAx数据导出(整个项目的硬件配置) /// private static void CaxExportProject(Project project, string exportFilePath, string logFilePath) { CaxProvider caxProvider = project.GetService(); if (caxProvider == null) { Console.WriteLine("CAx服务不可用!"); return; } caxProvider.Export(project, new FileInfo(exportFilePath), new FileInfo(logFilePath)); Console.WriteLine("项目级CAx导出完成"); } /// /// 设备级CAx数据导出(单个设备的硬件配置) /// private static void CaxExportDevice(Project project, Device device, string exportFilePath, string logFilePath) { CaxProvider caxProvider = project.GetService(); if (caxProvider == null) { Console.WriteLine("CAx服务不可用!"); return; } caxProvider.Export(device, new FileInfo(exportFilePath), new FileInfo(logFilePath)); Console.WriteLine($"设备级CAx导出完成:{device.Name}"); }
private static void CaxImport(Project project, string importFilePath, string logFilePath, CaxImportOptions importOptions)
{
CaxProvider caxProvider = project.GetService();
if (caxProvider == null)
{
Console.WriteLine("CAx服务不可用!");
return;
}
FileInfo importFile = new FileInfo(importFilePath);
if (!importFile.Exists)
{
Console.WriteLine("导入文件不存在!");
return;
}
caxProvider.Import(importFile, new FileInfo(logFilePath), importOptions);
Console.WriteLine("CAx导入完成");
}
可在C#中通过进程调用TIA Portal的命令行工具执行CAx导出导入,适用于批量自动化场景:
///↑ 返回顶部/// 通过命令行执行CAx项目级导出 /// private static void CaxExportByCommandLine(string tiaPortalPath, string projectPath, string exportFilePath) { System.Diagnostics.Process process = new System.Diagnostics.Process(); process.StartInfo.FileName = tiaPortalPath; // 命令行参数:-p项目路径 -m格式(AML) -e导出路径 process.StartInfo.Arguments = $"-p "{projectPath}" -m "AML" -e "{exportFilePath}""; process.StartInfo.UseShellExecute = true; process.StartInfo.Verb = "runas"; // 管理员权限 process.Start(); process.WaitForExit(); Console.WriteLine($"命令行CAx导出完成,退出码:{process.ExitCode}"); } ////// 通过命令行执行CAx导入 /// private static void CaxImportByCommandLine(string tiaPortalPath, string projectPath, string importFilePath, string logPath) { System.Diagnostics.Process process = new System.Diagnostics.Process(); process.StartInfo.FileName = tiaPortalPath; process.StartInfo.Arguments = $"-p "{projectPath}" -m "AML" -i "{importFilePath}" -l "{logPath}""; process.StartInfo.UseShellExecute = true; process.StartInfo.Verb = "runas"; process.Start(); process.WaitForExit(); Console.WriteLine($"命令行CAx导入完成,退出码:{process.ExitCode}"); }
| TIA版本 | .NET框架要求 | 核心API特性 |
|---|---|---|
| V13 SP1 | .NET Framework 4.5 | 基础API,事务用StartTransaction |
| V14 | .NET Framework 4.6 | 独占访问+事务重构,HMI变量属性变更 |
| V14 SP1 | .NET Framework 4.6.1 | 常量拆分、外部源重构、库功能调整 |
| V15/V16/V17 | .NET Framework 4.8 | 工艺对象、OPC UA导出增强 |
| V18+ | .NET Framework 4.8 / .NET 6 | 全功能支持,无 breaking changes |
ExclusiveAccess + Transaction 中TiaPortal 对象必须使用 using 或手动调用 Dispose()| 异常类型 | 原因 | 解决方案 |
|---|---|---|
| 权限拒绝 | 未以管理员运行 | 右键程序→以管理员身份运行 |
| 对象为空 | 设备/块/变量名称错误 | 检查名称拼写,区分大小写 |
| 设备在线 | 写操作时PLC/HMI在线 | 先切换至离线状态 |
| 文件被占用 | 项目已被TIA打开 | 关闭TIA中的项目,或附加到已有进程 |
| 版本不兼容 | dll版本与TIA版本不匹配 | 引用对应版本的西门子程序集 |