INCA ProF脚本教程:ECU刷写文件体系与Section状态机排错

发布时间:2026/11/2 12:24:17
INCA ProF脚本教程:ECU刷写文件体系与Section状态机排错

简介:这是一份围绕INCA软件ProF编程脚本的教程总结PDF,面向汽车动力系统标定、ECU闪存编程与自动化流程开发人员,也可供需要理解ProF脚本组织方式的工程师查漏补缺。资源为1个PDF文件,压缩包约271KB,重点梳理ProF脚本中.prm主控制流、.pri子流程和.cnf控制器配置文件的职责划分,并说明layout参数如何定义按键或下拉菜单式交互界面。正文结合[Section]顺序执行、CASE分支跳转、CALL调用子流程以及Flash programming流程示例,呈现从初始化、通信建立、文件转换到编程执行与错误处理的完整逻辑,同时涉及security.dll、Install.ini等配套配置信息,便于读者理解模块化脚本如何组织和维护。已有6748人学习,适合作为ProF脚本入门梳理与ECU标定自动化实践参考。

1. 从一份刷写卡死的日志说起

台架上的 ECU 刷写卡在 30% 不动,界面没报错,日志里只有一行看不懂的返回码——这种现场最能让人意识到 INCA ProF 脚本不是可有可无的配置项。这份 INCA_ProF脚本教程总结.pdf 整理于 2022 年初,把 ProF 脚本的文件构成、Section 状态机、参数传递和 layout 界面定义拆开讲了一遍:.prm是主控制流,.pri是子流程,.cnf是控制器协议描述,Install.ini管路径与文件清单。它适合已经会用 INCA 做标定、但要自己动手改刷写流程、或者接手一套别人留下的脚本无从下手的工程师,也适合想把下载动作从手工点按钮变成产线可重复动作的团队。

2. 文件体系拆解:.prm / .pri / .cnf 三件套怎么分工

ProF 脚本最容易被误解成"一个文件写完的批处理"。实际上它是一套有明确分工的多文件工程:入口、子过程、协议配置、界面定义各管一段,任何一段放错位置,症状都不一样。先把这个分工理清,后面写流程才不会到处打补丁。

2.1 .prm 是唯一入口,一个脚本只能有一份

.prm是主控制流描述文件,作用等价于 C 语言里的main()。这里有个硬约束:一个 ProF 脚本工程里只能有一份.prm。它承担三件事——声明界面布局、按顺序编排各个[Section]、决定流程从哪里开始往哪跳。

之所以强调"唯一",是因为实际项目里经常出现多份.prm并存的情况:有人把main.prm复制成main_v2.prm调试验证,有人从别的项目拷过来一份prog_app_data.prm放在同一目录。结果是你在 A 文件里改了半天,点下载跑的却是 B 文件,日志和你看到的源码完全对不上,这种"黑匣子"式的排查体验极其消耗时间。

.prm的内部结构由若干个块组成,块的边界用[节名]和[节名_END]标记,节名大小写和拼写必须完全一致,结束标记就是节名后加_END。这个规则看着简单,但它是整个脚本能跑起来的地基,写错一个字符,ProF 在解析阶段就会出问题。

2.2 .pri 与 #include:子流程的展开顺序

.pri是子流程文件,数量不限,作用等价于 C 语言的子函数。主流程通过CALL (流程名)跳转到某个.pri里定义的 procedure 执行,执行完再回来。

但.pri不是自动加载的,得先#include进来。原文给出的头部是这样的:

#include "define.pri" #include "error_mess.pri" #include "%7.pri" #include "%8.pri"

这一段值得逐行看:

  • define.pri一般放常量、地址宏、路径宏,是所有流程共享的"头文件",必须先于其他文件 include,否则后面引用宏会解析不出来。
  • error_mess.pri放错误码到可读信息的映射,配合DSP_ERROR使用。把它单独拆出来,是为了让错误提示统一维护,而不是散落在每个节里改。
  • %7.pri和%8.pri是参数化 include,这两个是整个脚本"一套代码多套流程"的关键,具体替换成什么文件名由调用时传入的参数决定(3.4 节展开)。

include 的顺序就是符号可见的顺序。常见做法是:常量与宏在最前,错误定义其次,参数化的业务子流程最后。反过来的话,子流程里引用宏时会找不到定义,症状往往是某个地址变成 0 或者直接报解析失败。

还有一个容易忽略的点:.pri里定义的 procedure 名在整个工程内应当唯一。两个.pri里出现同名 procedure,ProF 不会友好地提示"重复定义",而是按 include 顺序取先找到的那个,于是你改了 B 文件里的函数,跑的却是 A 文件里的版本。我给自己的规矩是 procedure 名带模块前缀,比如programECUFlash、checkECUFlash,一眼能看出归属。

2.3 .cnf 里必须核对清楚的四个字段

.cnf是控制器配置文件,描述 ProF 操作对象控制器协议的基础信息,格式在随软件发布的 ProF Documentation 里有严格定义。字段名各版本可能有差异,但下面这四类信息任何一份.cnf都必须交代清楚:

字段类别作用填错后的典型症状
通信速率决定与控制器握手时的总线速率初始化阶段就超时,INIT_USB一直不返回 ACK
控制器 ID请求发给谁、响应从谁来回报文发出去了但收不到回应,表现为"假死"
Memory_layout描述目标芯片的存储分区结构擦除/写入地址越界,中途报错或写进去读出来不对
Checksum 计算方式决定校验和怎么算、算哪一段刷写流程走完但控制器拒绝启动,回读校验对不上

原文用INIT_FLASH_PROGRAMMING(ECU_ADDRESS,1,CONFIG"phys.cnf")这一行把.cnf挂到流程上。注意第三个参数是CONFIG"phys.cnf"这种写法,文件路径相对于脚本根目录,改名或者挪位置就得同步改这里。

一份.cnf大致的组织方式如下(仅示意字段分组,实际字段名以你手上那份 Documentation 为准):

; phys.cnf 结构示意 [Communication] Baudrate = 500000 ; 通信速率,与台架线束和控制器能力对齐 Channel = 1 ; 物理通道号 ECU_ID = 0x18DA00F1 ; 控制器诊断 ID [Memory] Memory_Layout = FLASH_APP ; 存储布局名称,必须与控制器实际分区一致 [Checksum] Checksum_Type = CRC32 ; 校验算法 Checksum_Start= 0x80000000 ; 参与校验的起始地址 Checksum_End = 0x8003FFFF ; 结束地址,含边界

参数说明:Baudrate和硬件强绑定,换台架要重核;Memory_Layout和Checksum_*是一对,布局改了校验范围基本也要跟着改,这两个字段最好成对审。我一般会在首次调试时把Checksum_Start/End单独打出来核对一遍,而不是等刷完启动不了再倒推。

2.4 从零搭一个最小可跑骨架

把上面几块拼起来,一个能跑通的最小工程长这样:

; main.prm —— 最小可跑骨架 #include "define.pri" #include "error_mess.pri" #include "%7.pri" #include "%8.pri" [START] DEFAULT_SCREEN_LAYOUT (FALSE) EXTENDED_MESSAGE(FALSE) DISPLAY_MESSAGE ("START section!!! ",FALSE) case TRUE : INIT_CNF default : INIT_CNF [START_END] [INIT_CNF] INIT_FLASH_PROGRAMMING(ECU_ADDRESS,1,CONFIG"phys.cnf") case TRUE : INIT_USB default : DSP_ERROR [INIT_CNF_END]

搭建顺序按这个来:先把define.pri里需要的宏补齐(控制器地址ECU_ADDRESS、脚本根路径等),再写phys.cnf并单独验证连通性,最后写.prm的节顺序。这个顺序的理由是——连通性不行的时候写再多流程都是空转,先把INIT_FLASH_PROGRAMMING这一段跑通,后面的节才有意义。

3. Section 状态机:CASE 分支、返回值与跳转

ProF 脚本不是顺序执行的线性批处理,它是一台靠返回值驱动的状态机。每个节执行完,根据函数返回的结果决定下一步去哪。不理解这一点,写出来的脚本能跑但不可控——出错时不报错,而是继续往下走,把问题推到更靠后的环节,症状和根因彻底脱节。

3.1 [Section] ... [Section_END] 的顺序执行

主流程整体按[节名]到[节名_END]自上而下展开。每个节内部是一到多个函数调用,最后一次调用的返回值参与case判定,决定跳出这个节之后进入哪个节。

原文给出的骨架大致是这样一条链:

[START] case TRUE : INIT_CNF default : INIT_CNF [START_END] [INIT_CNF] INIT_FLASH_PROGRAMMING(ECU_ADDRESS,1,CONFIG"phys.cnf") case TRUE : INIT_USB default : DSP_ERROR [INIT_CNF_END] [INIT_USB] UDSB_INIT_COMMUNICATION case FPA_ACK : CONV1 default : DSP_ERROR [INIT_USB_END] [CONV1] CALL (convert) case TRUE : MAIN default : DSP_ERROR [CONV1_END] [MAIN] CALL (programECUFlash) case TRUE : success case ESCAPE: DSP_break default : DSP_ERROR [MAIN_END] [success] EXTENDED_MESSAGE(FALSE) default : EXIT [success_END]

读法:INIT_CNF里只有INIT_FLASH_PROGRAMMING一个调用,它返回TRUE就进INIT_USB,返回其他任何值就走DSP_ERROR。到了INIT_USB,判定条件换成了FPA_ACK——通信初始化的成功返回值不是布尔量,而是一个特定的 ACK 状态码。这个细节很关键:不同函数有各自的成功返回值,不能一律拿TRUE去比。

[success]节只有一条default : EXIT,意思是无论什么情况都跳到结束,这是流程收尾的出口点。

3.2 CASE 的返回值清单与 default 的必要性

case部分能写多少个分支,取决于被判定函数的返回值域。从原文里能直接看到的返回语义有三类:

返回值含义常规处理
TRUE函数执行成功进入下一正常节
FPA_ACK通信初始化返回确认进入转换或业务流程
ESCAPE上层要求中断跳DSP_break中断流程

default分支的作用是兜底:只要返回值不命中任何显式case,就走default。它的必要性体现在两个层面——一是可读性,维护的人一眼能看出失败路径在哪;二是可控性,万一把返回值判断写错(比如该写FPA_ACK写成TRUE),有default至少会跳到错误处理,而不是在节边界处留下未定义行为。

我见过省掉default的写法,在部分版本上表现为当前节执行完就"悬停",界面不返回也不报错,跟第 1 章说的卡 30% 是同一类现象。所以这条不是风格问题,是稳定性问题。

另外注意原文[MAIN]节里case和case并存、default兜底的结构:

[MAIN] CALL (programECUFlash) case TRUE : success case ESCAPE: DSP_break default : DSP_ERROR [MAIN_END]

这里success在源文件里是另一个节名,DSP_break、DSP_ERROR是内置的流程控制动作,语义不同,别混着用。

3.3 CALL 跨文件调用与 ESCAPE / DSP_break

当.prm里出现CALL ( programECUFlash ),ProF 会自动跳到对应.pri文件里执行那个 procedure,执行完毕再回到调用点继续判定。

这个"自动跳转"靠的是 procedure 名匹配,所以CALL括号里的名字必须和被调.pri里定义的完全一致。原文提到的prog_app_data.pri里的programECUFlash就是这样被调起来的。

DSP_break和ESCAPE这一对的配合值得单独说清楚:子流程在内部判断出"这次不该继续了"(比如操作员点了取消、或者前置校验失败),就返回ESCAPE;主流程收到ESCAPE后跳DSP_break,走优雅中断而不是错误处理。区分"中断"和"错误"的好处是日志干净——中断是预期行为,不该在错误日志里留一堆噪音,否则真正的问题会被淹掉。这也是我坚持在每个子流程里显式处理取消路径的原因,属于典型的"事后后悔没早点加"的事。

3.4 参数 %7 %8 %9 从哪来

这是整套脚本里最容易看懵的一处。原文解释得很直白:当layout里选中不同的 Action 时,ProF 会把不同的参数传进主流程描述文件。以选择 "Download - Application Code, Data" 为例,实际传递的形式是:

prog_app_data convert c:$prof\Install\main.prm

这串内容按空格切成多个参数位,编号从 1 开始,于是:

参数位实际值用途
参数 7prog_app_data决定加载哪个业务子流程文件
参数 8convert决定是否做 hex 文件转换
参数 9c:$prof\Install\main.prm决定主流程文件路径

回到 2.2 节那两行#include "%7.pri"和#include "%8.pri",就说得通了:选 "Download - Application Code, Data" 时,%7展开成prog_app_data,实际 include 的是prog_app_data.pri;%8展开成convert,include 的是convert.pri。选别的 Action,传进来的参数位变了,加载的子流程文件也就跟着换——一套主流程骨架,对应多条业务路径。

原文在转换那块还给了取值说明:

;%;% <conv>: hex file conversion ;% convert = convert ;% noconv = do not convert

convert走转换,noconv跳过转换。做产线快速刷写时用noconv省一道工序,但前提是你给的文件已经是控制器可直接接收的格式,否则会刷进去一堆不对的字节。

参数位编号不是拍脑袋定的,它是调用约定的一部分。调试期最实用的方法是把%7%8%9用DISPLAY_MESSAGE原样打出来,看一眼实际值是什么再往下写逻辑——这比对着文档猜编号靠谱得多。

4. layout 与 Install.ini:把脚本做成有人愿意点的界面

脚本能跑通只是第一层。产线上真正被使用的是那个"点开就有一排选项"的界面,操作员不需要知道.prm在哪、.cnf叫什么。这一层由layout文件和Install.ini共同决定,也是最容易在交接时被漏掉的部分。

4.1 layout 的选项 1 取值语义

layout负责定义 ProF 界面长什么样。原文给了两个取值规则:

  • 选项 1 取值为3时,该参数以按键(button)方式选择,典型例子是File name选项——点按钮弹文件选择框。
  • 选项 1 取值为2时,该参数以下拉选项方式选择,典型例子是Channel选项。

这个区分背后是参数类型:值域开放、每次都可能是新路径的,用按键选文件;值域封闭、就那么几个已知值的,用下拉避免手输错。

原文还有一句提醒很重要:这套界面元素仅在Action = Flash programming时有效。换句话说,换到别的 Action,你在layout里精心排的控件可能根本不生效,界面上什么都不显示。排查"界面怎么空了"时,先回头确认当前 Action 是什么,比逐行检查 layout 语法省时间。

4.2 选项 2 与下拉项数量

选项 1 等于2时,选项 2 的值表示下拉栏里有多少个选择项。也就是说:

; layout 片段示意:Channel 用下拉,给 4 个候选 Channel : 2 : 4

含义是"Channel 这一项用下拉方式呈现,下拉里有 4 个选项"。这 4 个选项的具体内容需要在 layout 里逐条列出(或者由配置提供),数量必须和选项 2 对得上。数量写少了后面的选项显示不出来,写多了会出现空行,操作员选中空行后传下去的是一个空值,流程在很靠后的位置才炸,排查起来非常绕。

我的做法是:下拉项数量改动时,同步在注释里写清每一项目前对应什么,改一次更新一次。这种注释看着啰嗦,但半年后回来改的时候,能省掉一轮"这个 3 到底代表哪三个"的考古。

4.3 Install.ini 的四个段落

Install.ini是 ProF 的安装定义信息,决定脚本运行时要加载哪些文件、路径怎么替换。原文列出的段落有这几块:

[Configuration] ; ProF 配置信息定义 [ChangePath_XX] ConfigPath = c:$prof\Install ; 需要变更的路径定义 [Files] SecurityFile = seedms6.dll ; 安全访问用的动态库 [LanguageFiles] File = info.txt LayoutFile = layout File = config_func.cnf File = config_phys.cnf File = main.prm File = common1.pri

逐段说明:

  • [Configuration]放 ProF 自身的配置项,属于环境级设置。
  • [ChangePath_XX]解决换机器、换盘符的问题。ConfigPath = c:$prof\Install里的$prof是变量,安装时被替换成实际根路径。这套机制的意义在于:脚本里所有引用路径都写$prof相对形式,脚本从一台机器搬到另一台,只改变量不改代码。
  • [Files]列出需要随脚本加载的文件,SecurityFile=seedms6.dll就是安全访问相关的动态库。这类 dll 缺失或架构不匹配,症状往往是初始化阶段直接卡住,而不给明确提示。
  • [LanguageFiles]是文件清单,把layout、各个.cnf、main.prm、common1.pri一一登记。这里漏登记一个文件,运行时就会找不到它,而且报错信息通常只给个文件名,不说是在哪一步要用的。

这份清单本质上就是工程的"依赖声明"。新增一个.pri别忘了往[LanguageFiles]里加一行,这个动作很小,漏了之后的排查成本很高。

4.4 一个 Action 配一条 prm 路径的映射关系

把第 3 章的参数传递和第 4 章的界面配置连起来看,实际的项目结构是这样的:

界面 Action传入参数 7加载的子流程使用的主流程
Download - Application Code, Dataprog_app_dataprog_app_data.pric:$prof\Install\main.prm
其他刷写动作各自的流程名对应的.pri可指向不同.prm

这张表的实际价值在于排查方向:界面点了某个 Action,流程却跑到了另一个分支,第一反应应该是核对传入的参数 7 到底是什么,而不是去翻.prm里的节顺序。参数决定了加载哪个子流程文件,子流程文件决定了CALL能不能找到目标 procedure——所有"找不到函数"的报错,根因多半在参数这一层。

至于prog_app_data convert之外的组合,做法一样:Action 名、参数、子流程文件名三者保持一致,命名对齐了,出问题时看日志就能定位到是哪条路径。我一般会把这张映射表直接写在脚本目录的说明文件里,接手的人不用反向推。

5. 避坑与排查:五个让刷写卡在中途的现场问题

前面把结构和机制讲完了,真正耗时间的还是出问题之后怎么定位。ProF 脚本的难点在于它的失败方式往往很安静:不抛异常、不弹窗,只是在某个节停住,或者更糟——继续往下跑但结果不对。下面这几条都是反复出现过的现场情况,按"现象 → 原因 → 解决"整理。

5.1 先建立一条固定的排查顺序

在逐条看坑之前,先把排查路径固化下来,避免每次凭感觉试。我习惯的顺序是:

  1. 开详细输出。在[START]节把EXTENDED_MESSAGE(TRUE)打开,让每一步的执行信息都打出来,先确认流程走到了哪个节。
  2. 打关键参数。把%7%8%9用DISPLAY_MESSAGE原样输出,确认加载的是你以为的那个子流程文件。
  3. 单节验证。注释掉后续节,只让当前节执行,观察返回值。逐个节往前推,直到找出第一个返回值不符合预期的位置。
  4. 核对配置文件。.cnf里的通信参数、存储布局、校验范围逐项与实际控制器比对,而不是和上一版配置比对。
  5. 确认依赖库。[Files]里登记的 dll 是否齐全、位数是否与当前 ProF 一致、是否被同目录的其他版本覆盖。

这五步走完,绝大多数"卡住"都能定位到具体某一层。跳过第 1、2 步直接改代码,是效率最低的做法,因为改的地方很可能根本不在执行路径上。

5.2 坑一:改的 .prm 没生效,工程里其实有两份

现象:在main.prm里加了一行DISPLAY_MESSAGE,重新执行后日志里完全没有这行输出,但流程又能正常跑完,说明执行的是另一份文件。

原因:目录下存在多份.prm,或者[LanguageFiles]里登记的是另一份路径。ProF 只认清单里声明的那一份,你编辑的文件如果没被登记,改一百遍也不会生效。另一种情况是从旧项目整体拷过来,main.prm被覆盖了一半,两份内容混在一起。

解决:先看[LanguageFiles]里File = xxx.prm指向哪个文件名,再确认该文件的实际修改时间。定下来之后,把多余的.prm移出脚本目录(别只改名留在原地,仍可能被误加载),并在[START]节加一行版本号输出,每次执行第一眼就能确认跑的是哪一版。这条我吃过亏之后就一直保留,几乎零成本。

5.3 坑二:CASE 少了 default,出错后流程一路跑到底

现象:某个前置校验明明失败了,流程却没有停在错误处理,而是继续往下执行,最后在刷写阶段报一个完全不相干的错误。日志里的失败点和实际根因隔着好几步。

原因:节内的case只写了成功分支,没有default兜底。函数返回一个非预期值时,没有匹配项,流程在节边界处失去明确跳转,后续行为依赖具体实现,表现为"跳过错误继续跑"或者"停住不动"。

解决:所有带case的节强制补default,统一指向DSP_ERROR(或者该场景下的错误处理节)。补完之后重跑一遍故意构造的失败用例(比如断开通信线),确认流程确实走到错误处理而不是继续。这一步属于典型的"后悔药"——出问题之后再补,至少要把之前所有跑过的节重新验证一遍。

5.4 坑三:路径带空格或特殊字符,文件转换直接失败

现象:CALL (convert)这一步失败,返回非TRUE,但文件确实存在、手工打开也正常。换成另一个目录下的同名文件就能跑通。

原因:参数按空格切分,路径里带空格就会被拆成两个参数位,%9拿到的是一个被截断的路径。中文或特殊字符在某些环境下还可能引发编码解析问题。原文的示例路径c:$prof\Install\main.prm本身没有空格,就是为了避开这个问题。

解决:脚本目录和所有被引用的文件路径统一不带空格,目录名用下划线或短横线分隔。已经带空格的,把整个脚本根目录换个位置,而不是在每个引用点加引号硬扛——引用点往往不止一处,漏改一个就又回到原点。

5.5 坑四:.cnf 与实际控制器不符,刷完启动不了

现象:流程一路绿灯走完,界面显示成功,但控制器上电后不启动,或者回读出来的数据和源文件不一致。

原因:.cnf里的Memory_Layout或Checksum计算方式与实际目标不一致。常见情况是拿了同系列但不同存储配置的.cnf直接用,通信参数对得上所以能连上,但擦写地址范围和校验范围是错的,结果就是"写进去了但不算数"。

解决:.cnf不靠拷贝,按目标控制器逐项确认:通信速率、控制器 ID、存储布局、校验起点终点、校验算法。确认方式是在首次调试时把关键字段打出来,并与控制器实际分区表逐条比对。同一项目里如果有多款控制器,.cnf按型号分开命名(如config_phys.cnf、config_func.cnf这种按功能拆分的命名),别用一份文件改来改去。

5.6 坑五:安全访问库不匹配,初始化阶段静默卡住

现象:INIT_USB节卡住不返回,UDSB_INIT_COMMUNICATION一直没有给出 ACK,也不报错。换一台机器同样的脚本能跑通。

原因:[Files]里登记的SecurityFile指向的 dll 在当前机器上不可用——位数不一致、版本不匹配,或者被同目录下另一个同名文件覆盖。这类问题最讨厌的地方是它不给出明确错误,只是"没反应"。

解决:先确认 dll 与当前 ProF 的位数一致,再确认目录下没有同名文件混放。判断方法是临时把SecurityFile换成一份已知可用的库,如果初始化能过,问题就锁定在库这一层。定位之后把可用版本的库和脚本一起归档,别指望每台机器上都能找到对的那一份。

6. 进阶:把脚本做成可复用的产线资产

脚本能跑通和能交给别人用,中间差着一层工程化。这套东西一旦进入产线,被复制的次数会远超预期,所以值得在第一次做完就补上几个低成本的习惯。

第一件事是版本可追溯。在[START]节固定打一行版本信息,比任何外部文档都直接:

[START] DEFAULT_SCREEN_LAYOUT (FALSE) EXTENDED_MESSAGE(FALSE) DISPLAY_MESSAGE ("PROF_SCRIPT v2.3.0 / 2022-01",FALSE) DISPLAY_MESSAGE ("LOADED PRM: main.prm",FALSE) case TRUE : INIT_CNF default : INIT_CNF [START_END]

两行输出,一行版本号,一行当前加载的主流程文件名。逻辑上不参与任何判定,纯粹是给人看的;参数上FALSE表示这条消息不阻塞,打完继续走。它的价值在出问题时立刻体现——不用去翻文件修改时间,日志第一行就告诉你跑的是哪一版、哪一份。

第二件事是调试开关分级。同一个脚本在开发期和产线期对输出的要求完全不同,用一张表管住:

场景EXTENDED_MESSAGE输出内容开关注意
首次联调TRUE每节进出、返回值、参数位信息量大,不要带到产线
产线正常刷写FALSE仅开始/成功/错误错误信息必须保留
现场问题复现TRUE全量复现完立刻改回FALSE

我见过把EXTENDED_MESSAGE(TRUE)留在产线版本里的,日志文件一天涨到几个 G,把真正有用的错误信息全冲掉了。这个开关建议做成脚本内的一个宏集中控制,改一处全脚本生效。

第三件事是收尾节别省。[success]里除了EXTENDED_MESSAGE(FALSE)复位,最好加一步回读校验:刷写完成后读回关键区域的校验和,与源文件比对,一致才走EXIT,不一致走DSP_ERROR。这一步的价值在于把"流程跑完了"和"数据真的对了"区分开——前者只能说明命令发出去了,后者才是产线要的结果。

[success] EXTENDED_MESSAGE(FALSE) CALL (verifyChecksum) ; 回读并比对校验和 case TRUE : EXIT default : DSP_ERROR [success_END]

verifyChecksum定义在单独的.pri里,注意同步加进[LanguageFiles]清单,否则运行时会加载不到。

从那以后我每次接手一套 ProF 脚本,第一件事都是把[LanguageFiles]清单和目录里的实际文件对一遍,再在[START]里加两行版本输出——这两步加起来不到五分钟,能挡掉后面大半的无效排查。希望帮到你。

本文还有配套的精品资源,点击获取