4. AVEVA脚本语言基础

在AVEVA System Platform与InTouch的二次开发中,脚本是把静态画面变成动态逻辑的关键。平台里常见的脚本体系主要有两类:一类是InTouch时代的QuickScript(含QuickScript .NET),另一类是System Platform中基于对象模板的AVEVA Script(在IDE中通常以脚本编辑器形式出现,与Automation对象、图形符号绑定)。两者语法风格接近,但运行宿主、作用域和事件模型差异明显,理解这些差异是写出稳定脚本的前提。

一、两种脚本的定位与语法风格

QuickScript .NET运行在InTouch WindowMaker/WindowViewer中,宿主是窗口、控件或应用程序本身。它支持条件判断、循环、函数调用,并可通过.NET扩展访问System.Windows.Forms、System.Data等命名空间。AVEVA Script则运行在Galaxy对象(如Automation对象、图形模板)内部,脚本随对象实例化,天然具备“模板—实例”的继承关系。语法上两者都使用类似C的表达式,但AVEVA Script更强调通过Me、MyArea等关键字访问对象自身属性。

' QuickScript .NET 示例:按钮点击时写入标签
IF $System.TagExists("Reactor1_SP") THEN
    $Reactor1_SP = 75.0;
    LogMessage("SP set to " + Text($Reactor1_SP, "#0.0"));
ELSE
    LogMessage("Tag not found");
ENDIF;

' AVEVA Script 示例:Automation对象脚本
Me.Setpoint = 75.0;
Me.AlarmLimitHigh = 80.0;
IF Me.PV > Me.AlarmLimitHigh THEN
    Me.AlarmState = 1;
ENDIF;

可以看到,QuickScript .NET用$前缀引用InTouch标签,AVEVA Script用Me引用当前对象属性。混用两者是常见错误,例如在Automation对象脚本里写$TagName不会解析到InTouch标签,而应通过对象属性或引用路径访问。

二、变量作用域:局部、窗口、对象与全局

变量作用域决定了脚本能“看见”哪些数据,也决定了并发调用时是否互相干扰。QuickScript .NET中,Dim声明的变量默认是脚本局部变量,每次触发重新初始化;窗口级变量(Window Script中声明)在窗口打开期间保持;应用程序级变量(Application Script)在整个InTouch会话中有效。AVEVA Script中,变量通常绑定到对象属性,作用域随对象实例走,模板中定义的属性在实例中独立存储。

实践建议:需要跨窗口共享的中间结果,优先用应用程序级变量或平台标签;只在单次事件内使用的临时值,用局部变量,避免污染全局命名空间。

下面这张图展示了从事件触发到变量读写、再到结果输出的作用域与数据流关系,帮助区分局部变量、对象属性和全局标签在脚本执行中的位置。

脚本执行中的作用域与数据流 事件源 按钮点击 / 数据变化 / 定时 脚本引擎 QuickScript .NET / AVEVA Script 结果输出 写标签 / 改属性 / 弹窗 / 日志 局部变量(Dim) 每次触发重新初始化 仅当前脚本可见 适合临时计算、循环计数 对象属性 / 窗口变量 随对象实例或窗口存在 Me.Setpoint、WindowVar 模板实例间相互独立 全局标签 / 应用变量 $Tag、Application Var 跨窗口、跨对象共享 需注意并发写入冲突 读写规则速记: • 局部变量只在本次事件内有效,事件结束即释放,不能用于跨事件保持状态。 • 对象属性(Me.xxx)随实例持久化,适合保存设定值、报警状态、累计量。 • 全局标签/应用变量可被多个脚本读写,写入前应判断当前值或加互锁,避免竞争。

三、事件驱动机制:什么时候执行脚本

脚本不是主动轮询,而是由事件触发。QuickScript .NET常见事件包括:按钮的OnClick、窗口的OnShow/OnHide、数据变化脚本(Data Change Script)、条件脚本(Condition Script)以及定时脚本(While/Scheduled)。AVEVA Script则绑定在对象属性变化、对象状态迁移、图形元素动画事件上。理解事件触发时机,才能避免“脚本没执行”或“执行了多次”的问题。

以InTouch数据变化脚本为例,当$Reactor1_PV变化超过死区(Deadband)时触发。若死区设为0,则每次微小波动都会触发,可能造成日志刷屏;若死区设为0.5,则只有变化量超过0.5时才执行。这是工程中必须显式设置的参数。

' 数据变化脚本:PV变化时判断高报警
' 触发条件:$Reactor1_PV 变化量 > 0.5
IF $Reactor1_PV > 80.0 THEN
    $Reactor1_HiAlarm = 1;
    LogMessage("High alarm ON, PV=" + Text($Reactor1_PV, "#0.0"));
ELSE
    $Reactor1_HiAlarm = 0;
ENDIF;

AVEVA Script中,事件通常与对象状态机绑定。例如Automation对象从“Idle”进入“Running”时触发OnStart脚本,从“Running”进入“Stopped”时触发OnStop脚本。这类脚本适合做初始化、清理和状态同步。

四、常用内置函数与工程用法

两类脚本都提供了一批内置函数,覆盖字符串、数学、时间、标签访问和日志。下面列出最常用的一组,并说明典型用途。

函数所属用途示例
Text(值, 格式)两者通用数值转字符串Text(75.3, "#0.0") → "75.3"
StringToValue(字符串)QuickScript .NET字符串转数值StringToValue("75.3") → 75.3
LogMessage(消息)两者通用写诊断日志LogMessage("SP changed")
TagExists(标签名)QuickScript .NET判断标签是否存在IF TagExists("Reactor1_SP") THEN
Me.SetAttribute(名, 值)AVEVA Script设置对象属性Me.SetAttribute("SP", 75.0)
Now() / TimeCurrent()两者通用获取当前时间LogMessage(Text(Now(), "yyyy-mm-dd hh:mm:ss"))
Abs(x)、Sqrt(x)两者通用数学计算Abs(-3.2) → 3.2
注意:不同版本对函数名大小写、参数个数可能略有差异。在正式工程中,建议先在测试窗口或测试对象中验证函数行为,再批量应用到生产画面。

五、一个可复用的脚本片段:设定值写入与越限检查

下面给出一个同时体现变量作用域、事件触发和内置函数使用的示例。场景:操作员在画面输入反应器设定值,点击“应用”按钮后,脚本检查输入是否在0~100之间,合法则写入标签并记录日志,非法则弹窗提示。

' 按钮 OnClick 脚本(QuickScript .NET)
DIM sInput AS STRING;
DIM nSP AS FLOAT;

sInput = $InputBox_Text;          ' 读取输入框文本
nSP = StringToValue(sInput);      ' 字符串转数值

IF nSP >= 0 AND nSP <= 100 THEN
    $Reactor1_SP = nSP;           ' 写入全局标签
    LogMessage("SP applied: " + Text(nSP, "#0.0"));
ELSE
    MessageBox("设定值必须在0~100之间,当前输入:" + sInput);
ENDIF;

这段脚本中,sInput和nSP是局部变量,只在本次点击事件中存在;$Reactor1_SP是全局标签,写入后其他画面和脚本都能读到;StringToValue和Text是内置函数,分别完成类型转换和格式化。若把这段逻辑放到AVEVA Script中,则改为通过Me.InputText读取输入、Me.Setpoint写入属性,并用Me.LogMessage记录。