☰
WinCC 7.5 SP1按钮操作记录方案:VBS实现二次确认、CSV日志与SAPI语音播报
2026/9/28 1:40:45 网站建设 项目流程

1. 按钮操作记录为什么值得单独做一套方案

在工业上位机项目里,按钮操作记录这件事,说大不大,说小也绝对不小。我做过好几个WinCC7.5SP1的改造项目,甲方在验收阶段最常提的两类需求,一个是"操作能不能留痕",另一个是"关键动作能不能再确认一下"。前者对应操作记录,后者对应二次确认,如果再叠加一个语音播报,整套交互体验就完全不一样了。

很多同行觉得WinCC自带的报警记录和操作员输入消息已经够用了,但实际用下来会发现两个问题。第一,系统自带的记录粒度太粗,它记录的是"变量被写了什么值",而不是"谁在哪个画面点了哪个按钮"。第二,二次确认和语音提示在标准控件里没有现成方案,要么用弹窗硬凑,要么干脆不做。而VBS在WinCC7.5SP1里是原生支持的脚本语言,不需要额外装运行库,配合Windows自带的语音接口就能把这三件事串起来。

这套方案适合谁?如果你正在做WinCC7.5SP1的画面组态,手上有几个关键按钮需要加确认逻辑,同时希望操作动作能落到数据库或者文本文件里方便追溯,那这篇内容基本可以照着抄。哪怕你之前没怎么写过VBS,只要会拖控件、会改属性,跟着走一遍也能落地。下面我会把设计思路、代码细节、踩过的坑全部摊开讲,代码都是实测能跑的,参数也会说明为什么这么设。

2. 整体设计思路与方案选型拆解

2.1 为什么选VBS而不是C脚本

WinCC里做脚本有两个选择,C脚本和VBS。C脚本性能好、能调API,但写起来啰嗦,字符串处理尤其难受。VBS的优势在于语法简单、和Windows系统接口亲和度高,尤其是调用语音播报这种系统级功能时,VBS几行就能搞定,C脚本反而要绕一圈。

具体到这个需求,按钮点击后要做三件事:弹确认框、写记录、播语音。确认框用MsgBox一行搞定,写记录用FileSystemObject或者数据库连接,语音播报用SAPI.SpVoice对象。这三个都是COM组件,VBS调用起来最顺。C脚本虽然也能调COM,但WinCC的C脚本对COM支持有限,调试起来很痛苦。所以选VBS不是因为它更强,而是因为它在这个场景下"够用且省事"。

还有一个现实原因:VBS脚本可以直接在按钮的"鼠标点击"事件里写,不需要编译,改完立即生效。调试阶段这个特性太重要了,你改一行代码点一下按钮就能看到效果,不用等编译。

2.2 二次确认的交互设计考量

二次确认看起来简单,但设计上有几个点要想清楚。首先是确认框的按钮类型,用"是/否"还是"确定/取消"?我建议用"是/否",因为操作员在工业现场往往戴手套操作,按钮越大越好点,而"是/否"的按钮比"确定/取消"更短,视觉上更聚焦。

其次是确认框的标题和内容措辞。标题要写清楚是哪个设备的操作,内容要说明后果。比如"确认启动1号泵?启动后管道将加压",这样操作员点"是"之前能明确知道自己在干什么。我见过有的项目确认框只写"是否确认",操作员根本不知道确认什么,这种二次确认等于没做。

第三是确认框的返回值判断。VBS的MsgBox返回值是数字,vbYes是6,vbNo是7。判断的时候要用常量而不是硬编码数字,否则后面维护的人看不懂。如果操作员点了"否",脚本要直接退出,不能继续往下执行写记录和播语音的逻辑。

2.3 语音播报的实现路径选择

语音播报这块,WinCC本身没有内置功能,必须借助系统接口。Windows提供了两套方案:一套是SAPI(Speech API),通过SAPI.SpVoice对象调用;另一套是直接播放音频文件,用Windows Media Player的COM组件或者SoundPlayer。

SAPI的好处是能把任意文字转成语音,不需要提前录音,适合播报动态内容,比如"1号泵已启动"这种带设备名的句子。缺点是语音音色比较机械,而且不同Windows版本的语音库不一样,Win7和Win10听起来差别挺大。播放音频文件的好处是音质可控,你可以提前录好"设备启动成功"的提示音,缺点是只能播固定内容,动态信息没法播。

我的建议是两者结合:固定提示音用音频文件,动态信息用SAPI。但为了简化,这篇先讲SAPI方案,因为它不需要额外的音频文件,部署起来最省事。如果你对音质有要求,后面我可以再写一篇讲音频文件方案的。

2.4 操作记录存储方式的选择

操作记录存哪里?三个选项:文本文件、CSV文件、数据库。文本文件最简单,但查询不方便;数据库最规范,但需要配置连接;CSV介于两者之间,能用Excel打开,也能用脚本解析。

考虑到WinCC项目通常部署在工控机上,不一定有数据库环境,我建议用CSV文件。格式就是"时间戳,操作员,按钮名称,操作结果",一行一条记录。这样既方便人工查看,也方便后续用脚本做统计分析。如果项目确实需要数据库,把写文件的部分换成ADO连接就行,逻辑是一样的。

文件路径要注意,不能写在WinCC安装目录下,因为那个目录可能需要管理员权限。建议写在D:\OperationLog\这种独立目录,脚本里用CreateFolder确保目录存在。文件名按日期分,比如20250115.csv,这样单文件不会太大,查起来也快。

3. 核心代码细节与实操要点

3.1 按钮点击事件的脚本挂载位置

在WinCC7.5SP1的画面编辑器里,选中按钮控件,右键属性,找到"事件"选项卡。这里要注意,按钮的点击事件有两个:一个是"鼠标点击",一个是"按左键"。区别在于"鼠标点击"是按下并松开后触发,"按左键"是按下就触发。对于需要二次确认的操作,必须用"鼠标点击",否则操作员按下按钮的瞬间就弹确认框,松手的时候可能误触。

挂载脚本的时候,选择"鼠标点击"事件,然后选"VBS动作"。WinCC会打开一个脚本编辑器,里面默认有一个Sub OnClick(ByVal Item)的函数框架。所有的代码都写在这个Sub里面。注意不要改函数名和参数,否则WinCC找不到入口。

还有一个细节:如果按钮上绑定了变量,比如"按下时置位",那这个变量动作和VBS脚本会同时执行。如果你希望确认通过后才改变量,就要把变量动作去掉,全部在VBS里用HMIRuntime.Tags("变量名").Write来写。这样控制权完全在脚本手里,逻辑更清晰。

3.2 二次确认框的代码实现与参数说明

确认框的核心代码就一行:

Dim ret ret = MsgBox("确认启动1号泵?启动后管道将加压。", vbYesNo + vbQuestion, "操作确认 - 1号泵启动") If ret <> vbYes Then Exit Sub End If

这里vbYesNo + vbQuestion是按钮和图标组合,vbQuestion会显示一个问号图标,视觉上提示操作员需要做决定。标题里带上设备名,方便操作员确认自己点的是哪个按钮。

有个坑要注意:MsgBox是模态对话框,它会阻塞WinCC的画面刷新。如果确认框弹出来之后操作员一直不点,画面上的其他数据就不会更新。对于实时性要求高的画面,这个阻塞可能是问题。解决办法是用非模态的自定义弹窗,但那需要额外做画面,复杂度高很多。我的经验是,确认框一般几秒内就会被点掉,阻塞影响可以接受。如果确实不能阻塞,那就得用画面窗口做确认层,这个后面可以单独展开。

还有一个细节:MsgBox的返回值在VBS里是vbYes(6)和vbNo(7),但如果你用了vbOKCancel,返回值就是vbOK(1)和vbCancel(2)。判断的时候一定要对应上,否则逻辑会反。

3.3 操作记录的写入逻辑与文件格式

写记录用FileSystemObject,核心代码如下:

Dim fso, logFile, logPath, logLine Dim operatorName, buttonName, result logPath = "D:\OperationLog\" operatorName = HMIRuntime.Tags("@CurrentUser").Read buttonName = "1号泵启动按钮" result = "确认通过" Set fso = CreateObject("Scripting.FileSystemObject") If Not fso.FolderExists(logPath) Then fso.CreateFolder(logPath) End If logFile = logPath & Year(Now) & Right("0" & Month(Now), 2) & Right("0" & Day(Now), 2) & ".csv" logLine = Now & "," & operatorName & "," & buttonName & "," & result If fso.FileExists(logFile) Then Dim ts Set ts = fso.OpenTextFile(logFile, 8, True) ts.WriteLine logLine ts.Close Else Dim ts2 Set ts2 = fso.CreateTextFile(logFile, True) ts2.WriteLine "时间,操作员,按钮,结果" ts2.WriteLine logLine ts2.Close End If

这里有几个关键点。第一,@CurrentUser是WinCC的系统变量,存的是当前登录的用户名,如果没启用用户管理,这个值可能是空的,那就要用HMIRuntime.Tags("@UserName").Read或者干脆写"未登录"。第二,OpenTextFile的第二个参数8是ForAppending,表示追加模式,第三个参数True表示文件不存在时创建。第三,CSV文件第一次创建时要写表头,后面追加就不写了。

文件名的日期格式用了Right("0" & Month(Now), 2)这种写法,是为了保证月份和日期都是两位数,比如1月写成"01",这样文件名排序才正确。如果直接写Month(Now),1月和10月的文件名排序会乱。

3.4 语音播报的SAPI调用与语速控制

语音播报的代码也不复杂:

Dim voice Set voice = CreateObject("SAPI.SpVoice") voice.Rate = 0 voice.Volume = 100 voice.Speak "1号泵已启动"

Rate是语速,范围-10到10,0是正常速度。工业现场环境嘈杂,建议设成-2到0之间,慢一点更清楚。Volume是音量,0到100,一般设80到100。Speak方法是同步的,会等语音播完才返回。如果你不希望阻塞脚本,可以用Speak的第二个参数SVSFlagsAsync,但那样语音会和后续操作重叠,一般不建议。

有个坑要特别注意:SAPI.SpVoice对象在WinCC的VBS环境里创建时,如果系统没有安装语音库,会报错。Windows10默认有中文语音库,但Windows7可能只有英文的。如果播报中文时听到的是英文发音或者没声音,就要去系统设置里添加中文语音包。另外,SAPI的语音是异步加载的,第一次调用可能会有几百毫秒的延迟,如果对实时性要求高,可以在画面启动时先创建一个全局的voice对象,后面复用。

还有一点,Speak方法播报的内容如果是动态拼接的,要注意特殊字符。比如设备名里如果有引号,会破坏字符串。建议在拼接前用Replace把引号替换掉。

3.5 完整脚本的整合与执行顺序

把上面几段拼起来,完整的按钮脚本是这样的:

Sub OnClick(ByVal Item) Dim ret, fso, logFile, logPath, logLine Dim operatorName, buttonName, result, voice buttonName = "1号泵启动按钮" ret = MsgBox("确认启动1号泵?启动后管道将加压。", vbYesNo + vbQuestion, "操作确认") If ret <> vbYes Then result = "取消操作" Call WriteLog(buttonName, result) Exit Sub End If result = "确认通过" Call WriteLog(buttonName, result) Set voice = CreateObject("SAPI.SpVoice") voice.Rate = -1 voice.Volume = 90 voice.Speak "1号泵已启动" HMIRuntime.Tags("Pump1_Start").Write 1 End Sub Sub WriteLog(btnName, res) Dim fso, logFile, logPath, logLine, operatorName logPath = "D:\OperationLog\" operatorName = HMIRuntime.Tags("@CurrentUser").Read If operatorName = "" Then operatorName = "未知用户" Set fso = CreateObject("Scripting.FileSystemObject") If Not fso.FolderExists(logPath) Then fso.CreateFolder(logPath) logFile = logPath & Year(Now) & Right("0" & Month(Now), 2) & Right("0" & Day(Now), 2) & ".csv" logLine = Now & "," & operatorName & "," & btnName & "," & res If fso.FileExists(logFile) Then Dim ts Set ts = fso.OpenTextFile(logFile, 8, True) ts.WriteLine logLine ts.Close Else Dim ts2 Set ts2 = fso.CreateTextFile(logFile, True) ts2.WriteLine "时间,操作员,按钮,结果" ts2.WriteLine logLine ts2.Close End If End Sub

执行顺序是:先弹确认框,根据返回值决定是否继续;然后写记录,不管确认还是取消都写;最后如果确认通过,播语音并写变量。注意写变量放在最后,因为写变量可能触发其他脚本或报警,放在最后能保证记录已经落盘。

4. 实操过程与关键环节实现

4.1 环境准备与前置检查

在开始写脚本之前,有几项环境检查必须做。第一,确认WinCC7.5SP1的VBS功能已启用。在WinCC项目管理器的"计算机"属性里,找到"启动"选项卡,确保"全局脚本"和"画面脚本"都勾选了。如果没勾,脚本不会执行。

第二,确认系统有SAPI语音库。打开"控制面板"的"语音识别"或者直接在运行里输入powershell -Command "Add-Type -AssemblyName System.Speech; (New-Object System.Speech.Synthesis.SpeechSynthesizer).GetInstalledVoices() | Select VoiceInfo",能看到中文语音库就行。如果没有,去系统设置的"时间和语言"里添加中文语音包。

第三,确认日志目录有写权限。在工控机上,D:\盘一般是数据盘,权限比较宽松。如果只有C盘,建议在C:\ProgramData\下建目录,这个目录默认对所有用户可写。不要用C:\Program Files\,那个目录需要管理员权限,WinCC运行时可能没有。

第四,确认当前登录用户。如果WinCC启用了用户管理,操作员登录后@CurrentUser才有值。如果没启用,这个变量是空的,脚本里要处理空值情况,否则记录里操作员字段就是空白。

4.2 按钮控件的属性配置

在画面里拖一个按钮控件,右键属性,几个关键属性要改。在"常规"选项卡里,把"按钮文本"改成"1号泵启动","对象名称"改成btnPump1Start,方便后面识别。在"事件"选项卡里,找到"鼠标点击",点右边的闪电图标,选"VBS动作",把上面的代码粘进去。

如果按钮需要显示状态,比如启动后变绿,可以在"属性"选项卡里绑定背景颜色到变量。但注意,如果按钮的变量动作和VBS脚本同时存在,可能会有冲突。我的做法是按钮只负责触发脚本,状态显示用单独的指示灯控件,这样职责清晰。

还有一个细节:按钮的"安全性"属性里可以设置权限等级,只有特定用户才能点击。这个和VBS里的二次确认是互补的,权限控制"能不能点",二次确认控制"点了之后要不要再确认"。两个一起用,安全性更高。

4.3 脚本调试与断点技巧

WinCC的VBS调试不太方便,没有断点功能。我的做法是在关键位置加MsgBox输出中间变量,比如在写记录之前弹一个框显示logLine的内容,确认格式正确后再把调试的MsgBox删掉。

另一个技巧是用HMIRuntime.Trace输出到WinCC的诊断窗口。在脚本里写HMIRuntime.Trace "logLine=" & logLine & vbCrLf,然后在WinCC的"工具"菜单里打开"诊断窗口",就能看到输出。这个不会阻塞画面,比MsgBox好用。

如果脚本报错,WinCC会在诊断窗口显示错误信息,但信息比较简略。常见错误有"对象不支持此属性"(通常是COM组件没注册)和"权限拒绝"(文件路径没写权限)。遇到报错先看诊断窗口,再去查对应的COM组件或路径。

4.4 语音播报的实测效果与参数调优

我在一台Win10工控机上实测,SAPI的中文语音播报"1号泵已启动"大概需要1.5秒,语速设为-1时约1.8秒。这个延迟在操作确认场景下可以接受,因为操作员点完确认后本来就需要一点反应时间。

音量方面,工控机通常接的是小功率喇叭,设90和100差别不大,但设50就明显偏小。建议设80以上。如果现场噪音大,可以考虑外接功放,但那是硬件层面的事,脚本里把音量拉满就行。

语速方面,-2到0之间比较合适。设成-5会慢得让人着急,设成5会快得听不清。如果播报内容比较长,比如"1号泵已启动,当前压力0.5兆帕",建议语速设0,否则信息量太大听不过来。

还有一个实测发现:SAPI对象第一次创建时会有约300毫秒的延迟,后面复用就快了。如果按钮点击频繁,可以在画面启动脚本里创建一个全局voice对象,按钮脚本里直接用。但WinCC的VBS全局变量支持有限,简单做法是在按钮脚本里创建,接受那300毫秒延迟。

4.5 操作记录的验证与查询方法

脚本跑起来之后,怎么验证记录写对了?最简单的办法是点几次按钮,然后去D:\OperationLog\目录看当天的CSV文件。用Excel打开,检查四列是否都有值,时间格式是否正确,操作员是不是当前登录用户。

如果发现记录没写进去,先检查目录是否存在。脚本里虽然有CreateFolder,但如果父目录D:\不存在(比如只有C盘),就会报错。这时候要改成C:\ProgramData\OperationLog\。

如果记录写了但操作员是空的,说明@CurrentUser没读到值。可以在脚本里加一个判断,如果为空就写"未登录用户"。更好的做法是检查WinCC的用户管理是否启用,如果没启用,考虑用Windows登录名代替,通过CreateObject("WScript.Network").UserName获取。

查询方面,CSV文件可以用Excel的筛选功能按操作员或按钮名过滤。如果记录量大,可以写一个VBS脚本定期把CSV导入数据库,但那是另一个话题了。

5. 常见问题与排查技巧实录

5.1 确认框不弹出或弹出后画面卡死

确认框不弹出,最常见的原因是脚本没挂载到正确的事件上。检查按钮的"鼠标点击"事件里是否有VBS动作,以及动作是否被禁用。另外,如果按钮的"安全性"权限设了但当前用户没权限,点击也不会触发脚本。

弹出后画面卡死,是因为MsgBox是模态的,会阻塞WinCC的UI线程。如果操作员不点,画面就一直不刷新。解决办法前面提过,用非模态画面窗口代替MsgBox。如果暂时不想改,可以在确认框上加一个超时自动关闭的逻辑,但VBS的MsgBox不支持超时,只能用WScript.Shell的Popup方法,那个支持超时参数。

Dim shell, ret Set shell = CreateObject("WScript.Shell") ret = shell.Popup("确认启动1号泵?", 10, "操作确认", vbYesNo + vbQuestion)

这里的10是超时秒数,超时后返回-1。判断的时候要处理-1的情况,当作取消处理。

5.2 语音播报没声音或报错

没声音先检查系统音量是否静音,再检查SAPI语音库是否安装。如果报错"ActiveX部件不能创建对象",说明SAPI没注册。在运行里执行regsvr32 sapi.dll可以重新注册,但注意要用管理员权限。

如果播报英文正常但中文没声音,说明缺中文语音库。Win10在"设置"的"时间和语言"里可以添加中文语音包,Win7需要单独安装。安装后在SAPI里用voice.GetVoices枚举,选择中文的voice对象。

还有一个坑:如果WinCC项目是以服务方式运行的,SAPI可能无法访问音频设备。这种情况要把WinCC改成以应用程序方式运行,或者用音频文件播放代替SAPI。

5.3 操作记录文件写入失败

写入失败最常见的原因是权限不足。如果日志目录在C:\Program Files\下,普通用户没有写权限。解决办法是换到C:\ProgramData\或D:\盘。另一个原因是文件被Excel占用,如果操作员正用Excel打开当天的CSV文件,脚本写入会失败。解决办法是写入前先检查文件是否被占用,或者改用按小时分文件,减少冲突概率。

如果文件写入了但内容是乱码,说明编码不对。CreateTextFile的第三个参数是True表示Unicode,False表示ASCII。中文内容要用Unicode,否则会乱码。但Unicode的CSV用Excel打开可能显示不正常,解决办法是用ADODB.Stream写UTF-8编码的文件,那个Excel能正确识别。

5.4 脚本执行速度慢或画面卡顿

脚本执行慢通常是COM对象创建开销大。FileSystemObject和SAPI.SpVoice每次创建都要几百毫秒。如果按钮点击频繁,可以考虑把日志写入改成异步的,比如先写到一个内存队列,后台脚本定期落盘。但那样复杂度高,一般项目没必要。

画面卡顿如果是因为MsgBox阻塞,前面说了用Popup代替。如果是因为语音播报同步阻塞,可以用异步播报:

voice.Speak "1号泵已启动", 1

第二个参数1是SVSFlagsAsync,表示异步播报,脚本不等待语音结束就继续执行。但这样语音可能和后续操作重叠,要权衡。

5.5 常见问题速查表

问题现象可能原因排查方法解决方案
确认框不弹出脚本未挂载或权限不足检查事件挂载和用户权限重新挂载脚本,调整权限
画面卡死MsgBox模态阻塞观察是否只有确认框弹出时卡改用WScript.Shell.Popup带超时
语音没声音语音库缺失或静音检查系统音量和语音库安装中文语音包,取消静音
记录写入失败目录无权限或文件被占用检查目录权限和文件占用换目录,按小时分文件
记录乱码编码不匹配用记事本打开看编码改用UTF-8编码写入
脚本执行慢COM对象创建开销计时观察哪段慢复用对象或异步处理

5.6 几个我踩过的坑和独家技巧

第一个坑:WinCC的VBS里不能用On Error Resume Next来忽略错误,因为WinCC的脚本引擎对错误处理支持不完整。如果某行代码出错,整个脚本会中断,后面的代码不执行。解决办法是在关键操作前加判断,比如写文件前先判断目录是否存在,而不是靠错误处理。

第二个坑:HMIRuntime.Tags("@CurrentUser").Read在用户未登录时返回的是空字符串,不是Null。判断的时候要用If operatorName = "" Then,不能用IsNull。

第三个技巧:如果项目里有多个按钮需要同样的逻辑,可以把公共代码写成一个Sub,放在全局脚本里,按钮脚本里调用。WinCC的全局脚本在"全局脚本"编辑器里,VBS的全局函数可以被画面脚本调用。这样改一处就能影响所有按钮,维护效率高很多。

第四个技巧:日志文件建议加一个"操作结果"字段,除了"确认通过"和"取消操作",还可以加"执行失败"。如果写变量失败,记录里要体现出来,否则事后追溯时不知道操作到底成没成功。

第五个技巧:如果甲方要求操作记录不可篡改,可以把CSV文件设成只读,或者写入后立即计算一个校验值存到另一个文件。但工控机上的操作员通常也是管理员,真要篡改拦不住,所以这个需求一般用数据库的审计功能实现,CSV方案只能做到"有记录",做不到"防篡改"。

6. 方案扩展与后续优化方向

这套方案跑通之后,有几个方向可以继续优化。第一个是把日志从CSV换成SQLite数据库,SQLite不需要安装服务,单文件就能用,查询比CSV方便得多。VBS可以通过ADODB.Connection连接SQLite,但需要装SQLite的ODBC驱动。

第二个是把语音播报从SAPI换成预录制的音频文件。用WScript.Shell的Run方法调用系统播放器,或者用WMPlayer.OCX控件播放MP3。音质更好,但只能播固定内容。如果播报内容需要动态拼接,可以预录几个片段,比如"1号泵"、"2号泵"、"已启动"、"已停止",然后按顺序播放,这样既有音质又有灵活性。

第三个是把二次确认从MsgBox换成自定义画面窗口。在WinCC里做一个确认画面,包含操作描述、确认按钮、取消按钮,用OpenPicture函数弹出。这样不阻塞主画面,而且界面可以做得更美观,还能加倒计时自动取消。

第四个是把操作记录和WinCC的报警记录关联起来。操作记录写CSV的同时,也触发一条WinCC的操作员消息,这样在报警控件里也能看到操作历史。WinCC提供了MSRTGenerateMessage函数,可以在VBS里调用。

这些扩展方向每一个都可以单独写一篇,但核心逻辑和这篇是一样的:确认、记录、播报。把基础版本跑通,后面加功能就是搭积木。

我个人在实际项目中的体会是,按钮操作记录这件事,技术难度不高,但细节特别多。权限、编码、路径、阻塞、语音库,每一个都可能让方案翻车。最稳妥的做法是先在一个按钮上跑通全流程,确认记录能写、语音能播、确认框能弹,然后再复制到其他按钮。不要一上来就批量改,否则出了问题很难定位是哪个环节的错。另外,日志目录一定要提前和甲方确认,有些工控机只有C盘,有些有D盘但没格式化,这些都要在部署前检查清楚。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询