4. 变量与数据传递
在 TestStand 中,数据传递的混乱往往不是“变量不够用”,而是“用错了作用域”。同一个测试值,如果放在局部变量里,序列调用结束后就消失;如果放在序列参数里,只能沿调用链传递;如果放在文件全局变量里,同一序列文件内所有序列都能访问;如果放在站全局变量里,整个测试站的所有序列文件都能读写。理解这四类变量的生命周期和可见范围,是避免“数据丢失”“值被覆盖”“回调读不到参数”等问题的前提。
四类变量的作用域与生命周期
TestStand 的变量体系可以按“可见范围”和“生存周期”两个维度来划分。局部变量(Local)属于某个序列,序列开始执行时创建,序列结束时销毁,只有该序列内的步骤能访问。序列参数(Parameters)也属于某个序列,但它由调用者传入,分为输入参数和输出参数,生命周期与序列执行期一致,是序列间传递数据的标准通道。文件全局变量(File Globals)属于某个序列文件(.seq),文件被加载时创建,文件卸载时销毁,同一文件内所有序列和回调都能访问。站全局变量(Station Globals)属于整个测试站,TestStand 引擎启动时创建,引擎关闭时销毁,所有已加载的序列文件都能访问。
这四类变量的关键差异在于“谁能看见”和“活多久”。局部变量最安全但最短命;序列参数最规范但需要显式声明;文件全局变量适合同一文件内的共享状态;站全局变量适合跨文件的全局配置,但滥用会导致序列文件之间产生隐式耦合,降低可移植性。
步骤间传递:局部变量与步骤属性
同一序列内步骤之间传递数据,最直接的方式是使用局部变量。例如在“MainSequence”中,先执行一个“Statement”步骤把计算结果写入 Locals.measuredValue,后续的“Numeric Limit Test”步骤在 Limits 表达式中引用 Locals.measuredValue 进行上下限判断。局部变量的优势是隔离性好,不会污染其他序列;缺点是序列结束后值不再保留,如果下一个序列需要这个值,必须通过参数或全局变量传递。
步骤之间还可以通过步骤的“Post Expression”或“Pre Expression”读写变量。例如在“Call DMM”步骤的 Post Expression 中写 Locals.voltage = Step.Result.Measurement,把测量结果从步骤结果中提取到局部变量,供后续步骤使用。这种写法在 TestStand 中非常常见,关键是要区分“步骤结果”和“用户变量”两个不同的数据容器。
序列间传递:序列参数的输入与输出
序列间传递数据的标准做法是使用序列参数。假设有一个“MeasureVoltage”序列,它需要接收一个量程参数,并返回测量结果。在序列属性中定义输入参数 Range(Number)和输出参数 MeasuredV(Number)。调用者使用“Sequence Call”步骤,在参数映射中把 Locals.rangeSetting 绑定到 Range,把 MeasuredV 绑定到 Locals.result。这样数据就沿着调用链正确流动。
需要注意,输出参数必须在被调用序列内部被赋值,否则调用者读到的是默认值。如果被调用序列提前退出或发生错误,输出参数可能未被写入,调用者应通过 Step.Result.Error.Code 判断调用是否成功,再决定是否使用输出值。对于需要返回多个值的场景,可以把输出参数定义为容器(Container),在容器内放置多个子属性,减少参数数量。
回调间传递:ThisContext 与文件全局变量
回调(Callback)是 TestStand 在特定事件点自动调用的序列,例如 ProcessSetup、PreUUT、PostUUT、MainSequence 等。回调与普通序列一样,可以通过参数接收数据,但更常见的是通过 ThisContext 访问当前执行上下文。例如在 PreUUT 回调中,可以读取 ThisContext.TestSocket.Index 获取当前工位号,也可以写入 FileGlobals.OperatorID 供后续序列使用。
回调之间传递数据时,文件全局变量是最常用的桥梁。例如 ProcessSetup 回调中初始化 FileGlobals.TestCounter = 0,PostUUT 回调中执行 FileGlobals.TestCounter += 1,这样计数器在同一个序列文件内跨回调保持。如果需要在多个序列文件之间共享,则应使用站全局变量,但要注意站全局变量的修改会影响整个测试站,必须谨慎管理。
工程选择原则与常见陷阱
选择变量类型时,可以遵循以下原则:只在当前序列内使用的临时值,用局部变量;需要由调用者传入或返回给调用者的值,用序列参数;同一序列文件内多个序列或回调共享的状态,用文件全局变量;跨序列文件的全局配置或运行时状态,用站全局变量。优先级从高到低依次是:局部变量 → 序列参数 → 文件全局变量 → 站全局变量。越靠前的变量耦合度越低,越容易复用和调试。
常见陷阱包括:在回调中直接读写局部变量,但局部变量属于回调序列本身,无法访问调用者的局部变量;把站全局变量当作“万能存储”,导致序列文件无法独立运行;输出参数未赋值就使用,得到默认值或旧值;在并行测试中多个线程同时写同一个文件全局变量,产生竞态。对于并行场景,应使用锁(Lock)或把数据放在每个工位独立的容器中,避免共享写冲突。
StationGlobals.Socket[0].Result 和 StationGlobals.Socket[1].Result,而不是共用一个 StationGlobals.Result。
掌握这四类变量的边界和传递路径后,实际开发中遇到“数据读不到”“值被覆盖”“回调拿不到参数”等问题时,就可以按“先看作用域、再看生命周期、最后看赋值时机”的顺序排查。大多数数据传递问题,根源都在于把本该用参数传递的数据放进了全局变量,或者把本该用文件全局变量共享的数据放进了局部变量。