简介泰克 TSP Toolkit 官方快速入门指南以 PDF 形式呈现专为从事电子测试与测量的工程师、技术员和开发者编写。指南详细讲解如何安装和使用基于 Visual Studio Code 的开源扩展在支持 TSP 技术的泰克仪器上编辑、运行与调试 .tsp 脚本解决仪器控制与自动化测试中脚本开发效率低、排错难的问题。内容由浅入深从扩展安装、工作区配置、仪器连接到项目设置、脚本运行与调试、终端使用再到自动化脚本生成和下载示例脚本每一步均有操作指引。工具内建语法检测、代码补全、悬停帮助与命令集文档可显著降低入门门槛。资源包为单个 PDF 文件大小约 1.55MB轻量便于随时查阅。目前已有 260 人学习下载。文档特别强调了仪器连接方式和项目配置方法并配合 GitHub 示例脚本可帮助读者快速搭建测试环境、定位脚本问题加速 IV 测试等常用自动化流程的落地。无论你是初次接触 TSP 脚本还是希望优化既有测试程序这份指南都能帮助你快速上手并减少试错成本。1. 从逐条SCPI到仪器端TSP这套VS Code脚本工具包改变了什么做过源表自动化的人应该都体会过这条链路上位机循环里拼SCPI命令逐条发出去再逐条等回应。测量一万个点就意味着至少一万次网络往返调度一忙数据就堵在缓冲区里。基于Visual Studio Code 的 TSP 脚本开发工具包要解决的正是这个「上位机太累、仪器太闲」的错位。TSP 是仪器内置的脚本处理器复用 Lua 语法让循环、判断、数据归档直接在仪表端完成。这套工具包对三类人最有价值要跑大批量 IV 扫描或脉冲序列的测试工程师想把产线测试写成可版本管理的脚本、而不是一长串记事本命令的自动化开发以及刚拿到支持 TSP 的源表、想用最短路径建立本地开发环境的初学者。它解决的痛点很明确在 VS Code 里获得语法高亮、自动补全和代码片段在需要时把脚本完整下发到仪器再用回传的 print 输出做交互式调试。别把 TSP 当成新一套 SCPI 替代品它真正的改变是执行位置。理解这一点以后环境配置和踩坑排查才有依据。2. TSP脚本模型先立住仪器里的Lua解释器与你手里编辑器各管哪一段2.1 慢网络下的快测量为什么TSP把循环放进仪器而不是上位机SCPI 的核心单位是命令命令之间天然有网络往返。TSP 的核心单位是脚本脚本可以在仪器内部独立跑完一整段流程。源表类仪器通常内置 Lua 解释器你下发的不再是零零碎碎的单条指令而是一个带变量、循环、函数调用的完整程序。这个设计最直接的好处有两个一是大幅减少上位机与仪器之间的通信次数二是让时间敏感的操作不再依赖上位机调度精度。维度SCPI 逐条下发TSP 脚本下放基本单位单条命令完整 Lua 程序块控制流上位机负责仪器端负责循环效率每条循环都走一次网络循环在仪器内执行数据回传每次查询返回一次结果脚本内 print 统一回传适用场景少量手动验证批量扫描、产线自动化我做自动化测试时有个体会当测量点数从几十涨到几千SCPI 的瓶颈会非常明显界面像卡死一样仪器却在那边空转等待。换成 TSP 之后同样的业务流程在仪器端跑完网络只承载最终结果和必要的调试输出整个流程干净很多。2.2 loadscript 到底发生了什么下发、驻留与执行的边界直接往 TSP 仪器的远程终端里粘贴下面这段可以看到脚本的完整生命周期loadscript stress_scan for i 1, 5 do -- 这里的逻辑由仪器端 Lua 解释器逐行执行 print(step, i) waitcomplete() end endscript stress_scan()这段代码的关键在loadscript与endscript这对命令。loadscript后面跟着的stress_scan是脚本名中间所有内容会被仪器的脚本管理器捕获为一段可调用的程序endscript表示定义结束。你看到stress_scan()在最后单独出现是因为前面只是定义真正执行还要靠这次调用。如果不调用仪器什么也不会发生。这里就是VS Code工具包介入的地方了编辑器负责 Lua 语法与逻辑的静态检查而loadscript这类外壳命令更适合交给下发脚本自动处理。我一般不在源文件里混写loadscript源文件保持纯 Lua工具包封装好发送过程这样语言服务器可以稳定工作。2.3 调试信息怎么回传print、waitcomplete 与远端缓冲TSP 脚本执行时仪器端唯一稳定的回传通道是print。print的内容会进入仪器远程会话的输出缓冲上位机通过 VISA 的 read 接口逐行读取。和桌面程序不一样TSP 里没有打断点看变量的交互界面调试全靠把关键状态用print打出来。我的习惯是在每个阶段切换后打一行状态标记这样即使脚本跑挂了也能源头定位到最后成功的行。waitcomplete()是另一个必须理解透的同步点。TSP 仪器内部的测量操作经常进入异步队列命令已经发出但数据还没准备好。waitcomplete()会阻塞脚本执行直到队列里的操作全部完成。它在 TSP 脚本里的作用相当于给数据流装了一道闸门保证后面读到的数据是当前这一轮的而不是上一轮的残留。2.4 编辑端凭什么选 VS Code跨平台、Git 与任务机制TSP 脚本本质是文本编辑器的首要任务是语法正确和可追溯。VS Code 的优势不在仪器通信而在工程化跨平台一致体验、内置 Git 客户端、任务自动化和代码片段管理。你不需要引入庞大的 IDE装一个 Lua 语言服务器把.tsp关联到 Lua就能获得补全和语法诊断。搭配一个 Python 下发脚本按CtrlShiftB就能把当前文件送到仪器执行。这套组合轻量也适合放进产线自动化框架里统一管理。3. 用VS Code把最小TSP脚本跑通语言服务、工作区与一键下发3.1 让编辑器认识TSP脚本Lua语言服务器与API声明文件第一步是把 VS Code 配成一个能看懂 TSP 的编辑器。我常用的做法是安装 Lua Language Server再把.tsp后缀关联到 Lua 语言。这样打开脚本文件时高亮、括号匹配、语法检查都是现成的。工作区创建.vscode/settings.json写入如下配置{ files.associations: { *.tsp: lua }, Lua.runtime.version: Lua 5.3, Lua.workspace.library: [ lib ], Lua.diagnostics.globals: [ smua, waitcomplete, loadscript, endscript ] }这里把Lua.runtime.version设为Lua 5.3是考虑到 TSP 仪器内置解释器普遍基于 Lua 5.0/5.1 分支5.3 的诊断能力覆盖大部分语法又不至于启用太新的语言特性。Lua.workspace.library指向工作区下的lib目录这个目录里放一个 TSP 全局 API 声明文件语言服务器读取后就能识别smua、waitcomplete这些仪器端才存在的全局符号。在lib/tsp-globals.lua里我一般放这些声明-- 以下是 TSP 全局 API 的本地补全声明不会发送到仪器 smua {} smua.source {} smua.measure {} script {} function script.list() end function waitcomplete() end function loadscript(name) end function endscript() end这些空函数和空表只是用来告诉语言服务器「这些符号是存在的」。这样你在.tsp文件里写smua.source.levelv时不会因为全局变量未定义而满屏红色波浪线。声明文件本身不参与下发它是纯本地的编辑器辅助资源这也是工具包和普通文本编辑的本质区别。3.2 最小TSP脚本文件从编辑到代码结构工作区跑通以后新建一个hello.tsp先不要写任何loadscript外壳只写纯 Lua 逻辑-- hello.tsp最小可用 TSP 脚本 local sum 0 for i 1, 4 do sum sum i -- 仪器端会把这行内容回传给上位机 print(i, i, sum, sum) end print(final, sum)这段脚本做的事很简单循环累加边加边用print回传状态。它验证的是三件事编辑器能正常解析 Lua 语法Python 下发通道能正确传文件仪器端能执行循环并回传输出。先跑通这条链路再往上加源表测量逻辑会从容很多。在源文件里保持纯 Lua 还有一个隐性好处当你需要把一个脚本迁移到另一台 TSP 仪器或交给同事复用文件内容不掺杂外壳命令语义清晰。loadscript外壳由发送工具自动补后续改脚本名也只要改发送参数。3.3 一键下发用任务和Python把当前文件送到仪器下发工具我用的是 PyVISA它提供跨平台 VISA 资源访问代码短且容易集成。先安装依赖pip install pyvisa pyvisa-py网络连接一般用 pyvisa-py 就能顶住USB 连接则建议搭配厂商提供的 VISA 运行时。接着在工作区根目录创建tools/send_tsp.pyimport sys import pyvisa def send_file(addr, file_path): rm pyvisa.ResourceManager() inst rm.open_resource(addr) inst.timeout 30000 # 毫秒长测试时必须加大 inst.write_termination \n inst.read_termination \n with open(file_path, r, encodingutf-8) as f: source f.read() source source.replace(\r\n, \n) if loadscript not in source: # 自动包一层具名脚本并在末尾执行 source loadscript devscript\n source \nendscript\ndevscript()\n inst.write(source.rstrip(\n) \nprint(__TS_DONE__)\n) try: while True: line inst.read() if line.strip() __TS_DONE__: break print(TSP:, line) except pyvisa.errors.VisaIOError: print(-- script done --) finally: inst.close() if __name__ __main__: send_file(sys.argv[1], sys.argv[2])这个脚本的逻辑分四步打开 VISA 资源并设置超时和换行符读取.tsp文件内容判断是否需要自动包loadscript外壳写入仪器并循环读取print回传。__TS_DONE__是哨兵标记读到它就认为脚本执行完毕不至于每次都等满超时时间。inst.timeout的桌面单位是毫秒。批量扫描时如果预期一轮测试要 60 秒这里至少设成 90000否则脚本还没跑完上位机先放弃等待了。write_termination和read_termination统一成\n是为了避开 Windows 下\r\n引起的解析错乱。调用方式举例如下python tools/send_tsp.py TCPIP0::192.168.1.108::inst0::INSTR hello.tsp然后在.vscode/tasks.json里注册一个默认构建任务让命令可以在编辑器里直接触发{ version: 2.0.0, tasks: [ { label: send-tsp, type: shell, command: python, args: [ ${workspaceFolder}/tools/send_tsp.py, TCPIP0::192.168.1.108::inst0::INSTR, ${file} ], group: { kind: build, isDefault: true }, problemMatcher: [] } ] }按下CtrlShiftB当前打开的.tsp文件就会被下发并执行。Windows 上如果python命令不可用把command改成py -3。这套任务机制的好处是团队里任何人拿到工作区按下同一个快捷键就能跑同一段下发流程不依赖记忆菜单操作。3.4 首次连接验证先别跑业务逻辑第一次连仪器我建议先做一次最小回读验证确认链路通、地址对、换行符匹配再跑真正的测量脚本。python -c import pyvisa; rmpyvisa.ResourceManager(); instrm.open_resource(TCPIP0::192.168.1.108::inst0::INSTR); print(inst.query(print(100)))这里query(print(100))发过去的是 TSP 命令仪器执行后会回传100。如果能看到100说明 VISA 资源名和网络配置没问题。如果超时先确认上位机到仪器的网络能 Ping 通再把资源字符串里的inst0和INSTR换成仪器实际支持的接口名。这一步能隔离出「网络问题」和「脚本问题」后面调试会省很多时间。4. 调试TSP脚本时最该较真的三件事等待完成、数据回传与脚本驻留4.1 同步问题为什么waitcomplete不能省TSP 脚本在仪器端虽然是顺序执行的但源表类仪器内部存在异步队列。一条测量命令发出后数据采集可能还在进行中下一条脚本语句却已经踩上来了。这是我见过最多的翻车点明明读到了值却是上一轮或旧状态的残留。-- 开启输出并设定电压 smua.source.output smua.OUTPUT_ON smua.source.levelv 1.0 -- 触发一次测量 smua.measure.iv() -- 等队列排空再继续 waitcomplete() print(channel ready)这里waitcomplete()是 TSP 里专门用来同步的挂起函数。它不接收业务参数只负责阻塞脚本直到之前排入的异步操作全部完成。测量、量程切换、输出电压变更这类操作之后如果后续语句依赖操作结果都应该补一个waitcomplete()。无脑在每个阶段之间塞一个代价是几次毫秒级延迟但能避免一大批难以复现的诡异数据问题。4.2 print 回传数据怎么解析缓冲、换行与超时脚本下发后仪器端print产生的文本会依次进入远程会话的缓冲区。上位机读取时要注意两个匹配读终止符要和仪器输出一致超时设置要大于脚本的最长执行时间。我的工具使用read_termination\n是因为 TSP 的 print 默认以换行结束每条记录。读回传数据时有一个常见误区以为脚本执行完所有 print 就立即可以读。实际上仪器是执行一行、输出一行上位机必须循环 read直到遇见约定的结束哨兵。这也是我在下发脚本末尾统一加__TS_DONE__的原因避免通过猜「等多久」来判定脚本是否结束。while True: line inst.read() if line.strip() __TS_DONE__: break print(TSP:, line)如果你要在回传数据里提取数值别直接用字符串分割硬编下标。建议每一行 print 固定格式比如用keyvalue的键值结构上位机用split()解析。这样即使字段顺序调整解析逻辑也不容易崩。4.3 脚本驻留的坑内存里的那半片脚本loadscript创建的脚本驻留在仪器内存中不会自动写入持久存储。仪器重启后这些脚本会消失。这不算 bug但工程上一旦脚本内部还引用了另一段脚本就会出现重启后「函数找不到」的连锁报错。我见过有人把公共函数放在一段脚本里测量流程放在另一段仪器一重启整个测试流程就散架。开发阶段想确认仪器内存里到底有哪些脚本可以发送下面这条命令print(script.list())回传结果会列出当前已加载的脚本名。看到不认识的残留脚本用对应的删除命令清理掉。批量跑测试之前先看一眼这个输出能避免「仪器里还留着上一次调试的半段代码」这种低级但也最难排查的问题。5. TSP开发避坑五个让我返工最多的问题下面五条是我在实际调试中返工率最高的现场问题每一条都遵循「现象、原因、解决」三层来拆。5.1 脚本传上去了却不执行——忘了调用现象下发脚本没有任何报错仪器也没有任何输出看起来像石沉大海。原因loadscript只完成脚本定义不会自动执行。如果发送工具没有在脚本末尾补一次调用你看到的只是「仪器内存里多了一段代码」业务逻辑一次都没跑。解决在脚本末尾显式调用比如script_name()。用我提供的下发工具时它会给纯 Lua 文件自动包一层devscript()调用所以文件里不需要写调用行。如果你在某些终端里手工粘贴脚本务必自己补上调用。最简单的自检方式回传一条print(start)在文件第一行跑了就会有输出。5.2 输出被截断或者读到旧结果——读取早于waitcomplete现象上位机循环 read 时拿到不全的数据或数值前后不一致同一段脚本跑两次结果对不上。原因测量操作还在异步队列里脚本已经执行到了后续读取逻辑。上位机和仪器端都没有错只是同步点没踩对。更隐蔽的情况是上一轮测试的数据没清空这一轮直接读到了残留值。解决在每条测量命令后补waitcomplete()尤其涉及量程、输出开关、源电平切换时。我的习惯是在每个逻辑块之间加一行并把读到的数据用print打上批次号比如print(batch, batch_no, value)后续解析时对不上批次号就直接丢弃。5.3 VS Code不报错、仪器端报语法错误——本地与仪器Lua版本不一致现象脚本在编辑器里看着干干净净语法诊断全绿下发到仪器却提示解析错误或执行到一半报非法语句。原因本机 Lua 语言服务器默认用较新的 Lua 版本做诊断TSP 仪器内置解释器往往停留在 Lua 5.0/5.1 分支。某些新语法本地能通过仪器端不认识。典型的比如使用//整除运算符、goto跳转或在变量名前用local之后又跨块引用。解决把.vscode/settings.json里的Lua.runtime.version调整为Lua 5.1或Lua 5.3并且尽量只写最基础的 Lua 语法。涉及位运算、整除这类特性时先在仪器终端里做最小验证再放进批量脚本。编辑器诊断只是辅助最终裁判永远是仪器端解释器。5.4 长扫描跑到一半网络超时——VISA超时设太短现象批量扫描执行到三分之一上位机抛出超时异常但仪器端看起来还在继续工作数据通道却断了。原因Python 脚本里inst.timeout设置的是单次读写操作的最大等待时间不是整个脚本的总时限。脚本单次 read 等不到数据时如果 timeout 太小PyVISA 会直接抛VisaIOError。长测量循环里某一线程恰好处于无输出的采集阶段就容易触发误判。解决把 timeout 设为预期最长单段执行时间的放大值。我一般给批量扫描设置成单点耗时乘以扫描点数再乘 1.5最低不低于 30 秒。另外循环里定期print一个进度标记这样即使超时你也能从最后输出的进度行判断仪器跑到哪里不需要盲猜。5.5 改完代码后仪器还在跑旧逻辑——残留脚本串台现象明明在编辑器里更新了函数逻辑重新下发后行为没有变化执行的还是上一版代码。原因脚本名冲突。新脚本与内存里旧脚本同名定义时机或调用顺序有误导致实际调用的仍然是旧版本。TSP 仪器不会自动清理同名脚本loadscript的重复定义有时也不会立刻替换已驻留的版本。解决先查后删再下发。每次修改关键逻辑前执行一次print(script.list())确认内存中的脚本列表发现同名残留就先删除再重新下发。更严格一点的做法是给每个版本的脚本名带上编号比如scan_v2彻底避开同名覆盖的模糊地带。这比靠感觉清理内存靠谱得多。6. 把工具包用成生产力脚本库、参数化模板与回读校验开发到一定规模后你手里会有很多个.tsp文件。这时候该上代码片段和脚本库两件事。代码片段解决的是写重复模板的问题脚本库解决的是多台仪器之间复用公共逻辑的问题。在.vscode下创建tsp.code-snippets把最常用的循环模板放进去{ TSP repeat scan: { prefix: tspfor, body: [ for i 1, ${1:10} do, ${2:-- test body}, waitcomplete(), end, ${3:} ], description: TSP 循环测量模板 } }输入tspfor回车编辑器会自动展开成带占位符的循环结构Tab 键跳转填写参数。公共函数则单独抽成一个common.tsp里面只放通用函数定义不写测量执行逻辑。业务脚本通过loadscript引用公共脚本下发工具一样能处理。这样你在几个测试流程间切换时改的只是业务脚本公共部分不用动。回读校验是我最后一道固定动作。任何脚本正式跑批量前都会先发一个最小测试并回读script.list()和一行print(READY)确认仪器内存加载的是当前版本。这个习惯的成本是十几秒但能拦住前面提到的残留脚本串台和版本不一致问题。我见过有同事在万点矩阵上直接调试跑到一半发现公式里少乘了一个系数整轮数据作废重来。那次之后我把这套「先查列表、再跑最小循环、最后跑全量」的流程写进了任务模板再也不敢靠眼睛扫一遍代码就当验证完成。工具包的最终价值不是省掉那几行命令而是让你的每一步操作都有回读、有验证、有版本可追溯。希望帮到你。本文还有配套的精品资源点击获取