博图TIA中ModbusRTU_CRC校验程序的实现

博图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
posted @ 2021-08-21 18:13  生命在等待中延续  阅读(1780)  评论(0编辑  收藏  举报