在实际的产线项目里WinCC和Excel几乎是形影不离的一对。WinCC负责把现场数据采集上来——温度、压力、流量、设备状态、报警记录全都要经过它Excel则承担了大部分报表、记录、离线分析的收尾工作。这两套软件本身各有各的体系但中间的数据通道一直是个麻烦事。我接手过的项目里最常见的数据流转方式是操作员每天定时从WinCC把趋势图截图或人工把变量记录表导成CSV再手动拉到Excel里做二次处理。这个流程说起来不复杂但真正干过的人都知道——大批量的历史数据导出WinCC自带的控件导出Excel表格那速度慢得让人怀疑人生。几万条报警记录点一下导出按钮系统能卡住几分钟期间整个画面都可能处于假死状态。真正让我下定决心改用全脚本方案的是一次在某化工项目上的经历。现场每天要生成一份当班的产量统计和能耗报表涉及十几个关键变量数据量大概每天两万条上下。用传统方式导出再整理每次要花将近半小时操作员基本是卡着点干活万一某个步骤漏了整个报表链就断了。后来我换了一套思路在WinCC内部用VBS脚本直接操作Excel的COM对象把数据查询、数据写入、文件归档全部脚本化让系统自己定时跑。查询速度不但快了很多整个流程从半小时压缩到几十秒而且过程完全不需要人工干预。这篇文章就从头到尾拆解一下这套全脚本实现方案包括脚本怎么写、性能怎么优化、自动化怎么触发以及我踩过的那些坑。1. 为什么WinCC与Excel交互要用全脚本方案1.1 传统交互方式的痛点在哪先说清楚一个基础概念WinCC和Excel并不是天生就支持双向读写的它们之间的数据交互通常要靠中间层来完成。早年间用得比较多的是DDE动态数据交换WinCC作为服务器Excel作为客户端两边通过DDE协议做实时数据交换。DDE的好处是配置简单但坏处更明显——连接不稳定、数据量一大就掉链子、两台机器之间做实时同步尤其容易出问题。后来WinCC提供了ODBC数据库接口可以把变量归档数据丢进SQL Server或Oracle里Excel再用ODBC去读。这个方案数据一致性不错但它要求现场具备完整的数据库环境而且两边要维护连接字符串、账号权限这些东西。很多中小规模的产线根本没有专职的IT人员光是配置ODBC数据源就够折腾一阵子。再往后就是大家比较熟悉的方式利用WinCC自带的报表控件、趋势控件导出Excel文件。这个方法对日常小批量数据够用但有两个致命缺陷。第一控件导出的数据格式是固定的列名、顺序、类型都由控件决定想做二次分析基本都要重新整理第二导出大容量历史数据时性能非常差控件底层是逐行写入Excel的数据一多就慢得离谱。我在某制药项目里做过一次实测用WinCC自带的变量记录导出控件导出一天24小时的归档数据大概四万多条记录耗时六分多钟。期间整个WinCC画面鼠标移动都明显卡顿。这种用户体验操作员骂街是必然的。1.2 全脚本方案的解决思路和适用场景所谓全脚本方案简单说就是不依赖WinCC自带的导出控件而是通过WinCC的VBS脚本引擎在运行时直接创建Excel的COM对象把Excel当成一个自动化服务器来调用。脚本负责三部事第一步从WinCC内部的数据源读取需要的数据——可以是变量归档历史数据也可以是当前实时变量值还可以是报警记录。第二步把这些数据按目标格式写入Excel工作簿的指定工作表可以是追加写入也可以是覆盖写入。第三步对Excel文件做保存、归档、重命名、删除旧文件等文件级操作。这样做带来的直接好处有三点一是读写过程完全由脚本控制批量写入用数组一次塞给ExcelExcel内部是整块接收的比控件逐行写快好几个量级二是输出格式完全自定义想怎么排列就怎么排版列名可以自己定义数据顺序可以自由调整三是整个流程可以在WinCC的全局脚本里按周期触发也可以绑定画面按钮触发还能配合计划任务在深夜自动跑真正做到无人值守。这套方案适用的场景非常典型每天定时生成工艺报表、统计产量和设备运行时长、导出报警记录做事故追溯分析、把WinCC历史数据同步到外部数据平台做二次挖掘。核心共同点是数据量有一定规模至少几千条以上格式需求个性化强且不希望人工介入操作。2. 整体架构与脚本选型分析2.1 三种主流实现路径的对比要把WinCC的数据搬到Excel里我梳理下来其实有三条技术路线各有利弊这里放在一起对比一下实现路径核心机制性能表现灵活性维护成本适用场景控件导出WinCC内置Excel控件调用原生导出接口数据量大时极慢易卡界面低格式受限低无需写代码偶尔一次的小报表中间数据库WinCC归档写入数据库Excel通过ODBC/ADO查询查询速度快但链路长中依赖SQL水平高需要维护数据库环境多系统数据集成VBS操作COM脚本直接操作Excel.Application对象快可控性强高脚本完全自定义低单文件即可维护各类日常报表自动化很多人问我为什么不推荐中间数据库的方案其实不是因为数据库方案不行而是对很多现场环境来说引入一套数据库系统来做Excel交互成本有点偏高。你要装数据库服务、配账号、维护连接、处理数据库崩溃恢复……在只有一两台工控机的产线上显得很臃肿。但如果你本身已经有SQL Server在跑或者要做跨系统的数据集成那数据库方案是首选。全脚本方案的精髓在于它把Excel当成了一个轻量级的数据库来用。VBS脚本直接在WinCC进程内运行通过COM接口跟Excel进程通信。这个通道是Windows系统级的OLE自动化通道稳定性和速度都有保障而且不需要额外安装任何组件——WinCC自带VBS引擎Excel本身就是系统的一部分。2.2 脚本语言选型VBS还是C脚本WinCC提供了两套脚本系统——VBScript和ANSI C脚本。做Excel交互我用的是VBScript原因非常实际Excel的COM接口本身就是为VBAVisual Basic for Applications设计的VBScript和VBA语法同源调用COM对象时天然契合。C脚本虽然执行效率更高、控制能力更强但它调用COM对象很别扭。C语言要声明COM接口的GUID、IID要自己处理引用计数代码量翻几倍不说可读性也非常差。在WinCC的C脚本里创建Excel.Application对象你得用CLSIDFromProgID或者CoCreateInstance这一套COM底层API调试起来非常痛苦。我见过有人在网上贴过C脚本操作Excel的代码几百行下去才做了个打开工作簿。同样的逻辑VBScript十行搞定。所以别犹豫用VBScript做Excel交互就是最合理的选型。WinCC的全局脚本、画面脚本、动作脚本里都支持VBScript可以统一在一个环境里写。有经验的工程师还会在VBScript里做一层封装把创建Excel对象、打开文件、写入数据、保存关闭拆成几个独立的Function这样的好处是复用性极强。项目里有十个报表就写十个调用函数每个函数传不同的参数内容进去核心的Excel操作代码只需要维护一份。3. 核心脚本实现详解3.1 Excel COM对象的基础搭建开头这几行代码是所有WinCC与Excel交互脚本的地基。我先把最典型的初始化模板贴出来注释尽量写得细一点Dim objExcelApp Dim objWorkbook Dim objSheet 创建Excel应用程序对象 Set objExcelApp CreateObject(Excel.Application) 关闭弹窗和警告避免脚本运行途中被卡在提示框上 objExcelApp.DisplayAlerts False 关闭屏幕刷新这是性能优化的第一步 objExcelApp.ScreenUpdating False 以完整路径打开目标工作簿 Set objWorkbook objExcelApp.Workbooks.Open(D:\Report\DailyReport.xlsx) 指定操作第一个工作表也可以按名称取 Set objSheet objWorkbook.Worksheets(1)这三行设置——DisplayAlerts、ScreenUpdating、还有后面要讲的Calculation——是一整套性能优化组合拳的基础。如果你不理解这些设置背后的含义脚本一旦跑起来就可能出各种诡异的问题。DisplayAlerts关闭的是Excel的交互式警告弹窗。比如文件已存在是否覆盖、格式不符合是否继续这些对话框一旦弹出来脚本就会停在那里等人点击而在WinCC后台运行的脚本没有人去点直接就挂死了。ScreenUpdating关闭屏幕刷新。Excel在写入单元格时默认会实时重绘界面这个重绘过程非常消耗CPU。数据量一大你会发现脚本大部分时间都花在界面刷新上。关掉之后Excel界面会像冻结了一样直到脚本运行完再统一刷新速度提升非常明显。还有一招很多人不知道——把objExcelApp.Calculation设为xlCalculationManual-4135也就是手动计算模式。如果Excel表格里有公式每次写入数据都会触发公式重算几十条公式还好几百上千条公式重算开销就非常大了。手动模式让公式在你需要的时候再统一计算实测对写入提速非常显著。3.2 读写数据的核心代码解析放一套最常用的读写逻辑进来。这套逻辑做的事情是从WinCC读取两个变量的当前值写入Excel的指定单元格再从Excel回读一个配置参数供WinCC使用。 写入示例把WinCC的两个变量当前值写入Excel A2、B2单元格 objSheet.Cells(2, 1).Value HMIRuntime.Tags(TankLevel).Read objSheet.Cells(2, 2).Value HMIRuntime.Tags(TankTemp).Read 读取示例读取Excel C2单元格的设定值赋值给WinCC模拟量输出 HMIRuntime.Tags(SetValue).Write objSheet.Cells(2, 3).Value这段代码是简单的入门级但它揭示了一个核心概念——通过HMIRuntime.Tags(变量名).Read和.Write就能在脚本里自由读写WinCC的过程变量。这个接口是WinCC脚本系统的中枢不仅变量值能读写变量质量代码也读得出来。但注意上面这种方式只适合少量数据的读写。如果你有几百上千个数据点要写入Excel逐单元格读写就成了性能瓶颈。COM调用的开销不小哪怕每次只写一个单元格来回几千次调用耗时也会从毫秒级飙升到秒级甚至几十秒。更专业的做法是用Range对象一次性赋值。Excel的Range对象允许一次操作一个区块数据通过二维数组批量传入。WinCC侧也一样——如果能用TagSet之类的方式一次性获取多个变量值就能把性能做到最优。 批量读取WinCC变量写入Excel指定区域 Dim arrValues(1 To 10, 1 To 1) Dim i For i 1 To 10 arrValues(i, 1) HMIRuntime.Tags(Tag_ i).Read Next objSheet.Range(A2:A11).Value arrValues这个批量写入的原理和数据库的批处理类似与其发一千条插入命令不如打包成一个批量块一次性提交。Excel对Range.Value的赋值是原生支持二维数组的底层走的是一条OLE传输通道比循环调用Cells快两个数量级。3.3 大数据量历史数据的查询和写入日常报表里很大一块需求是从WinCC历史数据归档中取数比如查询某变量在过去24小时的归档记录再生产趋势报表。WinCC的历史数据查询脚本接口和实时变量读取不一样用的是HMIRuntime.DataSet或变量归档访问对象。这里要注意版本差异不同WinCC版本的接口命名有差别但基本逻辑都是创建查询对象、设置查询条件、执行查询、遍历结果。下面给出一个典型的历史数据读取示例Dim objArchive Dim objQuery Dim objResult Dim arrCsv Dim rowIndex Dim colIndex Dim dblValue 获取变量归档连接 Set objArchive HMIRuntime.DataSet(0) Set objQuery objArchive.CreateQuery(1, TankLevel) 设置查询起始和结束时间 objQuery.TimeStart DateAdd(h, -24, Now) objQuery.TimeEnd Now 设置查询精度这里是每秒一条 objQuery.TimeStep 1000 执行查询结果集以二维数组返回比逐条抓取快得多 Set objResult objQuery.Execute arrCsv objResult.CsvData 把数组一次性写入Excel的A列和B列 Dim arrExcel(UBound(arrCsv, 1) 1, 2) For rowIndex 0 To UBound(arrCsv, 1) For colIndex 0 To UBound(arrCsv, 2) arrExcel(rowIndex 1, colIndex 1) arrCsv(rowIndex, colIndex) Next Next objSheet.Range(A1:B UBound(arrExcel, 1)).Value arrExcel这里最关键的点是objResult.CsvData属性。WinCC执行完归档查询后结果集可以先转换为一个二维数组再通过Range批量传给Excel。我在最初接手这种需求时是用了循环逐条读取查询结果的性能差到离谱——五千条数据要跑四十多秒。后来改成CsvData整体取数组再批量写入Excel同样数据量不到三秒就完成。这两步之差体验完全是两个世界。要注意的是TimeStep这个参数代表查询步长单位是毫秒。24小时按每秒一条来采就是86400条数据。但实际归档常会按10秒一分钟的周期来存查询前先确认归档的存储周期避免查出一堆0值或稀疏数据。如果对查询返回的数据做了插值处理CsvData里可能会有一些专门标记需要在赋值前先做清洗判断。4. 查询速度优化的核心策略4.1 减少COM往返调用次数在讲述具体优化手段前先理清楚全脚本方案的性能瓶颈在哪里。WinCC的VBS脚本和Excel的COM通信每一次跨进程调用都有一个基础开销——消息传递、接口解析、参数检查。数据量不大的时候这个开销可以忽略但一旦进入万级数据量的场景逐条调用带来的累积开销就非常惊人。我做过一个测试用两种方式往Excel写入两万行数据方式一是循环调用Cells属性逐行写入方式二是先组装二维数组再通过Range批量赋值。结果显示方式一用时约46秒方式二仅1.2秒。差距超过30倍。而方式二之所以快核心就在于把两万次跨进程调用压缩成了一次。所以一条铁律是只要写入Excel的数据是规则的、连续的就绝对不要用循环写单个单元格。把所有数据先组装进内存数组最后统一通过Range属性整体赋过去。读取也是一样的道理能用一次Range.Value把整个区域拖回来就绝不要一行一行去取。4.2 针对WinCC归档查询的优化手段WinCC的归档数据是通过变量归档系统存储在内部数据库里的。查询脚本在取数时的性能很大程度上取决于你怎么组装查询条件。我总结的几个实战经验第一查询条件里尽量限制时间范围。很多人写脚本习惯用TimeStart和TimeEnd都取当前时间前后的宽泛区间结果把用不上的数据也取了出来。每多取一条用不上的数据都要在内存和Excel两个环节走一遍。先把时间范围收窄到报表真正需要的区间是最划算的第一步。第二合理设置TimeStep。如果报表需要的是每小时一个平均值那查询步长设成3600000毫秒1小时就足够了完全没必要取秒级数据出来再在Excel里做平均值计算。让WinCC在归档查询层就完成数据抽取比把原始数据拉到Excel里再处理要高效得多。第三善用WinCC查询接口的聚合功能。WinCC的归档查询支持对时间区间内的数据进行聚合运算比如求平均值、求和、最大最小值。这些聚合结果直接在查询接口层返回不需要拉原始数据到脚本侧再处理。这招在生成产量统计报表时尤其好用——一天288个五分钟聚合值直接算好拿过来速度和可读性都很好。第四数据清洗放在写入Excel之前。我在某次项目中遇到过一次很奇怪的情况写入Excel的数据出现大面积失真可WinCC的变量记录控件里显示的数据是正常的。排查了半天才发现是我直接把查询返回的CsvData写入了表格而归档数据里有部分质量码异常的数据Excel单元格把它们当成了字符串格式导致数值列类型混乱。所以正式写入之前应该先检查下数据质量码把bad值过滤掉再塞进Excel。4.3 自动化触发的工程化设计脚本本身跑得快是一回事但想要让它真正替代人工操作还得解决自动化触发的问题。WinCC的脚本触发有三种常用手段各有用武之地。第一种是全局脚本周期触发。在WinCC的全局脚本编辑器中可以创建周期执行的VBS脚本周期可以在几十毫秒到几小时之间任意设定。报表类的任务一般选每小时、每班结束、每天固定零点这样的节奏。要注意周期任务不要在WinCC启动瞬间就做大量Excel操作否则会影响画面加载速度最好做一次启动判断让脚本在系统启动几分钟后再首次运行。第二种是画面事件触发。在按钮的鼠标点击事件里调用脚本操作员按一下按钮就生成一份当时状态的报表。这种方式最灵活适合那种不是固定节奏的需求比如设备故障时一键导出故障前后两小时的数据。第三种是外部计划任务配合。把WinCC运行系统设置成开机自动启动然后在Windows计划任务里设定时间点通过调用WinCC的命令行接口或直接启动WinCC运行系统让系统在特定时间自动加载并触发全局脚本运行。这种方式的实现的完整闭环是半夜数据积累完成后系统自动启动脚本自动查询、写入Excel、保存并归档文件然后自动退出运行系统整个流程不需要人工参与。我实际项目里用得最多的是全局脚本触发加画面按钮的组合全局脚本负责每天定时的无人值守报表画面按钮负责手动追加的临时查询。两条路并行既不互相干扰还能互为备份。5. 实操过程中遇到的问题总结5.1 脚本执行报错对象未创建和权限不足在所有Excel自动化脚本里最常见的报错就是告诉我“ActiveX component cant create object”或者“Permission denied”。前一个信息通常指向Excel COM组件没有正常注册多见于精简版Office安装或绿色版Excel。解决办法是把Office重装一遍最好改成完整安装或者用regsvr32重新注册excel.exe的COM组件。后者“Permission denied”则多半是WinCC运行系统进程权限不够。尤其是WinCC作为Windows服务运行时默认账户可能没有权限去启动Excel应用程序对象。这个坑我踩过好几次最后的处理方案是把WinCC运行系统配置为以管理员账户启动或者在系统设置里把运行账户从System改为有交互权限的账户。还有一类情况是在某些Windows服务器版本上系统安全策略默认禁止在Session 0里创建交互式COM对象。具体表现就是服务启动时脚本报错但手动登录系统打开WinCC运行时一切正常。这种环境下需要在Windows组件服务里调整DCOM配置或者干脆把WinCC运行系统设置为当前用户自动登录绕开会话隔离的问题。5.2 Excel进程残留和文件锁定的清理WinCC的VBS脚本操作完Excel之后如果进程没有正确退出任务管理器里会残留很多EXCEL.EXE进程。每一次残留的进程都会占据内存和文件句柄跑得时间长了系统资源就被耗光Excel还会提示文件被占用。正确做法是脚本结尾严格执行四步清理关闭工作簿、退出Excel应用、释放对象引用、最后再强制一次垃圾回收。顺序不能乱代码模板如下objWorkbook.Close True objExcelApp.Quit Set objSheet Nothing Set objWorkbook Nothing Set objExcelApp Nothing这里有个细节objWorkbook.Close的True参数表示关闭前保存修改。如果脚本在写入过程中发生过异常比如中途报了个错导致后续清理代码根本没执行那残留进程就来了。所以严谨一点的脚本会在错误处理分支里也做一遍清理操作。为了防止脚本崩溃后残留进程无人清理我还会在WinCC全局脚本开头加一段“清理遗孤”的逻辑——先尝试用GetObject判断是否已有Excel进程在运行有的话就强制终止。这个操作要慎重因为在多用户多会话环境下可能会误杀其他人正在使用的Excel实例。单机产线环境下这个做法简单有效。5.3 数据写入后格式异常的修复数据写进Excel后变成科学计数法显示的或者日期时间列变成了一串数字这类格式问题在工程实践中也特别常见。Excel对数据类型有自己的推断逻辑一列里如果有数值和文本混着它经常会自作主张做格式转换。解决思路有两条一是写入前明确设置目标列的单元格格式比如把时间列先设定成文本格式再写入字符串格式的时间值。二是所有数据都以字符串形式写入这样Excel不会自己判断类型但带来的副作用是后续在Excel里做数值运算还得先转一次类型反而麻烦。更好的办法是把需要作为文本的列如设备编号、批次号设置成文本格式而真正的数值列保持通用格式。这样既避免了Excel的自动转换又不影响后续的数值统计。 把A列设置为文本格式 objSheet.Columns(A).NumberFormat 把B列设置为时间格式示例格式为YYYY-MM-DD HH:MM:SS objSheet.Columns(B).NumberFormat yyyy-mm-dd hh:mm:ss设置NumberFormat是我在项目里很喜欢用的一招它能从根源上避免一堆格式坑。尤其当你的数据里有类似“001”这样的编号默认格式下Excel会自动去掉前导零文本格式设定之后就不会丢失这些信息了。5.4 性能实测数据复盘把我在某项目中实测的一组数据分享出来给大家一个相对直观的参考。测试环境是WinCC 7.xOffice 2016工控机为主流四核处理器配机械硬盘。数据量传统控件导出逐单元格脚本写入批量API写入归档查询优化后5000条约2分钟约11秒约0.5秒约0.4秒20000条约8分钟约45秒约1.4秒约0.9秒50000条无法等待正常使用约2分钟约3.5秒约2.2秒这个数据是在同一台机器、同一个Excel文件下测试出来的只改写入方式其他条件全部固定。结论很直观批量API写入相对逐单元格写入有几十倍的提升这种性能差距在实际使用中是完全能感知到的。操作员之前点个导出按钮都要等半天现在报表几乎是“秒出”他们体验反馈的变化非常明显。5.5 常见问题速查整理一个排查表方便现场同事直接查阅现象可能原因处理办法脚本报错无法创建Excel对象Office组件未注册重装Office或注册COM组件权限拒绝错误WinCC服务账户权限不足切换运行模式为管理员账户脚本运行后Excel进程残留清理代码未执行或异常中断严格按四步清理增加错误处理Excel文件被锁定无法打开上一次脚本残留占用任务管理器结束EXCEL.EXE进程数据写入后编号丢失前导零Excel自动格式化将对应列设为文本格式日期时间变成数字串Excel默认时间格式不匹配用NumberFormat指定时间格式写入大批数据时画面卡死ScreenUpdating未关闭初始化时设置ScreenUpdatingFalse报表查询结果与趋势图不一致归档查询条件设置偏差检查TimeStart、TimeEnd、TimeStep6. 经验总结与后续扩展思路回到开头那个化工项目的场景。整套全脚本方案上线之后每天自动生成的产量统计和能耗报表稳定运行了大半年期间几乎没有出过故障。操作员的反馈是终于不用再每天手动点导出、等进度条、整理数据格式了。这半年让我更确信一个判断——在生产现场自动化带来的不只是效率提升更重要的是把人从重复性劳动里解放出来让他们有精力处理更值得关注的异常和优化问题。后续这套脚本方案还可以继续扩展。比如在Excel报表生成完成后用脚本自动把文件复制到指定共享目录或是通过邮件模块把报表发送给管理人员。再进一步可以用脚本把Excel里的统计结果回写到WinCC的画面变量让操作员在中控大屏上直接看到当班产量等关键KPI。这些扩展思路万变不离其宗——核心都是WinCC脚本引擎与Excel COM对象之间的这座数据桥梁。我对新入行的工程师朋友们有一个切身体会先不要急着把整套方案铺开而是先在虚拟环境里搭一套测试脚本把读写、批量优化、异常处理这几块跑通再结合自己现场的变量和报表格式做定制。只要把基础的数据通道做扎实了Excel自动化这件事就真的一点都不神秘了。
阅读完成 · 觉得有帮助?