博图TIA中ModbusRTU_CRC校验程序的实现
使用SCL语言,在博图TIA中编写ModbusRTU_CRC校验程序,使用两个FC块,实现两种不同的应用CRC1将计算结果直接输出,CRC2将计算的结果插入到输入数组的最后端.
TIA中自带了modbusRTU通讯库,之所以自己实现CRC校验码的计算只是为了更深入的学习TIA SCL编程序.
实现效果及代码截图
代码片段
CRC1
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
SEND1
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
CRC2
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
SEND2
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