使用SCL语言,在博图TIA中编写ModbusRTU_CRC校验程序,使用两个FC块,实现两种不同的应用CRC1将计算结果直接输出,CRC2将计算的结果插入到输入数组的最后端.
TIA中自带了modbusRTU通讯库,之所以自己实现CRC校验码的计算只是为了更深入的学习TIA SCL编程序.
FUNCTION "CRC1" : Void { S7_Optimized_Access := 'TRUE' } VERSION : 0.1 VAR_INPUT CrcData : Variant; END_VAR VAR_OUTPUT CrcValue : Word; CrcErr : Word; END_VAR VAR_TEMP Preset : Word; LoopLength : Int; ArrayPoint : Int; i : Int; ArrayLength : UDInt; Array1 : Array[0..999] of Byte; // 最多1000个字节 Err : Int; END_VAR BEGIN #ArrayLength:= CountOfElements(#CrcData); IF #ArrayLength <= 1000 THEN //这里的1000如果需要调大,对应的数组临时变量Array1也要调大 #Err := MOVE_BLK_VARIANT(SRC := #CrcData, COUNT := #ArrayLength, SRC_INDEX := 0, DEST_INDEX := 0, DEST => #Array1); #Preset := 16#FFFF; #LoopLength := 0; #ArrayPoint := 0; //计算CRC校验码 WHILE #LoopLength < #ArrayLength DO //数据长度 #Preset := #Preset XOR #Array1[#ArrayPoint]; #ArrayPoint := #ArrayPoint + 1; FOR #i := 0 TO 7 DO IF (#Preset AND 16#01) = 16#01 THEN #Preset := SHR(IN := #Preset, N := 1); #Preset := #Preset XOR 16#A001; ELSE #Preset := SHR(IN := #Preset, N := 1); END_IF; END_FOR; #LoopLength := #LoopLength + 1; END_WHILE; //#CrcValue := #Preset; #CrcValue := SHR_WORD(IN := #Preset, N := 8) + SHL_WORD(IN := #Preset, N := 8); #CrcErr := 16#0000; ELSE #CrcErr := 16#8000; END_IF; END_FUNCTION
DATA_BLOCK "SEND1" { S7_Optimized_Access := 'FALSE' } VERSION : 0.1 NON_RETAIN STRUCT CrcData : Array[0..5] of Byte; // 该数组不大于1000字节 CrcValue : Word; CrcError : Word; END_STRUCT; BEGIN CrcData[0] := 16#01; CrcData[1] := 16#03; CrcData[2] := 16#00; CrcData[3] := 16#00; CrcData[4] := 16#00; CrcData[5] := 16#01; END_DATA_BLOCK
FUNCTION "CRC2" : Void { S7_Optimized_Access := 'TRUE' } VERSION : 0.1 VAR_INPUT Command : Variant; dataLen : Int; END_VAR VAR_TEMP buffer : Array[0..#MaxLen] of Byte; i : Int; j : Int; CrcReg : Word; Len : Int; END_VAR VAR CONSTANT MaxLen : Int := 255; END_VAR BEGIN IF #dataLen = 0 OR #dataLen > CountOfElements(IN := #Command) - 2 THEN RETURN; ELSE #Len := #dataLen; END_IF; #CrcReg := 16#FFFF; //将数据转到缓冲区 VariantGet(SRC:=#Command, DST=>#buffer); //计算CRC校验码 FOR #i := 0 TO (#Len - 1) DO #CrcReg := #CrcReg XOR #buffer[#i]; FOR #j := 0 TO 7 DO IF (#CrcReg AND 16#1) = 1 THEN #CrcReg := SHR_WORD(IN := #CrcReg, N := 1); #CrcReg := #CrcReg XOR 16#A001; ELSE #CrcReg := SHR_WORD(IN := #CrcReg, N := 1); END_IF; END_FOR; END_FOR; #buffer[#Len + 1] := SHR_WORD(IN := #CrcReg, N := 8); #buffer[#Len] := #CrcReg AND 16#FF; //将缓冲区数据再写入到指针所指向的区域 VariantPut(SRC := #buffer, DST := #Command); END_FUNCTION
DATA_BLOCK "SEND2" { S7_Optimized_Access := 'FALSE' } VERSION : 0.1 NON_RETAIN STRUCT CrcData : Array[0..7] of Byte; // 该数组不大于1000字节 END_STRUCT; BEGIN CrcData[0] := 16#01; CrcData[1] := 16#03; CrcData[2] := 16#00; CrcData[3] := 16#00; CrcData[4] := 16#00; CrcData[5] := 16#01; END_DATA_BLOCK