前几天我们对RFID读取功能块和校验功能块进行了解读
大众VASS标准:FB_Sick_RFU(FB520_RFID数据读取)功能块深度解读
大众VASS标准:FB_Pruefziffer(FB170)校验数据功能块深度解读
今天我们对FB_Typ_VAR(FB529)车辆代码匹配功能块进行详细解读
功能块简介
FB_Typ_VAR(FB529)核心作用是实现对车辆代码(RBS)接收与有效性校验、车型类型匹配评估,并提供可视化交互与故障监控能力。
功能块:
功能块大纲:
1初始化与参数计算
- 数据块缓存:通过`BLKMOV`将`DB_RBS`和`DB_STyp`复制到临时缓存(`tempDB_RBS`/`tempDB_STyp`)
- 参数计算:`iRBSAnz`(RBS位数)、`iRBSLen`(RBS长度,含校验位)、`iTypAnz`(工作站类型条目数)
2 RBS接收与处理
- 指针配置:`anyRBS`指向RBS数据(设置语法ID、数据类型、长度)
- 手动接收:从可视化界面读取RBS字符(`strVisuWertRBS`)或软键输入
- 自动接收:通过`BLKMOV`从RBS数据块自动读取
3 有效性校验
- RBS校验:逐位匹配`tempDB_RBS`中的有效字符,设置`arrRBS_IO`(位置正常)
- 校验位计算:基于Code39算法,计算`chrPZ`并与输入比对(`xCODE39_IO`)
- 整体有效性:`xRBS_PZ_IO`(RBS+校验位正常)、`xRBS_PZ_NIO`(异常)
4 工作站类型评估
- 匹配逻辑:对比RBS与`tempDB_STyp`中的类型条目,支持占位符`X`/`~`(由`Cfg.X2`控制)
- 状态标志:`xSTyp_IO`(类型正常)、`xSTyp_NIO`(类型异常)
5 接收确认与输出
- 接收触发:自动模式或手动软键触发,设置`xUebern`(RBS已接收)
- 输出映射:`RBS_IO`/`STypIO`等状态输出,`RBS_S1`至`RBS_S8`编码输出
6 可视化与消息系统
- 可视化控制:颜色配置(`bFarbKombi`)、文本更新(多语言支持)
- 故障消息:`MSYS`记录故障源,通过`MeldSend`发送至消息缓冲区
- 故障汇总:`xStoe`(汇总故障)、`VkStoe_Out`(连锁故障)
变量声明:
1. 输入变量(VAR_INPUT)
完整代码解读:
### 西门子SCL功能块FB_Typ_VAR(FB529)详细解读#### 一、版权与版本日志```plaintext******************************************************************************************* **** Copyright 2013 SIEMENS AG I IA/DT, D-90475 Nuernberg **** All Rights Reserved VOLKSWAGEN AG, 38436 Wolfsburg **** AUDI AG, D-85045 Ingolstadt **** ********************************************************************************************** **** Aenderungsjournal : ********************************************************************************************** Datum Version Autor Beschreibung **------------------------------------------------------------------------------------------07.09.15 3.1.03 Schulz 在有效工作站类型的声明中,'X'可作为占位符;若cfg.x2=true,'~'可作为占位符22.01.15 3.1.02 Schulz 移除了德语变音符号06.12.13 3.1.02 Maletz 调整了类型错误消息03.12.13 3.1.01 Maletz 校验位可关闭(Cfg.X1)21.10.13 3.1.00 Maletz 扩展校验位功能;扩展可变RBS长度14.10.13 3.0.01 Maletz 调整手动输入20.08.13 3.0.00 Maletz 重新创建*****************************************************************************************```**解读**:- 版权归属西门子、大众、奥迪公司,功能块用于工业控制场景(推测与汽车生产中的毛坯代码/工作站类型评估相关)。- 版本迭代记录了功能扩展(如校验位、占位符)、bug修复(如变音符号移除)等,最新版本为3.1.03。#### 二、功能块基本信息```sclFUNCTION_BLOCK FB_Typ_VAR //FB529TITLE = 'Version 3.1.03'VERSION : '3.1'AUTHOR : VASS_V05NAME : TYPVARFAMILY : TYPVAR```**解读**:- 定义功能块`FB_Typ_VAR`,编号`FB529`,版本3.1.03,作者VASS_V05,名称TYPVAR,属于TYPVAR家族(功能块组)。#### 三、变量声明##### 1. 输入变量(VAR_INPUT)```sclVAR_INPUTInit : BOOL; //初始化(重新读取数据块)RBS : POINTER; //指向UII_RBS起始地址的指针pRBS AT RBS : STRUCTDBNR : WORD; //字节4+5:DB编号BZ : DWORD; //字节6至10:区域指针END_STRUCT;DB_RBS : ANY; //毛坯代码数据块(DB_RBS)pDB_RBS AT DB_RBS : STRUCTBYTE0 : BYTE; //字节0TYP : BYTE; //字节1:数据/参数类型ANZ : WORD; //字节2+3:变量长度DBNR : WORD; //字节4+5:DB编号BZ : DWORD; //字节6至10:区域指针END_STRUCT;DB_STyp : ANY; //工作站类型数据块pDB_STyp AT DB_STyp : STRUCTBYTE0 : BYTE; //字节0TYP : BYTE; //字节1:数据/参数类型ANZ : WORD; //字节2+3:变量长度DBNR : WORD; //字节4+5:DB编号BZ : DWORD; //字节6至10:区域指针END_STRUCT;Sprache : INT; //语言(1:德语;2:其他语言;3:中文)Auto : BOOL; //自动类型评估使能Hand : BOOL; //手动类型评估使能FM_Reset : BOOL; //清除类型接收标志_Cfg : WORD; //配置字(X0:评估DB_RBS预设位置2-x;X1:无校验位;X2:占位符'~'替代'X')Cfg AT _Cfg : STRUCT //WORD拆分为BOOLX8 : BOOL;X9 : BOOL;X10 : BOOL;X11 : BOOL;X12 : BOOL;X13 : BOOL;X14 : BOOL;X15 : BOOL;X0 : BOOL; //评估DB_RBS预设位置2-xX1 : BOOL; //无校验位X2 : BOOL; //工作站类型评估:用'~'作为占位符(替代'X')X3 : BOOL;X4 : BOOL;X5 : BOOL;X6 : BOOL;X7 : BOOL;END_STRUCT;VkStoe_In : BOOL; //连锁故障输入END_VAR```**解读**:- `Init`:触发数据块重新读取(初始化)。- `RBS`:指针类型,通过`pRBS`结构体解析为`DBNR`(数据块编号)和`BZ`(区域指针,指向数据存储位置),用于定位毛坯代码(RBS)数据。- `DB_RBS`/`DB_STyp`:`ANY`类型(任意数据类型指针),分别指向毛坯代码和工作站类型的数据块,通过`pDB_RBS`/`pDB_STyp`解析内部结构(含长度、DB编号等元数据)。- `Sprache`:设置语言(支持中文)。- `Auto`/`Hand`:自动/手动模式使能,控制类型评估方式。- `FM_Reset`:清除“类型已接收”标志(`FM`)。- `_Cfg`:配置字,通过`Cfg`结构体拆分为16个BOOL位,分别控制功能(如`X1`关闭校验位,`X2`切换占位符)。- `VkStoe_In`:外部连锁故障输入,用于故障传递。##### 2. 输出变量(VAR_OUTPUT)```sclVAR_OUTPUTFM : BOOL; //毛坯代码已接收RBS_IO : BOOL; //毛坯代码正常RBS_NIO : BOOL; //毛坯代码异常STypIO : BOOL; //工作站类型正常STypNIO : BOOL; //工作站类型异常Data : WORD; //工作站类型数据RBS_S1 : WORD; //毛坯代码位1(位编码)RBS_S2 : WORD; //毛坯代码位2(位编码)RBS_S3 : WORD; //毛坯代码位3(位编码)RBS_S4 : WORD; //毛坯代码位4(位编码)RBS_S5 : WORD; //毛坯代码位5(位编码)RBS_S6 : WORD; //毛坯代码位6(位编码)RBS_S7 : WORD; //毛坯代码位7(位编码)RBS_S8 : WORD; //毛坯代码位8(位编码)Stoe : BOOL; //汇总故障VkStoe_Out : BOOL; //连锁故障输出END_VAR```**解读**:- `FM`:毛坯代码成功接收标志。- `RBS_IO`/`RBS_NIO`:毛坯代码是否有效(正常/异常)。- `STypIO`/`STypNIO`:工作站类型是否有效(正常/异常)。- `Data`:工作站类型对应的输出数据。- `RBS_S1`至`RBS_S8`:毛坯代码各位置的位编码(用于外部传递具体位状态)。- `Stoe`:汇总故障标志(所有故障的OR结果)。- `VkStoe_Out`:连锁故障输出(输入故障与内部故障的OR结果)。##### 3. 输入输出变量(VAR_IN_OUT)```sclVAR_IN_OUTST_Meld : Meldungspuffer; //消息缓冲区(消息结构体)END_VAR```**解读**:- `ST_Meld`:消息缓冲区,用于传递故障/状态消息(与消息系统交互)。##### 4. 临时变量(VAR_Temp)```sclVAR_TempTempPointerMsys : ANY; //消息系统辅助指针TempPointerFlanken : ANY; //边沿检测辅助指针TempPointerMeldpuffer : ANY; //消息缓冲区辅助指针erg_SFC20 : INT; //SFC20(块移动指令)返回值pMeldFeld AT TempPointerMsys: STRUCTBYTE0 : BYTE; //字节0TYP : BYTE; //字节1:数据/参数类型ANZ : WORD; //字节2+3:变量长度DBNR : WORD; //字节4+5:DB编号BZ : DWORD; //字节6至10:区域指针END_STRUCT;pMeldAbb AT TempPointerFlanken: STRUCTBYTE0 : BYTE; //字节0TYP : BYTE; //字节1:数据/参数类型ANZ : WORD; //字节2+3:变量长度DBNR : WORD; //字节4+5:DB编号BZ : DWORD; //字节6至10:区域指针END_STRUCT;pMeldDBNR AT TempPointerMeldpuffer: STRUCTBYTE0 : BYTE; //字节0TYP : BYTE; //字节1:数据/参数类型ANZ : WORD; //字节2+3:变量长度DBNR : WORD; //字节4+5:DB编号BZ : DWORD; //字节6至10:区域指针END_STRUCT;bFarbKombi : BYTE; //可视化颜色组合iAdr_RBS : INT; //RBS字节地址anyRBS : ANY; //RBS辅助ANY指针p_RBS AT anyRBS : STRUCTSyntaxId : BYTE; //字节0:语法ID(固定为16#10)DataType : BYTE; //字节1:数据类型(如02=BYTE)DataCount : WORD; //字节2+3:重复次数(长度)DBNR : WORD; //字节4+5:DB编号BZ : DWORD; //字节6至10:区域指针END_STRUCT;anyDB_RBS1 : ANY; //DB_RBS辅助指针1p_DB_RBS1 AT anyDB_RBS1 : STRUCTSyntaxId : BYTE; //语法IDDataType : BYTE; //数据类型DataCount : WORD; //长度DBNR : WORD; //DB编号BZ : DWORD; //区域指针END_STRUCT;anyDB_RBS2 : ANY; //DB_RBS辅助指针2p_DB_RBS2 AT anyDB_RBS2 : STRUCTSyntaxId : BYTE; //语法IDDataType : BYTE; //数据类型DataCount : WORD; //长度DBNR : WORD; //DB编号BZ : DWORD; //区域指针END_STRUCT;anyQRBS_S : ANY; //RBS_S源指针p_QRBS_S AT anyQRBS_S : STRUCTSyntaxId : BYTE; //语法IDDataType : BYTE; //数据类型DataCount : WORD; //长度DBNR : WORD; //DB编号BZ : DWORD; //区域指针END_STRUCT;anyZRBS_S : ANY; //RBS_S目标指针p_ZRBS_S AT anyZRBS_S : STRUCTSyntaxId : BYTE; //语法IDDataType : BYTE; //数据类型DataCount : WORD; //长度DBNR : WORD; //DB编号BZ : DWORD; //区域指针END_STRUCT;END_VAR```**解读**:- 临时变量用于中间计算,如`erg_SFC20`存储块移动指令的返回值(0表示成功);`anyRBS`系列指针用于动态定位数据块中的数据;`bFarbKombi`控制可视化界面的颜色(如正常为绿色,故障为红色)。##### 5. 静态变量(VAR)```sclVAR_dwVisuWerte1 : DWORD; //可视化状态双字1dwVisuWerte1 AT _dwVisuWerte1: STRUCT //DWORD拆分为BOOL/字节B3 : BYTE; //可视化符号03边框(0..3)B2 : BYTE; //可视化符号10边框(0..3)X8 : BOOL; //预留X9 : BOOL; //预留X10 : BOOL; //预留X11 : BOOL; //预留X12 : BOOL; //预留X13 : BOOL; //预留X14 : BOOL; //预留X15 : BOOL; //手动输入RBS接收标志X0 : BOOL; //预留X1 : BOOL; //预留X2 : BOOL; //预留X3 : BOOL; //RBS位1故障闪烁X4 : BOOL; //RBS位2故障闪烁X5 : BOOL; //RBS位3故障闪烁X6 : BOOL; //RBS位4故障闪烁X7 : BOOL; //RBS位5故障闪烁END_STRUCT;_dwVisuWerte2 : DWORD; //可视化状态双字2dwVisuWerte2 AT _dwVisuWerte2: STRUCT //DWORD拆分为字节B3 : BYTE; //校验位按钮颜色B2 : BYTE; //OK按钮颜色B1 : BYTE; //RBS/工作站类型显示(0..3/4..7)B0 : BYTE; //手动/自动显示(0..3/4..7)END_STRUCT;_strVisuWertRBS : STRING[10] := '**********'; //可视化RBS字符串strVisuWertRBS AT _strVisuWertRBS: STRUCT //字符串结构bMax : BYTE; //最大长度bAct : BYTE; //实际长度arrText : ARRAY[1..10] OF CHAR; //RBS字符数组END_STRUCT;_strVisuWertPZ : STRING[2] := '*'; //可视化校验位字符串strVisuWertPZ AT _strVisuWertPZ: STRUCT //校验位结构bMax : BYTE; //最大长度bAct : BYTE; //实际长度arrText : ARRAY[1..2] OF CHAR; //校验位字符END_STRUCT;bVisuTasten : BYTE; //可视化软键输入strVisuText : STRUCT //可视化文本结构S : ARRAY[1..8] OF STRUCTBez : STRING[20]; //标题Z : ARRAY[1..16] OF STRUCTBez : STRING[30]; //按键文本END_STRUCT;END_STRUCT;END_STRUCT;iVisuTastenS : ARRAY[1..8] OF INT; //可视化软键输入值(****************************************************************************************)(*****************************Anfang Variablendeklaration********************************)(*********************************fuers Meldesystem**************************************)(****************************************************************************************)MSYS : STRUCT //消息系统标志xF_1 : BOOL; //故障标志1(RBS位1异常)xF_2 : BOOL; //故障标志2(RBS位2异常)xF_3 : BOOL; //故障标志3(RBS位3异常)xF_4 : BOOL; //故障标志4(RBS位4异常)xF_5 : BOOL; //故障标志5(RBS位5异常)xF_6 : BOOL; //故障标志6(RBS位6异常)xF_7 : BOOL; //故障标志7(RBS位7异常)xF_8 : BOOL; //故障标志8(RBS位8异常)xF_9 : BOOL; //故障标志9(工作站类型无效)xF_10 : BOOL; //故障标志10(校验位异常)xF_11 : BOOL; //故障标志11(手动输入激活)xF_12 : BOOL; //预留xF_13 : BOOL; //预留xF_14 : BOOL; //预留xF_15 : BOOL; //预留xF_16 : BOOL; //预留Flanken : ARRAY[0..1] OF BYTE; //边沿检测字节END_STRUCT;AenderungsID : STRUCT //版本IDSNr : WORD; //序列号ANr : BYTE; //编号Detail : BYTE; //细节END_STRUCT;xIntegritaet : BOOL; //完整性标志(消息系统)(****************************************************************************************)(*****************************Ende Variablendeklaration**********************************)(*********************************fuers Meldesystem**************************************)(****************************************************************************************)xStoe : BOOL; //故障消息激活xWarn : BOOL; //警告消息激活xWart : BOOL; //维护消息激活xInit : BOOL; //初始化完成标志iStart : INT; //起始地址iLetzter : INT; //结束地址iLauf : INT; //循环变量1i : INT; //循环变量2iRBSAnz : INT := 4; //毛坯代码位数(默认4位)iTypAnz : INT := 1; //工作站类型DB条目数(默认1)iRBSLen : INT := 5; //毛坯代码长度(含校验位,默认5)iSicht_RBS : INT; //RBS位2-x的偏移量iBer_RBS : INT; //RBS位2-x的区域长度arrRBS : ARRAY[1..10] OF CHAR; //毛坯代码字符数组arrTemp : ARRAY[1..8] OF BOOL; //辅助布尔数组arrRBS_IO : ARRAY[1..8] OF BOOL; //RBS各位置正常标志arrRBS_NIO : ARRAY[1..8] OF BOOL; //RBS各位置异常标志xRBS_IO : BOOL; //RBS整体正常xRBS_NIO : BOOL; //RBS整体异常xRBS_PZ_IO : BOOL; //RBS+校验位正常xRBS_PZ_NIO : BOOL; //RBS+校验位异常xUebern : BOOL; //RBS已接收标志xS_TypFrg : BOOL; //类型输入接收按钮xS_UebPZ : BOOL; //校验位接收按钮xHand : BOOL; //手动接收标志xAuto : BOOL; //自动接收标志arrSTyp_IO : ARRAY[1..8] OF BOOL; //工作站类型各位置正常arrSTyp_NIO : ARRAY[1..8] OF BOOL; //工作站类型各位置异常xSTyp_IO : BOOL; //工作站类型整体正常xSTyp_NIO : BOOL; //工作站类型整体异常iZyklus : INT := 1; //循环计数器(优化周期)iZyklus16 : INT := 1; //循环计数器(16分频)wData : WORD; //工作站类型数据(内部)_wData AT wData : STRUCTIO : BOOL; //工作站类型有效标志END_STRUCT;arrCode_RBS : ARRAY[1..9] OF INT; //RBS字符的Code39编码值chrPZ : CHAR; //计算出的校验位iCharCode39 : INT; //Code39编码总和iMOD_39 : INT; //Code39编码总和模43结果xCODE39_IO : BOOL; //Code39校验正常xCODE39_NIO : BOOL; //Code39校验异常R_TRIG_S_TypFrg_Q : BOOL; //xS_TypFrg的上升沿xR_TRIG_S_TypFrg_Edge : BOOL; //xS_TypFrg的边沿记忆R_TRIG_Uebern : BOOL; //xUebern的上升沿xR_TRIG_Uebern : BOOL; //xUebern的边沿记忆R_TRIG_Auto_Q : BOOL; //Auto的上升沿xR_TRIG_Auto_Q_Edge : BOOL; //Auto的边沿记忆tempDB_RBS : STRUCT //RBS数据块缓存Z : ARRAY[1..8] OF STRUCTBez : ARRAY[1..3] OF STRING[20]; //各位置标题(3种语言)Z : ARRAY[1..16] OF STRUCTCH : CHAR; //字符Frg : BOOL; //有效标志Sicht_RBS : INT; //RBS可见性偏移Bez : ARRAY[1..3] OF STRING[30]; //字符描述(3种语言)END_STRUCT;END_STRUCT;END_STRUCT;tempDB_STyp : STRUCT //工作站类型数据块缓存Typ : ARRAY[1..100] OF STRUCTbMax : BYTE; //最大长度bAct : BYTE; //实际长度arrText : ARRAY[1..8] OF CHAR; //类型字符数组Data : STRUCTIO : BOOL; //类型有效标志END_STRUCT;END_STRUCT;END_STRUCT;END_VAR```**解读**:- 静态变量用于存储持久化状态(功能块调用间保持值),如`_dwVisuWerte1`/`_dwVisuWerte2`控制可视化界面的状态(颜色、闪烁等);`arrRBS`存储当前读取的毛坯代码字符;`tempDB_RBS`/`tempDB_STyp`缓存数据块内容(避免频繁读取DB);`arrCode_RBS`存储RBS字符的Code39编码(用于校验位计算)。#### 四、代码主体解读##### 1. 数据块初始化与参数计算```scl(* 数据块读取 *)IF Init OR NOT xInit OR "Neustart" THENerg_SFC20:= BLKMOV(srcblk:= DB_RBS , dstblk:= tempDB_RBS); //将DB_RBS复制到缓存tempDB_RBSerg_SFC20:= BLKMOV(srcblk:= DB_STyp , dstblk:= tempDB_STyp); //将DB_STyp复制到缓存tempDB_STyp(* 计算毛坯代码位数 *)iRBSAnz := WORD_TO_INT(pDB_RBS.Anz) / 1666; //pDB_RBS.Anz是DB_RBS的总长度,1666为单个位的长度(* 计算毛坯代码长度(带/不带校验位) *)IF Cfg.X1 THEN //Cfg.X1=1:不使用校验位iRBSLen := iRBSAnz;ELSE //使用校验位:长度=位数+1iRBSLen := iRBSAnz + 1;END_IF;(* 计算工作站类型DB中的条目数 *)iTypAnz := WORD_TO_INT(pDB_STyp.Anz) / 12; //pDB_STyp.Anz是DB_STyp的总长度,12为单个条目的长度END_IF;```**解读**:- 当`Init`触发、未初始化(`xInit=0`)或系统重启(`Neustart`)时,通过`BLKMOV`(块移动指令)将`DB_RBS`(毛坯代码数据块)和`DB_STyp`(工作站类型数据块)的数据缓存到`tempDB_RBS`和`tempDB_STyp`(减少对实际DB的访问)。- 计算核心参数:`iRBSAnz`(毛坯代码的位数)、`iRBSLen`(带/不带校验位的总长度)、`iTypAnz`(工作站类型的条目数量)。##### 2. 配置RBS数据的ANY指针```scl(* 设置ANY指针到RBS数据 *)p_RBS.SyntaxId := B#16#10; //ANY指针的语法ID固定为16#10p_RBS.DataType := 02; //数据类型:02=BYTE(RBS为字符,按字节存储)p_RBS.DataCount := INT_TO_WORD(iRBSLen); //长度:RBS的总长度(含校验位)p_RBS.DBNR := pRBS.DBNR; //DB编号:从RBS指针获取p_RBS.BZ := pRBS.BZ; //区域指针:从RBS指针获取```**解读**:- 配置`anyRBS`指针(`p_RBS`)指向实际的RBS数据,`SyntaxId=16#10`是西门子ANY指针的固定格式,`DataType=02`表示数据为字节类型,`DataCount`为RBS的长度。##### 3. 可视化按键评估```scl(******* 按键评估 ****************************************************************)IF PC_AKTIV = DWORD#16#00000000 THEN //PC未激活时,软键输入清零bVisuTasten := Byte#0;END_IF;xS_UebPZ := (bVisuTasten = Byte#1); //bVisuTasten=1:校验位接收按键xS_TypFrg := (bVisuTasten = Byte#2); //bVisuTasten=2:类型输入接收按键```**解读**:- 读取可视化界面的软键输入(`bVisuTasten`),映射为具体功能:`xS_UebPZ`(校验位接收)和`xS_TypFrg`(类型输入接收)。##### 4. 上升沿检测```scl(******* 上升沿检测 ***************************************************************)R_TRIG_S_TypFrg_Q := xS_TypFrg AND NOT xR_TRIG_S_TypFrg_Edge; //xS_TypFrg的上升沿(单次触发)xR_TRIG_S_TypFrg_Edge := xS_TypFrg; //记忆xS_TypFrg的当前状态R_TRIG_Auto_Q := Auto AND NOT xR_TRIG_Auto_Q_Edge; //Auto的上升沿(单次触发)xR_TRIG_Auto_Q_Edge := Auto; //记忆Auto的当前状态```**解读**:- 通过“当前值为1且前值为0”检测上升沿,确保`xS_TypFrg`(类型接收)和`Auto`(自动模式使能)的触发信号仅有效一次(避免持续触发)。##### 5. 重置接收标志```scl(******* 重置接收 ***************************************************************)IF FM_Reset OR (NOT Hand AND R_TRIG_Auto_Q) THENxUebern := False; //清除RBS已接收标志END_IF;```**解读**:- 当`FM_Reset`(重置命令)触发,或切换到自动模式(`Hand=0`且`Auto`上升沿)时,清除`xUebern`(RBS已接收标志),允许重新接收RBS。##### 6. RBS接收(手动/自动模式)```scl(******* RBS接收 *****************************************************************)//手动RBS接收IF NOT xUebern AND Hand THEN //未接收且手动模式使能IF dwVisuWerte1.X15 THEN //手动字符串输入接收标志触发arrRBS := strVisuWertRBS.arrText; //从可视化字符串读取RBS字符dwVisuWerte1.X15 := False; //清除标志ELSEFOR iLauf := 1 TO iRBSAnz BY 1 DO //循环读取各位置IF iVisuTastenS[iLauf] >= 1 AND iVisuTastenS[iLauf] <= 16 THEN //软键输入有效arrRBS[iLauf] := tempDB_RBS.Z[iLauf].Z[iVisuTastenS[iLauf]].CH; //从缓存读取对应字符ELSEarrRBS[iLauf] := '*'; //无效输入用'*'表示END_IF;END_FOR;IF NOT Cfg.X1 THEN //使用校验位时IF xS_UebPZ AND xRBS_IO THEN //校验位接收按键触发且RBS有效arrRBS[iRBSLen] := chrPZ; //用计算出的校验位填充ELSIF arrRBS[iRBSLen] <> chrPZ THEN //输入校验位与计算值不符arrRBS[iRBSLen] := '*'; //标记异常END_IF;END_IF;END_IF;//自动RBS接收ELSIF NOT xUebern AND Auto THEN //未接收且自动模式使能erg_SFC20 := BLKMOV(SRCBLK := anyRBS ,DSTBLK := arrRBS); //从RBS数据块自动读取字符END_IF;```**解读**:- **手动模式**:通过可视化界面输入RBS,支持两种方式:直接输入字符串(`dwVisuWerte1.X15`触发)或通过软键选择字符(`iVisuTastenS`),无效输入用`*`标记;若启用校验位,需匹配计算出的`chrPZ`。- **自动模式**:通过`BLKMOV`从`anyRBS`指向的RBS数据块自动读取字符到`arrRBS`。##### 7. RBS预设位置评估(位置1)```scl(******* 评估RBS预设位置1 ********************************************************)anyDB_RBS1 := DB_RBS; //指向原始DB_RBSanyDB_RBS2 := tempDB_RBS.Z[2]; //指向缓存中RBS的位置2IF Cfg.X0 THEN //Cfg.X0=1:需评估DB_RBS的预设位置2-xFOR i := 1 TO 16 BY 1 DO //循环匹配位置1的字符IF tempDB_RBS.Z[1].Z[i].CH = arrRBS[1] THEN //位置1字符匹配iSicht_RBS := tempDB_RBS.Z[1].Z[i].Sicht_RBS; //获取可见性偏移iBer_RBS := 1666 * (iRBSAnz - 1); //计算区域长度(位置2-x的总长度)p_DB_RBS1.DataCount := INT_TO_WORD(iBer_RBS); //设置数据长度//调整区域指针(指向位置2-x的起始地址)p_DB_RBS1.BZ := 16#84000000 OR SHL(IN:=INT_TO_DWORD(1666 + (iBer_RBS * iSicht_RBS)),N:=3);p_DB_RBS2.DataCount := INT_TO_WORD(iBer_RBS); //缓存中位置2-x的长度p_DB_RBS2.BZ := p_DB_RBS2.BZ OR 16#1000000; //调整区域指针(从DB到DI)erg_SFC20:= BLKMOV(srcblk:= anyDB_RBS1 , dstblk:= anyDB_RBS2); //更新缓存中位置2-x的数据END_IF;END_FOR;END_IF;```**解读**:- 当`Cfg.X0=1`时,需根据RBS位置1的字符匹配预设规则,动态更新位置2-x的数据(从`DB_RBS`复制到缓存`tempDB_RBS.Z[2]`),实现灵活的RBS结构适配。##### 8. 重置与初始化```scl(****** 重置 ***************************************************************************)IF NOT xUebern OR FM_Reset THEN //未接收或重置时arrRBS_IO := arrTemp; //清空RBS各位置正常标志xRBS_IO := False; //RBS整体正常标志清零xRBS_NIO := False; //RBS整体异常标志清零xRBS_PZ_IO := False; //RBS+校验位正常标志清零xRBS_PZ_NIO := False; //RBS+校验位异常标志清零iVisuTastenS[1] := 0; //软键输入值清零(位置1)iVisuTastenS[2] := 0; //位置2iVisuTastenS[3] := 0; //位置3iVisuTastenS[4] := 0; //位置4iVisuTastenS[5] := 0; //位置5iVisuTastenS[6] := 0; //位置6iVisuTastenS[7] := 0; //位置7iVisuTastenS[8] := 0; //位置8CASE iRBSLen OF //根据RBS长度初始化可视化字符串4 : _strVisuWertRBS := '****';5 : _strVisuWertRBS := '*****';6 : _strVisuWertRBS := '******';7 : _strVisuWertRBS := '*******';8 : _strVisuWertRBS := '********';9 : _strVisuWertRBS := '*********';END_CASE;_strVisuWertPZ := '*'; //校验位可视化字符串初始化arrSTyp_IO := arrTemp; //清空工作站类型各位置正常标志xSTyp_IO := False; //工作站类型整体正常标志清零xSTyp_NIO := False; //工作站类型整体异常标志清零wData := Word#0; //工作站类型数据清零xCODE39_IO := False; //Code39校验正常标志清零xCODE39_NIO := False; //Code39校验异常标志清零END_IF;```**解读**:- 当未接收RBS或`FM_Reset`触发时,重置所有与RBS、工作站类型相关的标志和变量,初始化可视化字符串(用`*`占位),确保下次接收前状态干净。##### 9. RBS有效性评估```scl(***** 评估毛坯代码 ******************************************************)IF (HAND OR Auto) AND NOT xUebern AND NOT FM_Reset THEN //手动/自动使能、未接收、未重置FOR i := 1 TO iRBSAnz BY 1 DO //循环评估各位置FOR iLauf := 1 TO 16 BY 1 DO //匹配缓存中的有效字符IF tempDB_RBS.Z[i].Z[iLauf].CH = arrRBS[i] THEN //字符匹配arrRBS_IO[i] := tempDB_RBS.Z[i].Z[iLauf].Frg; //获取该字符的有效标志IF arrRBS_IO[i] THEN //字符有效iVisuTastenS[i] := iLauf; //记录软键输入值strVisuWertRBS.arrText[i] := tempDB_RBS.Z[i].Z[iVisuTastenS[i]].CH; //更新可视化字符END_IF;EXIT; //匹配后退出内层循环ELSIF tempDB_RBS.Z[i].Z[iLauf].CH = ' ' THEN //遇到空格(结束符)EXIT;END_IF;END_FOR;arrRBS_NIO[i] := NOT arrRBS_IO[i]; //异常标志=非正常标志END_FOR;xRBS_IO := True; //默认RBS整体正常FOR i := 1 TO iRBSAnz BY 1 DO //检查所有位置xRBS_IO := xRBS_IO AND arrRBS_IO[i]; //整体正常=所有位置正常xRBS_NIO := NOT xRBS_IO; //整体异常=非整体正常END_FOR;END_IF;```**解读**:- 评估RBS各位置的字符是否有效:循环匹配`tempDB_RBS`中定义的有效字符,设置`arrRBS_IO`(位置正常)和`arrRBS_NIO`(位置异常)。- `xRBS_IO`为所有位置正常的“与”结果(全正常才为1),`xRBS_NIO`为其反值。##### 10. 校验位评估(Code39算法)```scl(***** 评估校验位 ***********************************************************)IF NOT Cfg.X1 AND xRBS_IO THEN //启用校验位且RBS本身正常strVisuWertRBS.arrText[iRBSLen] := arrRBS[iRBSLen]; //更新可视化校验位FOR iLauf := 1 TO iRBSLen BY 1 DO //将RBS字符转换为Code39编码IF strVisuWertRBS.arrText[iLauf] = '0' THEN arrCode_RBS[iLauf] := 0;ELSIF strVisuWertRBS.arrText[iLauf] = '1' THEN arrCode_RBS[iLauf] := 1;ELSIF strVisuWertRBS.arrText[iLauf] = '2' THEN arrCode_RBS[iLauf] := 2;ELSIF strVisuWertRBS.arrText[iLauf] = '3' THEN arrCode_RBS[iLauf] := 3;ELSIF strVisuWertRBS.arrText[iLauf] = '4' THEN arrCode_RBS[iLauf] := 4;ELSIF strVisuWertRBS.arrText[iLauf] = '5' THEN arrCode_RBS[iLauf] := 5;ELSIF strVisuWertRBS.arrText[iLauf] = '6' THEN arrCode_RBS[iLauf] := 6;ELSIF strVisuWertRBS.arrText[iLauf] = '7' THEN arrCode_RBS[iLauf] := 7;ELSIF strVisuWertRBS.arrText[iLauf] = '8' THEN arrCode_RBS[iLauf] := 8;ELSIF strVisuWertRBS.arrText[iLauf] = '9' THEN arrCode_RBS[iLauf] := 9;ELSIF strVisuWertRBS.arrText[iLauf] = 'A' THEN arrCode_RBS[iLauf] := 10;ELSIF strVisuWertRBS.arrText[iLauf] = 'B' THEN arrCode_RBS[iLauf] := 11;ELSIF strVisuWertRBS.arrText[iLauf] = 'C' THEN arrCode_RBS[iLauf] := 12;ELSIF strVisuWertRBS.arrText[iLauf] = 'D' THEN arrCode_RBS[iLauf] := 13;ELSIF strVisuWertRBS.arrText[iLauf] = 'E' THEN arrCode_RBS[iLauf] := 14;ELSIF strVisuWertRBS.arrText[iLauf] = 'F' THEN arrCode_RBS[iLauf] := 15;ELSIF strVisuWertRBS.arrText[iLauf] = 'G' THEN arrCode_RBS[iLauf] := 16;ELSIF strVisuWertRBS.arrText[iLauf] = 'H' THEN arrCode_RBS[iLauf] := 17;ELSIF strVisuWertRBS.arrText[iLauf] = 'I' THEN arrCode_RBS[iLauf] := 18;ELSIF strVisuWertRBS.arrText[iLauf] = 'J' THEN arrCode_RBS[iLauf] := 19;ELSIF strVisuWertRBS.arrText[iLauf] = 'K' THEN arrCode_RBS[iLauf] := 20;ELSIF strVisuWertRBS.arrText[iLauf] = 'L' THEN arrCode_RBS[iLauf] := 21;ELSIF strVisuWertRBS.arrText[iLauf] = 'M' THEN arrCode_RBS[iLauf] := 22;ELSIF strVisuWertRBS.arrText[iLauf] = 'N' THEN arrCode_RBS[iLauf] := 23;ELSIF strVisuWertRBS.arrText[iLauf] = 'O' THEN arrCode_RBS[iLauf] := 24;ELSIF strVisuWertRBS.arrText[iLauf] = 'P' THEN arrCode_RBS[iLauf] := 25;ELSIF strVisuWertRBS.arrText[iLauf] = 'Q' THEN arrCode_RBS[iLauf] := 26;ELSIF strVisuWertRBS.arrText[iLauf] = 'R' THEN arrCode_RBS[iLauf] := 27;ELSIF strVisuWertRBS.arrText[iLauf] = 'S' THEN arrCode_RBS[iLauf] := 28;ELSIF strVisuWertRBS.arrText[iLauf] = 'T' THEN arrCode_RBS[iLauf] := 29;ELSIF strVisuWertRBS.arrText[iLauf] = 'U' THEN arrCode_RBS[iLauf] := 30;ELSIF strVisuWertRBS.arrText[iLauf] = 'V' THEN arrCode_RBS[iLauf] := 31;ELSIF strVisuWertRBS.arrText[iLauf] = 'W' THEN arrCode_RBS[iLauf] := 32;ELSIF strVisuWertRBS.arrText[iLauf] = 'X' THEN arrCode_RBS[iLauf] := 33;ELSIF strVisuWertRBS.arrText[iLauf] = 'Y' THEN arrCode_RBS[iLauf] := 34;ELSIF strVisuWertRBS.arrText[iLauf] = 'Z' THEN arrCode_RBS[iLauf] := 35;ELSIF strVisuWertRBS.arrText[iLauf] = '-' THEN arrCode_RBS[iLauf] := 36;ELSIF strVisuWertRBS.arrText[iLauf] = '.' THEN arrCode_RBS[iLauf] := 37;ELSIF strVisuWertRBS.arrText[iLauf] = ' ' THEN arrCode_RBS[iLauf] := 38;ELSIF strVisuWertRBS.arrText[iLauf] ='$24'THEN arrCode_RBS[iLauf] := 39;ELSIF strVisuWertRBS.arrText[iLauf] = '/' THEN arrCode_RBS[iLauf] := 40;ELSIF strVisuWertRBS.arrText[iLauf] = '+' THEN arrCode_RBS[iLauf] := 41;ELSIF strVisuWertRBS.arrText[iLauf] = '%' THEN arrCode_RBS[iLauf] := 42;END_IF;END_FOR;iCharCode39 := 0; //初始化编码总和FOR i := 1 TO iRBSAnz BY 1 DO //计算RBS位(不含校验位)的编码总和iCharCode39 := iCharCode39 + arrCode_RBS[i];END_FOR;iMOD_39 := iCharCode39 MOD 43 ; //总和模43(Code39校验规则)//检查输入校验位是否与计算值匹配IF arrCode_RBS[iRBSLen] = iMOD_39 AND strVisuWertRBS.arrText[iRBSLen] <> '*' THENxCODE39_IO := True; //校验正常xCODE39_NIO := False;ELSExCODE39_IO := False; //校验异常xCODE39_NIO := True;END_IF;//根据模43结果确定校验位字符CASE iMOD_39 OF0 : chrPZ := '0';1 : chrPZ := '1';2 : chrPZ := '2';3 : chrPZ := '3';4 : chrPZ := '4';5 : chrPZ := '5';6 : chrPZ := '6';7 : chrPZ := '7';8 : chrPZ := '8';9 : chrPZ := '9';10 : chrPZ := 'A';11 : chrPZ := 'B';12 : chrPZ := 'C';13 : chrPZ := 'D';14 : chrPZ := 'E';15 : chrPZ := 'F';16 : chrPZ := 'G';17 : chrPZ := 'H';18 : chrPZ := 'I';19 : chrPZ := 'J';20 : chrPZ := 'K';21 : chrPZ := 'L';22 : chrPZ := 'M';23 : chrPZ := 'N';24 : chrPZ := 'O';25 : chrPZ := 'P';26 : chrPZ := 'Q';27 : chrPZ := 'R';28 : chrPZ := 'S';29 : chrPZ := 'T';30 : chrPZ := 'U';31 : chrPZ := 'V';32 : chrPZ := 'W';33 : chrPZ := 'X';34 : chrPZ := 'Y';35 : chrPZ := 'Z';36 : chrPZ := '-';37 : chrPZ := '.';38 : chrPZ := ' ';39 : chrPZ := '$24';40 : chrPZ := '/';41 : chrPZ := '+';42 : chrPZ := '%';END_CASE;ELSEchrPZ := '*'; //不启用校验位或RBS异常时,校验位无效END_IF;strVisuWertPZ.arrText[1] := chrPZ; //更新可视化校验位(*RBS整体有效性(含校验位)*)xRBS_PZ_IO := xRBS_IO AND (xCODE39_IO OR Cfg.X1); //整体正常=RBS正常且(校验正常或不启用校验)xRBS_PZ_NIO := xRBS_NIO OR (xCODE39_NIO AND NOT Cfg.X1); //整体异常=RBS异常或(校验异常且启用校验)```**解读**:- 当启用校验位(`Cfg.X1=0`)且RBS本身正常(`xRBS_IO=1`)时,通过Code39算法计算校验位:1. 将RBS字符映射为Code39编码(0-42);2. 计算RBS位(不含校验位)的编码总和,对43取模(`iMOD_39`);3. 模值对应的字符即为正确校验位(`chrPZ`),与输入校验位比对,设置`xCODE39_IO`(校验正常)。- `xRBS_PZ_IO`为RBS整体有效性(含校验位),`xRBS_PZ_NIO`为其反值。##### 11. 工作站类型评估```scl(****** 评估工作站类型 **********************************************************)IF (HAND OR Auto) AND NOT xUebern AND NOT FM_Reset AND xRBS_PZ_IO THEN //RBS有效时评估工作站类型FOR iLauf := 1 TO iTypAnz BY 1 DO //循环匹配工作站类型条目FOR i := 1 TO iRBSAnz BY 1 DO //匹配各位置字符IF tempDB_STyp.Typ[iLauf].arrText[i] = arrRBS[i] //字符完全匹配OR tempDB_STyp.Typ[iLauf].arrText[i] = 'X' AND NOT cfg.X2 //占位符X(Cfg.X2=0)OR tempDB_STyp.Typ[iLauf].arrText[i] = '~' AND cfg.X2 //占位符~(Cfg.X2=1)THENarrSTyp_IO[i] := True; //该位置匹配ELSEEXIT; //不匹配则退出内层循环END_IF;END_FOR;IF arrSTyp_IO[iRBSAnz] THEN //所有位置都匹配_wData := tempDB_STyp.Typ[iLauf].Data; //获取该类型的数据EXIT; //退出外层循环END_IF;END_FOR;xSTyp_IO := arrSTyp_IO[iRBSAnz]; //工作站类型正常=所有位置匹配xSTyp_NIO := NOT xSTyp_IO; //工作站类型异常=非正常END_IF;```**解读**:- 当RBS有效(`xRBS_PZ_IO=1`)时,评估RBS是否匹配`tempDB_STyp`中定义的工作站类型:- 支持精确匹配或占位符匹配(`X`或`~`,由`Cfg.X2`控制);- 所有位置匹配时,`xSTyp_IO=1`(工作站类型正常),并获取对应数据`_wData`。##### 12. 接收确认```scl(* 接收确认 *)IF ((Auto AND NOT Hand) OR (Hand AND R_TRIG_S_TypFrg_Q AND NOT xUebern)) AND xRBS_PZ_IO AND NOT FM_Reset THENxUebern := True; //设置RBS已接收标志(自动模式或手动触发且RBS有效)ELSIF (Hand AND R_TRIG_S_TypFrg_Q AND xUebern) OR xRBS_PZ_NIO OR FM_Reset THENxUebern := False; //清除接收标志(手动触发已接收、RBS异常或重置)END_IF;//更新手动/自动接收标志R_TRIG_Uebern := xUebern AND NOT xR_TRIG_Uebern; //xUebern的上升沿xR_TRIG_Uebern := xUebern; //记忆xUebern状态IF R_TRIG_Uebern THEN //接收成功时xHand := Hand; //记录手动模式xAuto := NOT Hand; //记录自动模式ELSIF NOT xUebern THEN //未接收时xHand := False;xAuto := False;END_IF;```**解读**:- 当满足以下条件时,设置`xUebern`(RBS已接收标志):- 自动模式(`Auto=1`且`Hand=0`)且RBS有效;- 手动模式(`Hand=1`)且触发`R_TRIG_S_TypFrg_Q`(类型接收上升沿)且RBS有效。- 记录当前接收模式(`xHand`/`xAuto`)。##### 13. 输出变量赋值```scl(***** 输出 *************************************************************************)RBS_IO := xRBS_PZ_IO; //RBS正常=RBS+校验位正常RBS_NIO := xRBS_PZ_NIO; //RBS异常=RBS+校验位异常STypIO := xSTyp_IO AND xUebern; //工作站类型正常=类型正常且已接收STypNIO := xSTyp_NIO AND xUebern; //工作站类型异常=类型异常且已接收FM := xUebern; //RBS已接收标志//初始化RBS各位置输出(位编码)RBS_S1 := Word#0;RBS_S2 := Word#0;// ... 省略RBS_S3至RBS_S7 ...RBS_S8 := Word#0;Data := Word#0;IF xUebern THEN //已接收时更新输出IF iVisuTastenS[1] > 0 THEN RBS_S1 := ROL (IN:=WORD#2#0000_0000_1000_0000, N:=iVisuTastenS[1]); END_IF; //位1编码IF iVisuTastenS[2] > 0 THEN RBS_S2 := ROL (IN:=WORD#2#0000_0000_1000_0000, N:=iVisuTastenS[2]); END_IF; //位2编码// ... 省略RBS_S3至RBS_S8的编码 ...Data := wData; //输出工作站类型数据END_IF;```**解读**:- 输出变量与内部状态映射:`RBS_IO`/`RBS_NIO`反映RBS整体有效性,`STypIO`/`STypNIO`反映工作站类型有效性(仅在已接收时有效),`FM`为接收标志。- `RBS_S1`至`RBS_S8`通过循环左移(`ROL`)将软键输入值编码为位信号,便于外部识别具体位置。##### 14. 数据块更新(RBS_S数据)```scl(* 设置ANY指针到RBS_S数据源 *)anyQRBS_S := Data; //源为工作站类型数据p_QRBS_S.DataType := Byte#4; //数据类型:4=WORDp_QRBS_S.DataCount := INT_TO_WORD(iRBSAnz + 1); //长度:RBS位数+1p_QRBS_S.BZ := p_QRBS_S.BZ OR 16#1000000; //调整区域指针(从DB到DI)(* 设置ANY指针到RBS_S数据目标 *)anyZRBS_S := DB_STyp; //目标为工作站类型数据块p_ZRBS_S.DataType := Byte#4; //数据类型:4=WORDp_ZRBS_S.DataCount := INT_TO_WORD(iRBSAnz + 1); //长度:RBS位数+1p_ZRBS_S.BZ := SHL(IN:=pDB_STyp.Anz, N:=3) OR 16#84000000; //计算目标区域指针erg_SFC20 := BLKMOV(SRCBLK := anyQRBS_S ,dstblk := anyZRBS_S); //将RBS_S数据写入目标DB```**解读**:- 配置指针将工作站类型数据(`Data`)写入`DB_STyp`(工作站类型数据块),实现数据持久化存储。##### 15. 循环周期优化```scl(* 循环时间优化 *)iZyklus16 := iZyklus16 + 1; //16分频计数器IF iZyklus16 > 16 THENiZyklus16 := 1;iZyklus := iZyklus + 1; //主循环计数器IF iZyklus > iRBSAnz THENiZyklus := 1; //计数器回环(最大为RBS位数)END_IF;END_IF;```**解读**:- 通过分频计数器(`iZyklus16`)和主计数器(`iZyklus`)控制可视化更新频率,避免高频刷新占用过多资源。##### 16. 可视化文本更新```scl(* 列标题 *)strVisuText.S[iZyklus].Bez := tempDB_RBS.Z[iZyklus].Bez[Sprache]; //根据语言更新列标题(* 按键标题 *)strVisuText.S[iZyklus].Z[iZyklus16].Bez := tempDB_RBS.Z[iZyklus].Z[iZyklus16].Bez[Sprache]; //根据语言更新按键标题```**解读**:- 根据当前语言(`Sprache`)和循环计数器,动态更新可视化界面的列标题和按键文本(支持多语言)。##### 17. 可视化状态与颜色控制```scl(******* 可视化数据 **************************************************)(**************************颜色编码表***********************************************)(*BK=黑, BU=蓝, GN=绿, GR=灰, LT=浅, WH=白, YE=黄, RD=红 *)(*st=静态, bl=闪烁 *)(*HEX/INT 背景色 文本色 *)(*H00/I00: 灰st 黑st *)(*H01/I01: 不可见 *)(*H02/I02: 绿st 黑st *)(*H03/I03: 蓝st 白st *)(*H04/I04: 红st 白st *)(*... 省略其他颜色编码 ... *)(****************************************************************************************)//可视化状态位配置dwVisuWerte1.X0 := Hand AND NOT xUebern AND NOT FM_Reset; //手动输入使能dwVisuWerte1.X1 := Auto; //自动模式使能dwVisuWerte1.X2 := Hand; //手动模式使能dwVisuWerte1.X3 := xRBS_NIO AND NOT arrRBS_IO[1] OR (xSTyp_NIO AND NOT arrSTyp_IO[1]) AND NOT xUebern; //RBS位1故障闪烁// ... 省略RBS位2至位8的故障闪烁配置 ...dwVisuWerte1.X11 := iRBSAnz >= 5; //位5可见dwVisuWerte1.X12 := iRBSAnz >= 6; //位6可见dwVisuWerte1.X13 := iRBSAnz >= 7; //位7可见dwVisuWerte1.X14 := iRBSAnz >= 8; //位8可见dwVisuWerte1.X15 := dwVisuWerte1.X15; //手动RBS接收标志//RBS边框颜色(正常=绿,异常=红)bFarbKombi := byte#16#00; //默认灰底黑字IF xRBS_PZ_IO THEN //RBS正常bFarbKombi := byte#16#02; //绿底黑字ELSIF xRBS_PZ_NIO THEN //RBS异常bFarbKombi := byte#16#04; //红底白字END_IF;dwVisuWerte1.B2 := bFarbKombi; //更新可视化//校验位边框颜色(故障=红)bFarbKombi := byte#16#00;IF False THEN //预留故障条件bFarbKombi := byte#16#04; //红底白字END_IF;dwVisuWerte1.B2 := dwVisuWerte1.B2 OR SHL(IN:=bFarbKombi,N:=4); //高4位控制校验位边框// ... 省略其他可视化元素(符号边框、按钮颜色)的颜色配置 ...```**解读**:- 配置可视化界面的状态位(如手动/自动模式、故障闪烁)和颜色(基于颜色编码表),直观反映系统状态(正常为绿,异常为红)。##### 18. 消息系统与故障处理```scl(****************************************************************************************)(*******************消息系统信号处理 *******************************)(***********************在SCL块末尾调用**********************************)TempPointerMsys := Msys; //消息系统指针TempPointerFlanken := Msys.Flanken; //边沿检测指针TempPointerMeldpuffer := ST_Meld; //消息缓冲区指针pMeldFeld.BZ := pMeldFeld.BZ OR 16#1000000; //调整区域指针(DB→DI)pMeldAbb.BZ := pMeldAbb.BZ OR 16#1000000;pMeldFeld.TYP := 1; //数据类型=BOOLpMeldFeld.ANZ := 16; //16个消息标志pMeldAbb.TYP := 2; //数据类型=BYTEpMeldAbb.ANZ := 2; //2个边沿检测字节//消息标志映射(故障源)MSYS.xF_1 := xRBS_NIO AND arrRBS_NIO[1]; //RBS位1异常MSYS.xF_2 := xRBS_NIO AND arrRBS_NIO[2]; //RBS位2异常// ... 省略RBS位3至位8的故障映射 ...MSYS.xF_9 := STypNIO; //工作站类型无效MSYS.xF_10 := xCODE39_NIO; //校验位异常MSYS.xF_11 := HAND AND NOT xUebern; //手动输入激活//发送消息MeldSend(AufrufNr := 1,Anz_Meld := 11,pMeldFeld := pMeldFeld.BZ,pMeldAbb := pMeldAbb.BZ,MeldDB := WORD_TO_INT(pMeldDBNR.DBNR),AenderungsID := AenderungsID,Integritaet := xIntegritaet,Neustart := Neustart); // 发送消息到消息系统xInit := True; //初始化完成//故障/警告/维护消息汇总xStoe := Msys.xF_1 OR Msys.xF_2 OR Msys.xF_3 OR Msys.xF_4 OR Msys.xF_5 OR Msys.xF_6 OR Msys.xF_7 OR Msys.xF_8 OR Msys.xF_10; //故障汇总DB_ARG.VisuSS.Station_Stoer:= DB_ARG.VisuSS.Station_Stoer OR xStoe; //更新全局故障xWarn := Msys.xF_9 OR Msys.xF_11; //警告汇总DB_ARG.VisuSS.Station_Warn := DB_ARG.VisuSS.Station_Warn OR xWarn; //更新全局警告xWart := False; //维护消息(预留)DB_ARG.VisuSS.Station_Wart := DB_ARG.VisuSS.Station_Wart OR xWart;```**解读**:- 将内部故障(如RBS位异常、校验位错误)映射到消息系统标志(`MSYS.xF_1`至`xF_11`),通过`MeldSend`发送到消息缓冲区(`ST_Meld`)。- 汇总故障(`xStoe`)、警告(`xWarn`)并更新全局状态(`DB_ARG`),实现故障的集中监控。##### 19. 故障输出```scl(***** 汇总故障 *******************************************************************)Stoe := xStoe; //输出汇总故障(***** 连锁故障 **************************************************************)VkStoe_Out := VkStoe_In OR xStoe; //连锁故障=输入连锁故障OR内部故障```**解读**:- `Stoe`输出内部汇总故障;`VkStoe_Out`输出连锁故障(包含外部输入故障和内部故障),用于故障级联传递。#### 五、总结FB_Typ_VAR(FB529)是一个用于评估毛坯代码(RBS)和工作站类型的功能块,核心功能包括:1. 支持手动/自动模式接收RBS,通过数据块缓存实现高效访问。2. 对RBS进行有效性校验(含Code39校验位),评估各位置字符是否合法。3. 匹配工作站类型(支持占位符`X`/`~`),判断是否与RBS匹配。4. 丰富的可视化交互(多语言、颜色状态、软键输入)和故障消息系统,便于运维监控。该功能块广泛应用于工业自动化场景(如汽车生产),确保毛坯代码与工作站类型的一致性,提高生产过程的可靠性。
部分详细解读:
1. 数据块初始化与参数计算
##### 1. 数据块初始化与参数计算```scl(* 数据块读取 *)IF Init OR NOT xInit OR "Neustart" THENerg_SFC20:= BLKMOV(srcblk:= DB_RBS , dstblk:= tempDB_RBS); //将DB_RBS复制到缓存tempDB_RBSerg_SFC20:= BLKMOV(srcblk:= DB_STyp , dstblk:= tempDB_STyp); //将DB_STyp复制到缓存tempDB_STyp(* 计算毛坯代码位数 *)iRBSAnz := WORD_TO_INT(pDB_RBS.Anz) / 1666; //pDB_RBS.Anz是DB_RBS的总长度,1666为单个位的长度(* 计算毛坯代码长度(带/不带校验位) *)IF Cfg.X1 THEN //Cfg.X1=1:不使用校验位iRBSLen := iRBSAnz;ELSE //使用校验位:长度=位数+1iRBSLen := iRBSAnz + 1;END_IF;(* 计算工作站类型DB中的条目数 *)iTypAnz := WORD_TO_INT(pDB_STyp.Anz) / 12; //pDB_STyp.Anz是DB_STyp的总长度,12为单个条目的长度END_IF;```
解读:
- 当`Init`触发、未初始化(`xInit=0`)或系统重启(`Neustart`)时,通过`BLKMOV`(块移动指令)将`DB_RBS`(毛坯代码数据块)和`DB_STyp`(工作站类型数据块)的数据缓存到`tempDB_RBS`和`tempDB_STyp`(减少对实际DB的访问)。
- 计算核心参数:`iRBSAnz`(毛坯代码的位数)、`iRBSLen`(带/不带校验位的总长度)、`iTypAnz`(工作站类型的条目数量)。
1.1:
erg_SFC20:=BLKMOV(srcblk:= DB_STyp , dstblk:= tempDB_STyp); //将DB_STyp复制到缓存tempDB_STyp
两个结构不同,目的是将原来的字符串拆分开
bMax是复制的字符串最大值,
bAct 字符串当前长度,
因为字符串前面两个字节是隐藏的,所以在拆分的时候要写出来
1.2:
(* 计算车型代码位数 *)
iRBSAnz := WORD_TO_INT(pDB_RBS.Anz) / 1666; //pDB_RBS.Anz是DB_RBS的总长度,1666为单个位的长度
4代表四位车型码,四组
1.3:
ELSE //使用校验位:长度=位数+1
iRBSLen := iRBSAnz + 1;
此时+1 加一位代表着第五位的校验位
1.4:
iTypAnz := WORD_TO_INT(pDB_STyp.Anz) /12; //pDB_STyp.Anz是DB_STyp的总长度,12为单个条目的长度
48组数据
FB530的STyp结构总长度为576(16进制240) 除以12(每组车型12个字节占一组)
2. 配置RBS数据的ANY指针
(* 设置ANY指针到RBS数据 *)p_RBS.SyntaxId := B#16#10; //ANY指针的语法ID固定为16#10p_RBS.DataType := 02; //数据类型:02=BYTE(RBS为字符,按字节存储)p_RBS.DataCount := INT_TO_WORD(iRBSLen); //长度:RBS的总长度(含校验位)p_RBS.DBNR := pRBS.DBNR; //DB编号:从RBS指针获取p_RBS.BZ := pRBS.BZ; //区域指针:从RBS指针获取
解读:
- 配置`anyRBS`指针(`p_RBS`)指向实际的RBS数据,`SyntaxId=16#10`是西门子ANY指针的固定格式,`DataType=02`表示数据为字节类型,`DataCount`为RBS的长度。
DataCount:重复系数,只复制5个数据
输入数据RBS、DB2389.DBB89
2c8 —0010 1100 1000 —字地址89.0
(包含了字节地址与后三个位地址)
6. RBS接收(手动/自动模式)
(******* RBS接收 *****************************************************************)//手动RBS接收IF NOT xUebern AND Hand THEN //未接收且手动模式使能IF dwVisuWerte1.X15 THEN //手动字符串输入接收标志触发arrRBS := strVisuWertRBS.arrText; //从可视化字符串读取RBS字符dwVisuWerte1.X15 := False; //清除标志ELSEFOR iLauf := 1 TO iRBSAnz BY 1 DO //循环读取各位置IF iVisuTastenS[iLauf] >= 1 AND iVisuTastenS[iLauf] <= 16 THEN //软键输入有效arrRBS[iLauf] := tempDB_RBS.Z[iLauf].Z[iVisuTastenS[iLauf]].CH; //从缓存读取对应字符ELSEarrRBS[iLauf] := '*'; //无效输入用'*'表示END_IF;END_FOR;IF NOT Cfg.X1 THEN //使用校验位时IF xS_UebPZ AND xRBS_IO THEN //校验位接收按键触发且RBS有效arrRBS[iRBSLen] := chrPZ; //用计算出的校验位填充ELSIF arrRBS[iRBSLen] <> chrPZ THEN //输入校验位与计算值不符arrRBS[iRBSLen] := '*'; //标记异常END_IF;END_IF;END_IF;//自动RBS接收ELSIF NOT xUebern AND Auto THEN //未接收且自动模式使能erg_SFC20 := BLKMOV(SRCBLK := anyRBS ,DSTBLK := arrRBS); //从RBS数据块自动读取字符END_IF;
解读:
- 手动模式:通过可视化界面输入RBS,支持两种方式:直接输入字符串(`dwVisuWerte1.X15`触发)或通过软键选择字符(`iVisuTastenS`),无效输入用`*`标记;若启用校验位,需匹配计算出的`chrPZ`。
- 自动模式:通过`BLKMOV`从`anyRBS`指向的RBS数据块自动读取字符到`arrRBS`。
6.1:
IFiVisuTastenS[iLauf] >=1 AND iVisuTastenS[iLauf] <= 16 THEN //软键输入有效
iVisuTastenS数组为手动输入的数据
6.2:
arrRBS[iLauf] := tempDB_RBS.Z[iLauf].Z[iVisuTastenS[iLauf]].CH;//从缓存读取对应字符
iVisuTastenS[iLauf]
arrRBS[iLauf]
arrRBS[iRBSLen] := chrPZ; //用计算出的校验位填充
6.3:
erg_SFC20 :=BLKMOV(SRCBLK := anyRBS ,DSTBLK := arrRBS); //从RBS数据块自动读取字符
由输入RBS 传入
9. RBS有效性评估
(***** 评估毛坯代码 ******************************************************)IF (HAND OR Auto) AND NOT xUebern AND NOT FM_Reset THEN //手动/自动使能、未接收、未重置FOR i := 1 TO iRBSAnz BY 1 DO //循环评估各位置FOR iLauf := 1 TO 16 BY 1 DO //匹配缓存中的有效字符IF tempDB_RBS.Z[i].Z[iLauf].CH = arrRBS[i] THEN //字符匹配arrRBS_IO[i] := tempDB_RBS.Z[i].Z[iLauf].Frg; //获取该字符的有效标志IF arrRBS_IO[i] THEN //字符有效iVisuTastenS[i] := iLauf; //记录软键输入值strVisuWertRBS.arrText[i] := tempDB_RBS.Z[i].Z[iVisuTastenS[i]].CH; //更新可视化字符END_IF;EXIT; //匹配后退出内层循环ELSIF tempDB_RBS.Z[i].Z[iLauf].CH = ' ' THEN //遇到空格(结束符)EXIT;END_IF;END_FOR;arrRBS_NIO[i] := NOT arrRBS_IO[i]; //异常标志=非正常标志END_FOR;xRBS_IO := True; //默认RBS整体正常FOR i := 1 TO iRBSAnz BY 1 DO //检查所有位置xRBS_IO := xRBS_IO AND arrRBS_IO[i]; //整体正常=所有位置正常xRBS_NIO := NOT xRBS_IO; //整体异常=非整体正常END_FOR;END_IF;```
解读:
- 评估RBS各位置的字符是否有效:循环匹配`tempDB_RBS`中定义的有效字符,设置`arrRBS_IO`(位置正常)和`arrRBS_NIO`(位置异常)。
-`xRBS_IO`为所有位置正常的“与”结果(全正常才为1),`xRBS_NIO`为其反值。
9.1
arrRBS_IO[i]
9.2
strVisuWertRBS.arrText[i] :=tempDB_RBS.Z[i].Z[iVisuTastenS[i]].CH; //更新可视化字符
注意这里只存入前四个数据,校验位由下面的程序传入
10. 校验位评估(Code39算法)
(***** 评估校验位 ***********************************************************)IF NOT Cfg.X1 AND xRBS_IO THEN //启用校验位且RBS本身正常strVisuWertRBS.arrText[iRBSLen] := arrRBS[iRBSLen]; //更新可视化校验位FOR iLauf := 1 TO iRBSLen BY 1 DO //将RBS字符转换为Code39编码IF strVisuWertRBS.arrText[iLauf] = '0' THEN arrCode_RBS[iLauf] := 0;ELSIF strVisuWertRBS.arrText[iLauf] = '1' THEN arrCode_RBS[iLauf] := 1;ELSIF strVisuWertRBS.arrText[iLauf] = '2' THEN arrCode_RBS[iLauf] := 2;ELSIF strVisuWertRBS.arrText[iLauf] = '3' THEN arrCode_RBS[iLauf] := 3;ELSIF strVisuWertRBS.arrText[iLauf] = '4' THEN arrCode_RBS[iLauf] := 4;ELSIF strVisuWertRBS.arrText[iLauf] = '5' THEN arrCode_RBS[iLauf] := 5;ELSIF strVisuWertRBS.arrText[iLauf] = '6' THEN arrCode_RBS[iLauf] := 6;ELSIF strVisuWertRBS.arrText[iLauf] = '7' THEN arrCode_RBS[iLauf] := 7;ELSIF strVisuWertRBS.arrText[iLauf] = '8' THEN arrCode_RBS[iLauf] := 8;ELSIF strVisuWertRBS.arrText[iLauf] = '9' THEN arrCode_RBS[iLauf] := 9;ELSIF strVisuWertRBS.arrText[iLauf] = 'A' THEN arrCode_RBS[iLauf] := 10;ELSIF strVisuWertRBS.arrText[iLauf] = 'B' THEN arrCode_RBS[iLauf] := 11;ELSIF strVisuWertRBS.arrText[iLauf] = 'C' THEN arrCode_RBS[iLauf] := 12;ELSIF strVisuWertRBS.arrText[iLauf] = 'D' THEN arrCode_RBS[iLauf] := 13;ELSIF strVisuWertRBS.arrText[iLauf] = 'E' THEN arrCode_RBS[iLauf] := 14;ELSIF strVisuWertRBS.arrText[iLauf] = 'F' THEN arrCode_RBS[iLauf] := 15;ELSIF strVisuWertRBS.arrText[iLauf] = 'G' THEN arrCode_RBS[iLauf] := 16;ELSIF strVisuWertRBS.arrText[iLauf] = 'H' THEN arrCode_RBS[iLauf] := 17;ELSIF strVisuWertRBS.arrText[iLauf] = 'I' THEN arrCode_RBS[iLauf] := 18;ELSIF strVisuWertRBS.arrText[iLauf] = 'J' THEN arrCode_RBS[iLauf] := 19;ELSIF strVisuWertRBS.arrText[iLauf] = 'K' THEN arrCode_RBS[iLauf] := 20;ELSIF strVisuWertRBS.arrText[iLauf] = 'L' THEN arrCode_RBS[iLauf] := 21;ELSIF strVisuWertRBS.arrText[iLauf] = 'M' THEN arrCode_RBS[iLauf] := 22;ELSIF strVisuWertRBS.arrText[iLauf] = 'N' THEN arrCode_RBS[iLauf] := 23;ELSIF strVisuWertRBS.arrText[iLauf] = 'O' THEN arrCode_RBS[iLauf] := 24;ELSIF strVisuWertRBS.arrText[iLauf] = 'P' THEN arrCode_RBS[iLauf] := 25;ELSIF strVisuWertRBS.arrText[iLauf] = 'Q' THEN arrCode_RBS[iLauf] := 26;ELSIF strVisuWertRBS.arrText[iLauf] = 'R' THEN arrCode_RBS[iLauf] := 27;ELSIF strVisuWertRBS.arrText[iLauf] = 'S' THEN arrCode_RBS[iLauf] := 28;ELSIF strVisuWertRBS.arrText[iLauf] = 'T' THEN arrCode_RBS[iLauf] := 29;ELSIF strVisuWertRBS.arrText[iLauf] = 'U' THEN arrCode_RBS[iLauf] := 30;ELSIF strVisuWertRBS.arrText[iLauf] = 'V' THEN arrCode_RBS[iLauf] := 31;ELSIF strVisuWertRBS.arrText[iLauf] = 'W' THEN arrCode_RBS[iLauf] := 32;ELSIF strVisuWertRBS.arrText[iLauf] = 'X' THEN arrCode_RBS[iLauf] := 33;ELSIF strVisuWertRBS.arrText[iLauf] = 'Y' THEN arrCode_RBS[iLauf] := 34;ELSIF strVisuWertRBS.arrText[iLauf] = 'Z' THEN arrCode_RBS[iLauf] := 35;ELSIF strVisuWertRBS.arrText[iLauf] = '-' THEN arrCode_RBS[iLauf] := 36;ELSIF strVisuWertRBS.arrText[iLauf] = '.' THEN arrCode_RBS[iLauf] := 37;ELSIF strVisuWertRBS.arrText[iLauf] = ' ' THEN arrCode_RBS[iLauf] := 38;ELSIF strVisuWertRBS.arrText[iLauf] ='$24'THEN arrCode_RBS[iLauf] := 39;ELSIF strVisuWertRBS.arrText[iLauf] = '/' THEN arrCode_RBS[iLauf] := 40;ELSIF strVisuWertRBS.arrText[iLauf] = '+' THEN arrCode_RBS[iLauf] := 41;ELSIF strVisuWertRBS.arrText[iLauf] = '%' THEN arrCode_RBS[iLauf] := 42;END_IF;END_FOR;iCharCode39 := 0; //初始化编码总和FOR i := 1 TO iRBSAnz BY 1 DO //计算RBS位(不含校验位)的编码总和iCharCode39 := iCharCode39 + arrCode_RBS[i];END_FOR;iMOD_39 := iCharCode39 MOD 43 ; //总和模43(Code39校验规则)//检查输入校验位是否与计算值匹配IF arrCode_RBS[iRBSLen] = iMOD_39 AND strVisuWertRBS.arrText[iRBSLen] <> '*' THENxCODE39_IO := True; //校验正常xCODE39_NIO := False;ELSExCODE39_IO := False; //校验异常xCODE39_NIO := True;END_IF;//根据模43结果确定校验位字符CASE iMOD_39 OF0 : chrPZ := '0';1 : chrPZ := '1';2 : chrPZ := '2';3 : chrPZ := '3';4 : chrPZ := '4';5 : chrPZ := '5';6 : chrPZ := '6';7 : chrPZ := '7';8 : chrPZ := '8';9 : chrPZ := '9';10 : chrPZ := 'A';11 : chrPZ := 'B';12 : chrPZ := 'C';13 : chrPZ := 'D';14 : chrPZ := 'E';15 : chrPZ := 'F';16 : chrPZ := 'G';17 : chrPZ := 'H';18 : chrPZ := 'I';19 : chrPZ := 'J';20 : chrPZ := 'K';21 : chrPZ := 'L';22 : chrPZ := 'M';23 : chrPZ := 'N';24 : chrPZ := 'O';25 : chrPZ := 'P';26 : chrPZ := 'Q';27 : chrPZ := 'R';28 : chrPZ := 'S';29 : chrPZ := 'T';30 : chrPZ := 'U';31 : chrPZ := 'V';32 : chrPZ := 'W';33 : chrPZ := 'X';34 : chrPZ := 'Y';35 : chrPZ := 'Z';36 : chrPZ := '-';37 : chrPZ := '.';38 : chrPZ := ' ';39 : chrPZ := '$24';40 : chrPZ := '/';41 : chrPZ := '+';42 : chrPZ := '%';END_CASE;ELSEchrPZ := '*'; //不启用校验位或RBS异常时,校验位无效END_IF;strVisuWertPZ.arrText[1] := chrPZ; //更新可视化校验位(*RBS整体有效性(含校验位)*)xRBS_PZ_IO := xRBS_IO AND (xCODE39_IO OR Cfg.X1); //整体正常=RBS正常且(校验正常或不启用校验)xRBS_PZ_NIO := xRBS_NIO OR (xCODE39_NIO AND NOT Cfg.X1); //整体异常=RBS异常或(校验异常且启用校验)
解读:
- 当启用校验位(`Cfg.X1=0`)且RBS本身正常(`xRBS_IO=1`)时,通过Code39算法计算校验位:
1. 将RBS字符映射为Code39编码(0-42);
2. 计算RBS位(不含校验位)的编码总和,对43取模(`iMOD_39`);
3. 模值对应的字符即为正确校验位(`chrPZ`),与输入校验位比对,设置`xCODE39_IO`(校验正常)。
-`xRBS_PZ_IO`为RBS整体有效性(含校验位),`xRBS_PZ_NIO`为其反值。
10.1
strVisuWertPZ.arrText[1] := chrPZ; //更新可视化校验位
14. 数据块更新(RBS_S数据)
(* 设置ANY指针到RBS_S数据源 *)anyQRBS_S := Data; //源为工作站类型数据p_QRBS_S.DataType := Byte#4; //数据类型:4=WORDp_QRBS_S.DataCount := INT_TO_WORD(iRBSAnz + 1); //长度:RBS位数+1p_QRBS_S.BZ := p_QRBS_S.BZ OR 16#1000000; //调整区域指针(从DB到DI)(* 设置ANY指针到RBS_S数据目标 *)anyZRBS_S := DB_STyp; //目标为工作站类型数据块p_ZRBS_S.DataType := Byte#4; //数据类型:4=WORDp_ZRBS_S.DataCount := INT_TO_WORD(iRBSAnz + 1); //长度:RBS位数+1p_ZRBS_S.BZ := SHL(IN:=pDB_STyp.Anz, N:=3) OR 16#84000000; //计算目标区域指针erg_SFC20 := BLKMOV(SRCBLK := anyQRBS_S ,dstblk := anyZRBS_S); //将RBS_S数据写入目标DB
解读:
- 配置指针将工作站类型数据(`Data`)写入`DB_STyp`(工作站类型数据块),实现数据持久化存储。
将功能块输出Data以下的五个字的数据复制到DB530.Data结构开始的五个字
监控数据:
Data数据等于16#0100,iRBSAnz等于4,p_QRBS_S.BZ数据等于16#85000130,DB_STyp为输入管脚传入的any指针数据,
详细解读:
这段代码的核心功能是通过SCL 的 ANY 指针配置,使用块移动指令(BLKMOV/SFC20)将源数据区域的内容复制到目标数据区域,本质是实现结构化数据的批量传输。结合你提供的具体参数(Data=16#0100、iRBSAnz=4、p_QRBS_S.BZ=16#85000130),我们可以分步骤解析如下:
一、背景知识:ANY 指针与 BLKMOV
在西门子 PLC 编程中:
ANY 指针是一种灵活的数据类型,用于描述 “一段连续数据的位置、类型和长度”,其结构包含:数据类型(DataType)、数据长度(DataCount)、存储区域指针(BZ,即 Bereichszeiger)等。
BLKMOV(SFC20) 是块移动指令,功能是将SRCBLK(源地址)指向的连续数据,复制到DSTBLK(目标地址),复制的长度由 ANY 指针中的DataCount决定。
逐段解析代码逻辑
1. 配置源数据的 ANY 指针(anyQRBS_S)
scl
(* Anypointer auf Quelle RBS_S Daten setzten *)
anyQRBS_S := Data; // 源数据的基础地址指向Data变量
p_QRBS_S.DataType :=Byte#4; // 数据类型为WORD(16位)
p_QRBS_S.DataCount:=INT_TO_WORD(iRBSAnz +1); // 复制的长度:iRBSAnz=4 → 4+1=5个数据
p_QRBS_S.BZ := p_QRBS_S.BZOR16#1000000; // 修正存储区域指针
anyQRBS_S := Data:
Data是 FB 的输出变量(WORD 类型,值为 16#0100),这句的作用是将源 ANY 指针的 “基础地址” 绑定到Data所在的内存位置(即Data的地址作为源数据的起始地址)。
p_QRBS_S.DataType:=Byte#4:
西门子中,DataType是数据类型编码,Byte#4对应WORD 类型(16 位无符号整数)。这表示要复制的数据是 “WORD 类型”。
p_QRBS_S.DataCount:=5:
iRBSAnz=4,因此iRBSAnz +1=5,表示要复制5 个 WORD(总长度 =5×2 字节 =10 字节)。
p_QRBS_S.BZ:=16#84000130OR16#1000000:
得出数据16#85000130:修正为背景 DB 区域
• 区域指针(BZ)的作用:32 位值,最高字节表示存储区域,低 24 位表示地址偏移(以位为单位)。
• 原始p_QRBS_S.BZ=16#84000130:最高字节84表示 “全局 DB”,低 24 位000130表示地址偏移为0x130位。
• 执行OR 16#1000000后,结果为16#85000130:最高字节85表示 “FB 的背景 DB”(84 | 1=85),低 24 位保持000130(地址偏移不变)。
• 最终含义:源数据位于FB 的背景 DB 中,起始地址偏移为0x130位(换算为字节:0x130 ÷ 8= 0x19字节,即背景 DB 的第 25 个字节)。
在西门子 PLC 的块移动逻辑中,Data在这里代表的是 “源数据的起始地址”,而不是 “唯一的数据内容”。具体来说,“复制 5 个WORD” 是从Data的地址开始,连续读取 5 个 WORD 类型的内存单元,Data本身是这 5 个 WORD 中的第一个。
第 1 个 WORD:Data本身(地址DB2390.DBW38,值 = 16#0100)
第 2 个WORD:Data地址 + 2 字节(地址DB2390.DBW40,值 = 未知,取决于后续变量)
第 3 个WORD:Data地址 + 4 字节(地址DB2390.DBW42)
第 4 个WORD:Data地址 + 6 字节(地址DB2390.DBW44)
第 5 个WORD:Data地址 + 8 字节(地址DB2390.DBW46)
2. 配置目标数据的 ANY 指针(anyZRBS_S)
scl
(* Anypointer auf Ziel RBS_S Daten setzten *)
anyZRBS_S := DB_STyp; // 目标地址绑定到输入的DB_STyp(ANY指针)
p_ZRBS_S.DataType :=Byte#4; // 数据类型与源一致:WORD
p_ZRBS_S.DataCount:=INT_TO_WORD(iRBSAnz +1); // 复制长度与源一致:5个WORD
p_ZRBS_S.BZ :=SHL(IN:=pDB_STyp.Anz, N:=3) OR16#84000000; // 计算目标区域指针
anyZRBS_S := DB_STyp:
DB_STyp是 FB 的输入变量(ANY 类型),表示目标数据所在的数据库(如某个全局 DB),这句将目标 ANY 指针绑定到DB_STyp指向的数据库。
p_ZRBS_S.DataType:=Byte#4:
与源数据类型保持一致(WORD),确保数据格式匹配。
p_ZRBS_S.DataCount:=5:
与源数据长度一致(5 个 WORD),确保复制的数据量相同。
p_ZRBS_S.BZ的计算:
16#84000000是西门子存储区域编码,表示 “全局数据块(Global DB)”;
SHL(IN:=pDB_STyp.Anz, N:=3):pDB_STyp.Anz是DB_STyp中定义的 “数据长度”(WORD 类型),左移 3 位等价于 “乘以 8”(将字节地址转换为位地址偏移,西门子中地址以位为最小单位);
最终BZ的含义:目标数据位于全局 DB 中,起始地址偏移为pDB_STyp.Anz × 8。
目标地址:
第 1 个 WORD:地址DB530.DBW576)
第 2 个WORD:地址DB530.DBW578)
第 3 个WORD:地址DB530.DBW580)
第 4 个WORD:地址DB530.DBW582)
第 5 个WORD:地址DB530.DBW584)
3. 执行数据复制(BLKMOV)
scl
erg_SFC20 := BLKMOV(SRCBLK := anyQRBS_S ,dstblk := anyZRBS_S);
功能:调用块移动指令,将anyQRBS_S指向的源数据(5 个 WORD)复制到anyZRBS_S指向的目标地址。
具体传输内容:
源数据以Data(16#0100)为起始,连续 5 个 WORD(假设后续 4 个 WORD 的值为Data+1、Data+2、Data+3、Data+4),最终复制到DB_STyp指定的全局 DB 中。
erg_SFC20:返回值,0表示复制成功,非 0 表示失败(如地址无效、长度不匹配等)。
我找到一个博途的vass06程序,通过博途监控程序可以详细看出此时传输的是地址指针
1034
