前几天我们对大众VASS标准:FB_Sick_RFU(FB520_RFID数据读取)功能块进行了深度解读,读出来的数据需要使用FB_Pruefziffer(FB170)对数据进行校验是否正确。
大众VASS标准:FB_Sick_RFU(FB520_RFID数据读取)功能块深度解读
FB_Pruefziffer(FB170)是西门子 SCL 编写的校验位功能块,支持 Code 2/5、Code 39 和 CRC16 三种校验算法。通过配置字_Cfg 选择校验方式及模式,可实现校验位计算、输入校验位验证,或仅验证数据有效性。
功能块接收待校验数据指针、输入校验位、数据起始地址与长度等参数,经算法处理后输出计算的校验位、校验结果(通过 / 不通过)及选中的校验方式。包含可视化交互逻辑,可显示数据、校验位及状态,并通过消息系统报告故障(如数据长度为 0、无效数据等),支持链式故障传递。
功能块:
HMI界面:
功能块程序结构大纲:
1. **功能块基本信息**
- 名称、版本、用途(校验位计算与校验)、适用标准(VASS)。
2. **变量声明**
- 输入变量:控制信号(Start)、配置(_Cfg)、数据参数(Pruefdaten等)。
- 输出变量:校验结果(Pruef_IO)、计算的校验位(PruefZiff_Out)、状态指示(Anwahl_*)。
- 输入输出变量:消息缓冲区(ST_Meld)。
- 临时变量:数据处理(Buffer)、校验计算(iCheckSum2of5等)、可视化(strVisutext_*)。
3. **核心逻辑**
- 配置解析:_Cfg位映射为校验方式。
- 输入控制:可视化按键检测与无过程模式切换。
- 初始化:可视化文本与校验结果清空。
- 校验处理:
- Code 2/5:数据校验→加权求和→模10计算→对比。
- Code 39:数据校验→求和→模43计算→对比。
- CRC16:查表法计算→高低位拆分→对比。
- 结果输出:校验通过/不通过(Pruef_IO/NIO)、无效数据指示。
4. **辅助功能**
- 故障处理:本地故障与链式故障汇总。
- 消息系统:故障信息发送至消息缓冲区。
- 可视化:文本显示与按钮/指示灯状态控制。
下面是对FB_Pruefziffer功能块的逐行详细解读,包含代码和对应的解释:
(******************************************************************************************* **** Copyright ?2011 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 **------------------------------------------------------------------------------------------24.02.17 3.0.00 Schulz Uebernahme in VASS_Standard*****************************************************************************************)// 定义功能块FB_Pruefziffer,编号为170,用于校验位计算与验证FUNCTION_BLOCK FB_Pruefziffer //FB 170TITLE = 'Version 3.0.00' // 功能块标题,显示版本信息VERSION : '3.0' // 功能块版本号AUTHOR : VASS_V05 // 作者信息NAME : PRUEFZIF // 功能块名称FAMILY : PRUEFZIF // 功能块所属家族// 输入变量声明区VAR_INPUTStart : BOOL; // Pruefziffern Berechnung durchfuehren// 启动信号:触发校验位计算Frg_Start : BOOL; // Freigabe Vorwahl Start auf VISU// 可视化界面启动许可:允许从可视化界面启动校验Frg_oProz : BOOL; // Freigabe Vorwahl ohne Prozess// 无过程模式许可:允许切换到无过程模式Pruefdaten : ANY; // Pruefdaten Pointer// 校验数据:指向待校验数据的指针PruefZiff1_In : BYTE; // Eingabe zu pruefende Pruefziffer 1 (Hoeheres Byte)// 输入校验位1:待验证的高位校验字节PruefZiff2_In : BYTE; // Eingabe zu pruefende Pruefziffer 2 (niedrigeres Byte)// 输入校验位2:待验证的低位校验字节DatenAnfang : INT; // Startadresse// 数据起始地址:校验数据的起始位置DatenLaenge : INT; // Anzahl zu pruefender Daten// 数据长度:待校验数据的字节数_Cfg : WORD; //x0: C2/5 x1: C39 x2: nur Pruefziffer x3: CRC16 x4: CRC16 nur Pruefziffer// 配置字:用于选择校验算法和工作模式(**SIEMENS********************Anfang Variablendeklaration*************************************)(***********fuer bit-, byte-, wordgranulare Sicht von Variablen mit dem AT-Befehl**************)// 使用AT关键字将配置字_Cfg映射为结构体,便于按位访问Cfg AT _Cfg: STRUCT // WORD -> BOOLX8 : BOOL; // 配置位8X9 : BOOL; // 配置位9X10 : BOOL; // 配置位10X11 : BOOL; // 配置位11X12 : BOOL; // 配置位12X13 : BOOL; // 配置位13X14 : BOOL; // 配置位14X15 : BOOL; // 配置位15X0 : BOOL; //Code 2/5 Modulo10// 配置位0:启用Code 2/5(模10)校验X1 : BOOL; //Code 39 Modulo43// 配置位1:启用Code 39(模43)校验X2 : BOOL; //fuer Code 2/5 und Code 39 0:kontrollieren und berechnete Pruefziffer ausgeben,//1: nur kontrollieren ob gueltige Pruefdaten vorliegen und berechnete Pruefziffer ausgeben// 配置位2:对于Code 2/5和Code 39,0=验证并输出计算的校验位,1=仅验证数据有效性并输出校验位X3 : BOOL; //Code CRC16 Genibus (Ausgabe 2x8Bit)kontrollieren und berechnete Pruefziffer ausgeben// 配置位3:启用CRC16 Genibus校验(输出2个8位字节)X4 : BOOL; //fuer Code CRC16 0:kontrollieren und berechnete Pruefziffer ausgeben,1: nur berechnete Pruefziffer ausgeben// 配置位4:对于CRC16,0=验证并输出计算的校验位,1=仅输出计算的校验位X5 : BOOL; // 配置位5X6 : BOOL; // 配置位6X7 : BOOL; // 配置位7END_STRUCT;VkStoe_In : BOOL; // Sammelstoerung verkettet mit VkStoe_Out// 链式故障输入:与链式故障输出级联(**SIEMENS**********************Ende Variablendeklaration*************************************)(***********fuer bit-, byte-, wordgranulare Sicht von Variablen mit dem AT-Befehl**************)END_VAR// 输出变量声明区VAR_OUTPUTPruefZiff1_Out : BYTE; // berechnete Pruefziffer1 ausgeben (Hoeheres Byte)// 输出校验位1:计算得到的高位校验字节PruefZiff2_Out : BYTE; // berechnete Pruefziffer2 ausgeben (niedrigeres Byte)// 输出校验位2:计算得到的低位校验字节oProz : BOOL; // Vorwahl ohne Prozess/Ohne Berechnung// 无过程模式:预选无过程/无计算模式Pruef_IO : BOOL; // Pruefziffer PruefZiff_In passt zu Pruefdaten// 校验通过:输入校验位与校验数据匹配Pruef_NIO : BOOL; // Pruefziffer PruefZiff_In passt nicht zu Pruefdaten// 校验不通过:输入校验位与校验数据不匹配Anwahl_Pruef_Code2_5: BOOL; // Pruefung Code 2/5 Modulo10 parametriert// Code 2/5选中:已配置Code 2/5模10校验Anwahl_Pruef_C39 : BOOL; // Pruefung Code 39 Modulo43 parametriert// Code 39选中:已配置Code 39模43校验Anwahl_Pruef_CRC16 : BOOL; // Pruefung Code CRC16 Genibus parametriert// CRC16选中:已配置CRC16 Genibus校验Pruef_Auswahl_IO : BOOL; // (Nur) eine Pruefung ausgewaehlt// 校验选择有效:(仅)选中一种校验方式Invalide_Pruefdaten : BOOL; // Pruefdaten enthalten ungueltige Werte-->Pruefziffer nicht berechenbar// 无效校验数据:校验数据包含无效值,无法计算校验位Stoexx : BOOL; // Sammelstoerung// 汇总故障:本地故障信号VkStoe_Out : BOOL; // Verkettete Stoerung// 链式故障输出:级联后的故障信号END_VAR// 输入输出变量声明区(可读写)VAR_IN_OUTST_Meld : Meldungspuffer; // Meldestruktur// 消息缓冲区:用于存储和传递消息结构END_VAR(**SIEMENS****************************************************************************)// 临时变量声明区(仅在功能块内部使用,不保留状态)VAR_Temperg_SFC20 :INT;// Rueckgabewert SFC20// SFC20返回值:块移动指令的返回值_pMeldFeld :ANY; // Hilfsvariable// 消息字段指针:辅助变量pMeldFeld AT _pMeldFeld: STRUCTBYTE0 :BYTE; // Byte 0TYP :BYTE; // Byte 1 Daten/ParametertypANZ :WORD; // Byte 2+3 Laenge der VariablenDBNR :WORD; // Byte 4+5 DB-NummerBZ :DWORD; // Byte 6 bis 10 BereichszeigerEND_STRUCT;// 使用AT关键字将_pMeldFeld映射为结构体,便于访问消息字段的各个部分_pMeldAbb :ANY; // Hilfsvariable// 消息确认指针:辅助变量pMeldAbb AT _pMeldAbb: STRUCTBYTE0 :BYTE; // Byte 0TYP :BYTE; // Byte 1 Daten/ParametertypANZ :WORD; // Byte 2+3 Laenge der VariablenDBNR :WORD; // Byte 4+5 DB-NummerBZ :DWORD; // Byte 6 bis 10 BereichszeigerEND_STRUCT;// 使用AT关键字将_pMeldAbb映射为结构体,便于访问消息确认的各个部分_pMeld :ANY; // Hilfsvariable// 消息指针:辅助变量pMeld AT _pMeld: STRUCTBYTE0 :BYTE; // Byte 0TYP :BYTE; // Byte 1 Daten/ParametertypANZ :WORD; // Byte 2+3 Laenge der VariablenDBNR :WORD; // Byte 4+5 DB-NummerBZ :DWORD; // Byte 6 bis 10 BereichszeigerEND_STRUCT;// 使用AT关键字将_pMeld映射为结构体,便于访问消息的各个部分DATA_IN_T : ANY; //Kopie von DATA_IN// 数据输入副本:DATA_IN的副本p_DATA_IN AT DATA_IN_T: STRUCTSyntaxId : BYTE; //Byte 0DataType : BYTE; //Byte 1 Daten/ParametertypDataCount : WORD; //Byte 2+3 Laenge der VariablenDBNR : WORD; //Byte 4+5 DB-NummerBZ : DWORD; //Byte 6 bis 10 BereichszeigerEND_STRUCT;// 使用AT关键字将DATA_IN_T映射为结构体,解析数据输入的信息END_VAR(************************************************************************************)// 变量声明区(保留状态)VAR_dwVisuWerte1 : DWORD; // Statusdoppelword 1 an VISU// 可视化状态双字1:发送到可视化界面的状态信息strVisutext_1_32 : ARRAY [1..34] OF BYTE ;//STRING Visu Pruefdaten Zeichen 1 bis 32// 可视化文本1-32:可视化界面显示的校验数据字符1到32strVisutext_33_64 : ARRAY [1..34] OF BYTE ;//STRING Visu Pruefdaten Zeichen 33 bis 64// 可视化文本33-64:可视化界面显示的校验数据字符33到64strVisutext_Ziffer : ARRAY [1..4] OF BYTE ;//STRING Visu Pruefziffern// 可视化校验位文本:可视化界面显示的校验位_Visutext_Ziffer_Hex : WORD; //strVisutext_Ziffer als Hex// 可视化校验位十六进制:校验位的十六进制表示bVisuTasten : BYTE; // Softkeys von VISU// 可视化按键:来自可视化界面的软键输入(**SIEMENS************************************************************************************)(*****************************Anfang Variablendeklaration*************************************)(*********************************fuers Meldesystem********************************************)(*********************************************************************************************)MeldFeld : STRUCTb0 : Byte;b1 : Byte;b2 : Byte;b3 : Byte;END_STRUCT;// 消息字段:存储消息相关信息MSYS AT MeldFeld: STRUCTxF_1 : BOOL;xF_2 : BOOL;xF_3 : BOOL;xF_4 : BOOL;xF_5 : BOOL;xF_6 : BOOL;xF_7 : BOOL;xF_8 : BOOL;xF_9 : BOOL;xF_10 : BOOL;xF_11 : BOOL;xF_12 : BOOL;xF_13 : BOOL;xF_14 : BOOL;xF_15 : BOOL;xF_16 : BOOL;xF_17 : BOOL;xF_18 : BOOL;xF_19 : BOOL;xF_20 : BOOL;xF_21 : BOOL;xF_22 : BOOL;xF_23 : BOOL;xF_24 : BOOL;xF_25 : BOOL;xF_26 : BOOL;xF_27 : BOOL;xF_28 : BOOL;xF_29 : BOOL;xF_30 : BOOL;xF_31 : BOOL;xF_32 : BOOL;END_STRUCT;// 使用AT关键字将MeldFeld映射为结构体,每个位表示一种故障状态MeldAbb : STRUCTb0 : Byte;b1 : Byte;b2 : Byte;b3 : Byte;END_STRUCT;// 消息确认:存储消息确认相关信息AenderungsID : STRUCTSNr : WORD;ANr : BYTE;Detail : BYTE;END_STRUCT;// 变更ID:用于标识消息的变更信息Integritaet : BOOL;// 完整性:消息完整性标志(**SIEMENS************************************************************************************)(*****************************Ende Variablendeklaration***************************************)(*********************************fuers Meldesystem********************************************)(*********************************************************************************************)(**SIEMENS********************Anfang Variablendeklaration*************************************)(***********fuer bit-, byte-, wordgranulare Sicht von Variablen mit dem AT-Befehl**************)// 使用AT关键字将_dwVisuWerte1映射为结构体,便于访问可视化状态的各个位dwVisuWerte1 AT _dwVisuWerte1: STRUCT // DWORD -> BOOLB3 : BYTE ;//VISU Button Start// 可视化按钮Start:控制Start按钮的显示B2 : BYTE ;//VISU Button Ohne// 可视化按钮Ohne:控制Ohne按钮的显示X8 : BOOL ;//X9 : BOOL ;//X10 : BOOL ;//X11 : BOOL ;//X12 : BOOL ;//X13 : BOOL ;//X14 : BOOL ;//X15 : BOOL ;//X0 : BOOL ;//X1 : BOOL ;//X2 : BOOL ;//X3 : BOOL ;//X4 : BOOL ;//X5 : BOOL ;//X6 : BOOL ;//X7 : BOOL ;//END_STRUCT;// 使用AT关键字将_Visutext_Ziffer_Hex映射为结构体,拆分为两个字节Visutext_Ziffer_Hex AT _Visutext_Ziffer_Hex: STRUCT //strVisutext_Ziffer als HexB1 : BYTE;B2 : BYTE;END_STRUCT;(**SIEMENS**********************Ende Variablendeklaration*************************************)(***********fuer bit-, byte-, wordgranulare Sicht von Variablen mit dem AT-Befehl**************)xCfg_0 : BOOL; // 配置位0的副本xCfg_1 : BOOL; // 配置位1的副本xCfg_2 : BOOL; // 配置位2的副本xCfg_3 : BOOL; // 配置位3的副本xCfg_4 : BOOL; // 配置位4的副本xCfg_5 : BOOL; // 配置位5的副本xCfg_6 : BOOL; // 配置位6的副本xCfg_7 : BOOL; // 配置位7的副本xCfg_8 : BOOL; // 配置位8的副本iHM_Zaehler1 : INT; //Laufvariable// 循环变量1:用于循环计数iHM_Zaehler2 : INT; //Laufvariable// 循环变量2:用于循环计数iLaenge : INT; //Codelaenge// 代码长度:存储代码长度信息Buffer : ARRAY [0..68] OF BYTE;//Buffer + Pruefziffer// 缓冲区:存储数据和校验位arrCode_pos : ARRAY [0..68] OF INT; //Codedatensatz + Pruefziffer// 代码位置数组:存储转换后的代码数据和校验位iCheckSum2of5 : INT; //Checksumme Code 2of5// Code 2/5校验和:用于Code 2/5算法iMOD_39 : INT; //Modulofunktion Code 39// Code 39模运算结果:用于Code 39算法iCharCode39 : INT; //CharCode39// Code 39字符代码:用于Code 39算法xF_Invalide_Daten_C2x5 : BOOL; //Fehler Falsche Daten// Code 2/5无效数据:标记Code 2/5的无效数据xF_Invalide_Daten_C39 : BOOL; //Fehler Falsche Daten// Code 39无效数据:标记Code 39的无效数据xF_Invalide_Daten_CRC16 : BOOL; //Fehler Falsche Daten// CRC16无效数据:标记CRC16的无效数据xF_PruefdatenKopie : BOOL; //Pruefdaten nicht einlesbar// 校验数据复制错误:标记校验数据无法读取Pruefende : INT; //Letztes Zeichen, das geprueft werden soll// 校验结束位置:需要校验的最后一个字符位置iPaFe_Pruefdaten : INT; //parametrierfehler beim Kopieren der Pruefdaten// 校验数据复制参数错误:复制校验数据时的参数错误iFM : BOOL; //FM// 功能标志:用于标记某些功能状态xS_Start : BOOL; //Visu Tasten Lesen// Start信号:读取可视化按钮的Start信号xS_OProz : BOOL; //Visu Tasten Ohne Prozess// 无过程信号:读取可视化按钮的无过程信号R_TRIG_oProz : STRUCT //Positive Flanke ohne Prozess// 无过程上升沿触发器:检测无过程信号的上升沿Edge : BOOL; // 边沿:存储上一周期的状态Q : BOOL; // 输出:上升沿检测输出END_STRUCT;R_TRIG_Start : STRUCT //Positive Flanke Start// Start上升沿触发器:检测Start信号的上升沿Edge : BOOL; // 边沿:存储上一周期的状态Q : BOOL; // 输出:上升沿检测输出END_STRUCT;chrPZ : CHAR; //Berechnete Pruefziffer// 校验位字符:计算得到的校验位字符iDatenLaenge_max32 : INT; //Datenlaenge auf maximal 32 gesetzt, wenn > 32// 最大32的数据长度:当数据长度>32时设为32// CRC16查找表1:用于CRC16算法计算CRCTable1 : ARRAY [0..127] OF WORD :=16#0000,16#1021,16#2042,16#3063,16#4084,16#50a5,16#60c6,16#70e7,16#8108,16#9129,16#a14a,16#b16b,16#c18c,16#d1ad,16#e1ce,16#f1ef,16#1231,16#0210,16#3273,16#2252,16#52b5,16#4294,16#72f7,16#62d6,16#9339,16#8318,16#b37b,16#a35a,16#d3bd,16#c39c,16#f3ff,16#e3de,16#2462,16#3443,16#0420,16#1401,16#64e6,16#74c7,16#44a4,16#5485,16#a56a,16#b54b,16#8528,16#9509,16#e5ee,16#f5cf,16#c5ac,16#d58d,16#3653,16#2672,16#1611,16#0630,16#76d7,16#66f6,16#5695,16#46b4,16#b75b,16#a77a,16#9719,16#8738,16#f7df,16#e7fe,16#d79d,16#c7bc,16#48c4,16#58e5,16#6886,16#78a7,16#0840,16#1861,16#2802,16#3823,16#c9cc,16#d9ed,16#e98e,16#f9af,16#8948,16#9969,16#a90a,16#b92b,16#5af5,16#4ad4,16#7ab7,16#6a96,16#1a71,16#0a50,16#3a33,16#2a12,16#dbfd,16#cbdc,16#fbbf,16#eb9e,16#9b79,16#8b58,16#bb3b,16#ab1a,16#6ca6,16#7c87,16#4ce4,16#5cc5,16#2c22,16#3c03,16#0c60,16#1c41,16#edae,16#fd8f,16#cdec,16#ddcd,16#ad2a,16#bd0b,16#8d68,16#9d49,16#7e97,16#6eb6,16#5ed5,16#4ef4,16#3e13,16#2e32,16#1e51,16#0e70,16#ff9f,16#efbe,16#dfdd,16#cffc,16#bf1b,16#af3a,16#9f59,16#8f78;// CRC16查找表2:用于CRC16算法计算CRCTable2 : ARRAY [0..127] OF WORD :=16#9188,16#81a9,16#b1ca,16#a1eb,16#d10c,16#c12d,16#f14e,16#e16f,16#1080,16#00a1,16#30c2,16#20e3,16#5004,16#4025,16#7046,16#6067,16#83b9,16#9398,16#a3fb,16#b3da,16#c33d,16#d31c,16#e37f,16#f35e,16#02b1,16#1290,16#22f3,16#32d2,16#4235,16#5214,16#6277,16#7256,16#b5ea,16#a5cb,16#95a8,16#8589,16#f56e,16#e54f,16#d52c,16#c50d,16#34e2,16#24c3,16#14a0,16#0481,16#7466,16#6447,16#5424,16#4405,16#a7db,16#b7fa,16#8799,16#97b8,16#e75f,16#f77e,16#c71d,16#d73c,16#26d3,16#36f2,16#0691,16#16b0,16#6657,16#7676,16#4615,16#5634,16#d94c,16#c96d,16#f90e,16#e92f,16#99c8,16#89e9,16#b98a,16#a9ab,16#5844,16#4865,16#7806,16#6827,16#18c0,16#08e1,16#3882,16#28a3,16#cb7d,16#db5c,16#eb3f,16#fb1e,16#8bf9,16#9bd8,16#abbb,16#bb9a,16#4a75,16#5a54,16#6a37,16#7a16,16#0af1,16#1ad0,16#2ab3,16#3a92,16#fd2e,16#ed0f,16#dd6c,16#cd4d,16#bdaa,16#ad8b,16#9de8,16#8dc9,16#7c26,16#6c07,16#5c64,16#4c45,16#3ca2,16#2c83,16#1ce0,16#0cc1,16#ef1f,16#ff3e,16#cf5d,16#df7c,16#af9b,16#bfba,16#8fd9,16#9ff8,16#6e17,16#7e36,16#4e55,16#5e74,16#2e93,16#3eb2,16#0ed1,16#1ef0;EndAddr : DWORD; // 结束地址:存储数据结束地址iCRCIndex : INT; // Calculated CRC index into CRC lookup tables// CRC索引:计算得到的CRC查找表索引wCRCTemp : WORD; // CRC临时变量:用于CRC计算的临时变量_wCRC : WORD; // CRC结果:存储最终的CRC结果// 使用AT关键字将_wCRC映射为结构体,拆分为两个字节wCRC AT _wCRC : STRUCTB1 : BYTE; // 字节1:CRC结果的高位字节B2 : BYTE; // 字节2:CRC结果的低位字节END_STRUCT;END_VAR(*----------------------------------------------------------------------------------*)(*Dieser Baustein berechnet Pruefn anhand der Eingabedaten. Die Auswahl des Pruefverfahrenswird ueber cfg. Bits eingestellt*)(*此功能块根据输入数据计算校验位。校验方法的选择通过配置位设置*)(*----------------------------------------------------------------------------------*)(*Konfiguration auswerten*)(*解析配置*)xCfg_0 := Cfg.X0; // 配置位0:Code 2/5使能xCfg_1 := Cfg.X1; // 配置位1:Code 39使能xCfg_2 := Cfg.X2; // 配置位2:校验位验证模式xCfg_3 := Cfg.X3; // 配置位3:CRC16使能xCfg_4 := Cfg.X4; // 配置位4:CRC16验证模式xCfg_5 := Cfg.X5; // 配置位5xCfg_6 := Cfg.X6; // 配置位6xCfg_7 := Cfg.X7; // 配置位7xCfg_8 := Cfg.X8; // 配置位8(*----------------------------------------------------------------------------------*)(* Tasten von Visu pruefen *)(*检查来自可视化界面的按键*)// 如果PC未激活,则将可视化按键设为0IF PC_AKTIV=DWORD#16#00000000 THEN bVisuTasten := Byte#0;END_IF;// 定义Start信号:当可视化按键为1,且启动许可有效,且不在无过程模式xS_Start:=(bVisutasten = Byte#1) AND Frg_Start AND NOT oProz;// 定义无过程信号:当可视化按键为2,且无过程许可有效xS_oProz:=(bVisutasten = Byte#2) AND Frg_oProz;(* Pruefung starten *)(*启动校验*)// 检测Start信号的上升沿R_TRIG_Start.Q := xS_Start AND NOT R_TRIG_Start.Edge;R_TRIG_Start.Edge := xS_Start;(* An-/Abwahl ohne Prozess *)(*切换无过程模式*)// 检测无过程信号的上升沿R_TRIG_oProz.Q := xS_OProz AND NOT R_TRIG_oProz.Edge;R_TRIG_oProz.Edge := xS_OProz;// 当检测到无过程信号的上升沿且无过程许可有效时,切换无过程模式状态IF R_TRIG_oProz.Q AND Frg_OProz THENoProz := NOT oProz;END_IF;// 暂时注释掉的代码:将输入校验位直接输出//PruefZiff1_Out := PruefZiff1_In;//PruefZiff2_Out := PruefZiff2_In;// 输出选中的校验方式Anwahl_Pruef_Code2_5 := xCfg_0; // Code 2/5选中标志Anwahl_Pruef_C39 := xCfg_1; // Code 39选中标志Anwahl_Pruef_CRC16 := xCfg_3; // CRC16选中标志// 检查是否只选择了一种校验方式(通过异或运算)Pruef_Auswahl_IO := (xCfg_0 XOR xCfg_1 XOR xCfg_3);// 初始化Buffer[0] := 66; // 缓冲区初始化// 设置可视化文本的最大长度strVisutext_1_32[1] := 32; // 前32个字符的最大长度strVisutext_33_64[1] := 32; // 33-64个字符的最大长度strVisutext_Ziffer[1] := 2; // 校验位的最大长度// 当没有Start按钮按下且没有Start信号时,清空可视化文本和校验结果IF NOT xS_Start AND NOT Start THENstrVisutext_1_32[2] := 0; // 前32个字符的实际长度设为0strVisutext_33_64[2] := 0; // 33-64个字符的实际长度设为0strVisutext_Ziffer[2] := 0; // 校验位的实际长度设为0Pruef_IO := FALSE; // 校验通过标志设为FALSEPruef_NIO := FALSE; // 校验不通过标志设为FALSExF_Invalide_Daten_C2x5 := FALSE; // Code 2/5无效数据标志设为FALSExF_Invalide_Daten_C39 := FALSE; // Code 39无效数据标志设为FALSE_Visutext_Ziffer_Hex := 0; // 校验位的十六进制表示设为0END_IF;// 如果处于无过程模式,则直接设置校验通过IF oProz THENPruef_IO := TRUE;// 如果数据长度大于0,且有Start上升沿或Start信号,且不在无过程模式,且校验方式选择有效ELSIF DatenLaenge > 0 AND (R_TRIG_Start.Q OR Start) AND NOT oProz AND Pruef_Auswahl_IO THEN// 初始化可视化校验位文本strVisutext_Ziffer[3] := 20; // 空格strVisutext_Ziffer[4] := 20; // 空格Pruef_IO := FALSE; // 校验通过标志设为FALSEPruef_NIO := FALSE; // 校验不通过标志设为FALSE// 读取校验数据到缓冲区Byte_String(Start := DatenAnfang,Ende := ( DatenAnfang + DatenLaenge - 1 ),DATA_IN := Pruefdaten ,DATA_OUT := Buffer,PaFE := iPaFe_Pruefdaten,FM := iFM);// 如果复制过程有参数错误,则设置校验数据复制错误标志xF_PruefdatenKopie := iPaFe_Pruefdaten > 0;// 将输入的校验位添加到缓冲区Buffer[2 + DatenLaenge] := PruefZiff1_In;Buffer[2 + DatenLaenge + 1] := PruefZiff2_In;// 设置可视化校验位文本的长度strVisutext_Ziffer[2] := 1; // 实际长度设为1// strVisutext_Ziffer[3] := Buffer[2 + DatenLaenge];// 初始化可视化文本的实际长度strVisutext_1_32[2] := 0;strVisutext_33_64[2] := 0;// 处理前32个字符的可视化文本IF DatenLaenge > 0 AND DatenLaenge < 65 THEN// 如果数据长度大于32,则最大显示32个字符IF DatenLaenge > 32 THENiDatenLaenge_max32 := 32;ELSEiDatenLaenge_max32 := DatenLaenge;END_IF;// 复制数据到可视化文本缓冲区Byte_String(Start := DatenAnfang,Ende := ( DatenAnfang + iDatenLaenge_max32 - 1),DATA_IN := Pruefdaten ,DATA_OUT := strVisutext_1_32,PaFE := iPaFe_Pruefdaten,FM := iFM);// 如果复制过程有参数错误,则设置校验数据复制错误标志xF_PruefdatenKopie := xF_PruefdatenKopie OR iPaFe_Pruefdaten > 0;END_IF;// 处理33-64个字符的可视化文本IF DatenLaenge > 32 AND DatenLaenge < 65 THEN// 复制数据到可视化文本缓冲区Byte_String(Start := DatenAnfang + 32,Ende := ( DatenAnfang + DatenLaenge - 1),DATA_IN := Pruefdaten ,DATA_OUT := strVisutext_33_64,PaFE := iPaFe_Pruefdaten,FM := iFM);// 如果复制过程有参数错误,则设置校验数据复制错误标志xF_PruefdatenKopie := xF_PruefdatenKopie OR iPaFe_Pruefdaten > 0;ELSEstrVisutext_33_64[2] := 0; // 实际长度设为0END_IF;// 根据配置选择校验方法IF xCfg_0 THEN // Code 2/5校验strVisutext_Ziffer[3] := Buffer[2 + DatenLaenge];// 初始化Code 2/5校验相关变量xF_Invalide_Daten_C2x5 := FALSE;iCheckSum2of5 := 0;// 处理校验数据(不包括校验位)FOR iHM_Zaehler2 := 2 TO (2 + DatenLaenge - 1) DO(* 将CODE128字符集中的A-Z转换为数字以便计算校验和 *)CASE BYTE_TO_INT(Buffer[iHM_Zaehler2]) OF48: arrCode_pos[iHM_Zaehler2] := 0 ;// '0'49: arrCode_pos[iHM_Zaehler2] := 1 ;// '1'50: arrCode_pos[iHM_Zaehler2] := 2 ;// '2'51: arrCode_pos[iHM_Zaehler2] := 3 ;// '3'52: arrCode_pos[iHM_Zaehler2] := 4 ;// '4'53: arrCode_pos[iHM_Zaehler2] := 5 ;// '5'54: arrCode_pos[iHM_Zaehler2] := 6 ;// '6'55: arrCode_pos[iHM_Zaehler2] := 7 ;// '7'56: arrCode_pos[iHM_Zaehler2] := 8 ;// '8'57: arrCode_pos[iHM_Zaehler2] := 9 ;// '9'65: arrCode_pos[iHM_Zaehler2] := 1 ;// 'A'66: arrCode_pos[iHM_Zaehler2] := 2 ;// 'B'67: arrCode_pos[iHM_Zaehler2] := 3 ;// 'C'68: arrCode_pos[iHM_Zaehler2] := 4 ;// 'D'69: arrCode_pos[iHM_Zaehler2] := 5 ;// 'E'70: arrCode_pos[iHM_Zaehler2] := 6 ;// 'F'71: arrCode_pos[iHM_Zaehler2] := 7 ;// 'G'72: arrCode_pos[iHM_Zaehler2] := 8 ;// 'H'73: arrCode_pos[iHM_Zaehler2] := 9 ;// 'I'74: arrCode_pos[iHM_Zaehler2] := 1 ;// 'J'75: arrCode_pos[iHM_Zaehler2] := 2 ;// 'K'76: arrCode_pos[iHM_Zaehler2] := 3 ;// 'L'77: arrCode_pos[iHM_Zaehler2] := 4 ;// 'M'78: arrCode_pos[iHM_Zaehler2] := 5 ;// 'N'79: arrCode_pos[iHM_Zaehler2] := 6 ;// 'O'80: arrCode_pos[iHM_Zaehler2] := 7 ;// 'P'81: arrCode_pos[iHM_Zaehler2] := 8 ;// 'Q'82: arrCode_pos[iHM_Zaehler2] := 9 ;// 'R'83: arrCode_pos[iHM_Zaehler2] := 1 ;// 'S'84: arrCode_pos[iHM_Zaehler2] := 2 ;// 'T'85: arrCode_pos[iHM_Zaehler2] := 3 ;// 'U'86: arrCode_pos[iHM_Zaehler2] := 4 ;// 'V'87: arrCode_pos[iHM_Zaehler2] := 5 ;// 'W'88: arrCode_pos[iHM_Zaehler2] := 6 ;// 'X'89: arrCode_pos[iHM_Zaehler2] := 7 ;// 'Y'90: arrCode_pos[iHM_Zaehler2] := 8 ;// 'Z'ELSE: (* 如果找到不匹配的字符,则设置无效数据标志并退出循环 *)xF_Invalide_Daten_C2x5 := TRUE;Pruef_IO := FALSE;EXIT;END_CASE;(* 计算校验和 *)// +1是为了进行奇偶位的判断IF ((iHM_Zaehler2 + 1) MOD 2) = 0 THENiCheckSum2of5 := iCheckSum2of5 + 1 * arrCode_pos[iHM_Zaehler2];// 偶数位乘1ELSEiCheckSum2of5 := iCheckSum2of5 + 3 * arrCode_pos[iHM_Zaehler2];// 奇数位乘3END_IF;END_FOR;(* 从总和计算模10,10减去该值得到校验位 *)IF (iCheckSum2of5 MOD 10) > 0 THENiCheckSum2of5 := 10 - (iCheckSum2of5 MOD 10);ELSEiCheckSum2of5 := 0;END_IF;// 如果数据有效,则计算校验位IF NOT xF_Invalide_Daten_C2x5 THEN// 将校验位转换为字符CASE iCheckSum2of5 OF0: chrPZ := '0' ;// '0'1: chrPZ := '1' ;// '1'2: chrPZ := '2' ;// '2'3: chrPZ := '3' ;// '3'4: chrPZ := '4' ;// '4'5: chrPZ := '5' ;// '5'6: chrPZ := '6' ;// '6'7: chrPZ := '7' ;// '7'8: chrPZ := '8' ;// '8'9: chrPZ := '9' ;// '9'END_CASE;(************************************************************检查输入值,如果功能块外部的PruefZiff_OUT与PruefZiff_IN指向相同的存储位置,则存储计算得到的校验位。*)// 将字符转换为字节存储到输出校验位1PruefZiff1_Out := INT_TO_BYTE(CHAR_TO_INT(chrPZ));PruefZiff2_Out := 0; // 输出校验位2设为0// 如果不是仅验证数据有效性模式IF NOT xCfg_2 THEN// 将计算得到的校验位与输入校验位比较Pruef_IO := PruefZiff1_Out = PruefZiff1_In;ELSE // 仅验证数据有效性,不验证校验位strVisutext_Ziffer[3] := PruefZiff1_Out;Pruef_IO := TRUE;END_IF;END_IF;ELSIF xCfg_1 THEN // Code 39校验strVisutext_Ziffer[3] := Buffer[2 + DatenLaenge];// 初始化Code 39校验相关变量xF_Invalide_Daten_C39 := FALSE;iCharCode39 := 0;// 处理校验数据(不包括校验位)FOR iHM_Zaehler2 := 2 TO (2 + DatenLaenge - 1) DO// 将字符转换为对应的Code 39值CASE BYTE_TO_INT(Buffer[iHM_Zaehler2]) OF48: arrCode_pos[iHM_Zaehler2] := 0 ;// '0'49: arrCode_pos[iHM_Zaehler2] := 1 ;// '1'50: arrCode_pos[iHM_Zaehler2] := 2 ;// '2'51: arrCode_pos[iHM_Zaehler2] := 3 ;// '3'52: arrCode_pos[iHM_Zaehler2] := 4 ;// '4'53: arrCode_pos[iHM_Zaehler2] := 5 ;// '5'54: arrCode_pos[iHM_Zaehler2] := 6 ;// '6'55: arrCode_pos[iHM_Zaehler2] := 7 ;// '7'56: arrCode_pos[iHM_Zaehler2] := 8 ;// '8'57: arrCode_pos[iHM_Zaehler2] := 9 ;// '9'65: arrCode_pos[iHM_Zaehler2] := 10 ;// 'A'66: arrCode_pos[iHM_Zaehler2] := 11 ;// 'B'67: arrCode_pos[iHM_Zaehler2] := 12 ;// 'C'68: arrCode_pos[iHM_Zaehler2] := 13 ;// 'D'69: arrCode_pos[iHM_Zaehler2] := 14 ;// 'E'70: arrCode_pos[iHM_Zaehler2] := 15 ;// 'F'71: arrCode_pos[iHM_Zaehler2] := 16 ;// 'G'72: arrCode_pos[iHM_Zaehler2] := 17 ;// 'H'73: arrCode_pos[iHM_Zaehler2] := 18 ;// 'I'74: arrCode_pos[iHM_Zaehler2] := 19 ;// 'J'75: arrCode_pos[iHM_Zaehler2] := 20 ;// 'K'76: arrCode_pos[iHM_Zaehler2] := 21 ;// 'L'77: arrCode_pos[iHM_Zaehler2] := 22 ;// 'M'78: arrCode_pos[iHM_Zaehler2] := 23 ;// 'N'79: arrCode_pos[iHM_Zaehler2] := 24 ;// 'O'80: arrCode_pos[iHM_Zaehler2] := 25 ;// 'P'81: arrCode_pos[iHM_Zaehler2] := 26 ;// 'Q'82: arrCode_pos[iHM_Zaehler2] := 27 ;// 'R'83: arrCode_pos[iHM_Zaehler2] := 28 ;// 'S'84: arrCode_pos[iHM_Zaehler2] := 29 ;// 'T85: arrCode_pos[iHM_Zaehler2] := 30 ;// 'U'86: arrCode_pos[iHM_Zaehler2] := 31 ;// 'V'87: arrCode_pos[iHM_Zaehler2] := 32 ;// 'W'88: arrCode_pos[iHM_Zaehler2] := 33 ;// 'X'89: arrCode_pos[iHM_Zaehler2] := 34 ;// 'Y'90: arrCode_pos[iHM_Zaehler2] := 35 ;// 'Z'45: arrCode_pos[iHM_Zaehler2] := 36 ;// '-'46: arrCode_pos[iHM_Zaehler2] := 37 ;// '.'32: arrCode_pos[iHM_Zaehler2] := 38 ;// ' '36: arrCode_pos[iHM_Zaehler2] := 39 ;// '$'47: arrCode_pos[iHM_Zaehler2] := 40 ;// '/'43: arrCode_pos[iHM_Zaehler2] := 41 ;// '+'37: arrCode_pos[iHM_Zaehler2] := 42 ;// '%'ELSE: (* 如果找到不匹配的字符,则设置无效数据标志并退出循环 *)xF_Invalide_Daten_C39 := TRUE;Pruef_IO := FALSE;EXIT;END_CASE;// 累加所有字符的Code 39值iCharCode39 := iCharCode39 + arrCode_pos[iHM_Zaehler2]; 此时将刚转换的四个数值加起来4+2+5+10=21END_FOR;// 如果数据有效,则计算校验位IF NOT xF_Invalide_Daten_C39 THEN// 计算模43结果iMOD_39 := iCharCode39 MOD 43 ;// 将模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;// 将字符转换为字节存储到输出校验位1PruefZiff1_Out := INT_TO_BYTE(CHAR_TO_INT(chrPZ));PruefZiff2_Out := 0; // 输出校验位2设为0// 如果不是仅验证数据有效性模式IF NOT xCfg_2 THEN// 将计算得到的校验位与输入校验位比较Pruef_IO := PruefZiff1_Out = PruefZiff1_In;ELSE // 仅验证数据有效性,不验证校验位strVisutext_Ziffer[3] := PruefZiff1_Out;Pruef_IO := TRUE;END_IF;END_IF;ELSIF xCfg_3 THEN // CRC16 Genibus校验wCRCTemp := 16#FFFF;// CRC初始值// 对每个数据字节进行CRC计算FOR iHM_Zaehler2 := 2 TO (2 + DatenLaenge - 1) DO// 计算CRC表索引iCRCIndex := WORD_TO_INT(SHR(IN := wCRCTemp, N := 8) XOR Buffer[iHM_Zaehler2]);// 根据索引选择对应的CRC表进行计算IF iCRCIndex <= 127 THENwCRCTemp := SHL(IN := wCRCTemp, N := 8) XOR CRCTable1[iCRCIndex];ELSEwCRCTemp := SHL(IN := wCRCTemp, N := 8) XOR CRCTable2[iCRCIndex - 128];END_IF;END_FOR;// 计算最终的CRC值_wCRC := wCRCTemp XOR 16#FFFF;// 输出CRC的高低位字节PruefZiff1_Out := wCRC.B1; // 高位字节PruefZiff2_Out := wCRC.B2; // 低位字节// 如果不是仅输出校验位模式IF NOT xCfg_4 THEN// 显示输入的校验位Visutext_Ziffer_Hex.B1 := PruefZiff1_In;Visutext_Ziffer_Hex.B2 := PruefZiff2_In;// 比较计算得到的校验位与输入校验位Pruef_IO := PruefZiff1_Out = PruefZiff1_InAND PruefZiff2_Out = PruefZiff2_In;ELSE// 显示计算得到的校验位Visutext_Ziffer_Hex.B1 := PruefZiff1_Out;Visutext_Ziffer_Hex.B2 := PruefZiff2_Out;Pruef_IO := TRUE;END_IF;END_IF;// 校验不通过 = 校验通过的非Pruef_NIO := NOT Pruef_IO;END_IF;// 无效校验数据 = Code 39无效数据 或 Code 2/5无效数据Invalide_Pruefdaten := xF_Invalide_Daten_C39 OR xF_Invalide_Daten_C2x5;(*----------------------------------------------------------------------------------*)(* 汇总故障 *)Stoexx := False; // 初始化为无故障(*----------------------------------------------------------------------------------*)(* 链式故障输出 = 链式故障输入 或 汇总故障 *)VkStoe_Out:= VkStoe_In OR Stoexx;(*----------------------------------------------------------------------------------*)// 可视化相关设置dwVisuWerte1.X0 := FALSE;dwVisuWerte1.X1 := FALSE;dwVisuWerte1.X2 := xCfg_3; (* 显示CRC16是否选中 *)dwVisuWerte1.X3 := Pruef_IO; (* 显示校验是否通过 *)dwVisuWerte1.X4 := NOT Invalide_Pruefdaten AND (Pruef_NIO OR Pruef_IO); (* 显示数据是否有效 *)dwVisuWerte1.X5 := Frg_Start AND NOT oProz AND Pruef_Auswahl_IO; (* 控制Start按钮是否可点击 *)dwVisuWerte1.X6 := Frg_oProz; (* 控制Ohne按钮是否可点击 *)dwVisuWerte1.X7 := Pruef_NIOOR DatenLaenge < 1OR xF_PruefdatenKopieOR xF_Invalide_Daten_C2x5OR xF_Invalide_Daten_C39; (* 控制是否显示红色边框 *)dwVisuWerte1.X8 := FALSE; (* 不显示黄色边框 *)// 可视化Start按钮设置dwVisuWerte1.B3 := BYTE#64; // 显示Start按钮// 根据Start信号状态设置按钮颜色IF xS_Start THENdwVisuWerte1.B3 := dwVisuWerte1.B3 OR BYTE#16#01 ; (*01: 绿色背景 黑色文本*)ELSEdwVisuWerte1.B3 := dwVisuWerte1.B3 OR BYTE#16#00 ; (*00: 灰色背景 黑色文本*)END_IF;// 可视化Ohne按钮设置dwVisuWerte1.B2 := BYTE#64; // 显示Ohne按钮// 根据无过程模式状态设置按钮颜色IF oProz THENdwVisuWerte1.B2 := dwVisuWerte1.B2 OR BYTE#16#06 ; (*06: 黄色背景 黑色文本*)ELSEdwVisuWerte1.B2 := dwVisuWerte1.B2 OR BYTE#16#00 ; (*00: 灰色背景 黑色文本*)END_IF;(************************************************************************************)(**SIEMENS***************************************************************************)(************Anfang Signalaufbereitung Meldesystem fuer den Siemensteil**************)(***********************AUFRUF am Ende im SCL-BAUSTEINS******************************)// 初始化消息指针_pMeldFeld := MeldFeld;_pMeldAbb := MeldAbb;_pMeld := ST_Meld;// 修改消息指针的存储区域(从DB到DI)pMeldFeld.BZ := pMeldFeld.BZ OR 16#1000000;pMeldAbb.BZ := pMeldAbb.BZ OR 16#1000000;// 设置消息系统的故障标志MSys.xF_1 := DatenLaenge < 1; //'STE/Pruefdatenlaenge = 0' 校验数据长度为0MSys.xF_2 := xF_Invalide_Daten_C2x5; //'STE/Code2x5 Invalide Daten' Code 2/5无效数据MSys.xF_3 := xF_Invalide_Daten_C39; //'STE/Code39 Invalide Daten' Code 39无效数据MSys.xF_4 := xF_PruefdatenKopie; //'STE/Pruefdaten nicht einlesbar 校验数据无法读取// 发送消息MeldSend(AufrufNr := 1,Anz_Meld := 4,pMeldFeld := pMeldFeld.BZ,pMeldAbb := pMeldAbb.BZ,MeldDB := WORD_TO_INT(pMeld.DBNR),AenderungsID := AenderungsID,Integritaet := Integritaet,Neustart := "Neustart");// 站点相关的故障汇总DB_ARG.VisuSS.Station_Stoer:= DB_ARG.VisuSS.Station_StoerOR Msys.xF_1OR Msys.xF_2OR Msys.xF_3OR Msys.xF_4;// 站点相关的警告汇总(此处未使用,设为FALSE)DB_ARG.VisuSS.Station_Warn := DB_ARG.VisuSS.Station_WarnOR FALSE ;// 站点相关的维护提示汇总(此处未使用,设为FALSE)DB_ARG.VisuSS.Station_Wart := DB_ARG.VisuSS.Station_WartOR FALSE ;(**SIEMENS***************************************************************************)(*************Ende Signalaufbereitung Meldesystem fuer den Siemensteil****************)(************************************************************************************)// 注释掉的代码:块移动操作(用于优化循环时间)//erg_SFC20:= BLKMOV(srcblk:= _ST_BA, dstblk:= ST_BA); //Zykluszeitoptimierung(*----------------------------------------Ende--------------------------------------*)END_FUNCTION_BLOCK```以上是对FB_Pruefziffer功能块的逐行详细解读。这个功能块主要实现了三种校验算法(Code 2/5、Code 39和CRC16),用于计算和验证数据的校验位。功能块还包含了与可视化界面交互的逻辑,能够显示数据和校验结果,并通过消息系统报告故障状态。整个功能块设计严谨,考虑了各种边界情况和错误处理,适用于工业自动化环境中的数据校验场景。
加入知识星球智能制造与自动化,加入会员可下载此公众号发布文章中的相关资料(行业报告、MES、数字化技术方案、自动化教程、自动化行业标准化资料VASSSICAR戴姆勒等、C#上位机开发、node-red开发、人工智能教程等)。
981
