这段代码实现了 Modbus RTU 协议中常用的 CRC16 校验算法,适用于西门子 S7 系列 PLC 的结构化文本(Structured Text, ST)环境。其主要功能是根据输入的字节数组(byInputArray)和指定的字节数(uiInNumBytes),计算出对应的 CRC16 校验值,并将高、低字节分别输出。
代码首先通过 LOWER_BOUND 和 UPPER_BOUND 获取输入数组的上下界,确保后续遍历不会越界。如果实际需要校验的字节数小于数组长度,则动态调整上界,仅对前 uiInNumBytes 个字节进行校验。CRC 的初始值设为 0xFFFF(标准 Modbus 起始值),多项式为 0xA001。
主循环依次处理每个字节,将其与当前 CRC 值异或。随后,内部嵌套的位循环对每一位进行右移操作,并根据最低位是否为 1 决定是否与多项式异或,实现 CRC16 的逐位计算。所有字节处理完毕后,最终的 CRC16 值被拆分为高、低字节输出
FUNCTION "fcCRC16_ModbusRTU" : Void
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
VAR_INPUT
uiInNumBytes : UInt; // 输入字节数
END_VAR
VAR_OUTPUT
byOutCRCHigh : Byte; // 输出CRC高字节
byOutCRCLow : Byte; // 输出CRC低字节
END_VAR
VAR_IN_OUT
byInputArray : Array[*] of Byte; // 输入字节数组
END_VAR
VAR_TEMP
iTempLowerLimit : DInt; // 数组下界
iTempUpperLimit : DInt; // 数组上界
wTempCRC : Word; // 临时CRC值
iByteIndex : Int; // 字节索引
iBitIndex : Int; // 位索引
wTemp : Word; // 临时变量
END_VAR
VAR CONSTANT
cwXor : Word := 16#A001; // CRC多项式
cwStart : Word := 16#FFFF; // CRC初始值
END_VAR
BEGIN
#iTempLowerLimit := LOWER_BOUND(ARR := #byInputArray, DIM := 1); // 获取数组下界
#iTempUpperLimit := UPPER_BOUND(ARR := #byInputArray, DIM := 1); // 获取数组上界
IF #uiInNumBytes > 0 AND #uiInNumBytes <= (#iTempUpperLimit - #iTempLowerLimit + 1) THEN
#iTempUpperLimit := #uiInNumBytes + #iTempLowerLimit - 1; // 根据输入字节数调整上界
END_IF;
#wTempCRC := #cwStart; // 初始化CRC
FOR #iByteIndex := #iTempLowerLimit TO #iTempUpperLimit DO
#wTempCRC := #wTempCRC XOR #byInputArray[#iByteIndex]; // 按字节异或
FOR #iBitIndex := 0 TO 7 DO
#wTemp := SHR(IN := #wTempCRC, N := 1); // 右移一位
IF #wTempCRC.%X0 THEN
#wTempCRC := #wTemp XOR #cwXor; // 若最低位为1,异或多项式
ELSE
#wTempCRC := #wTemp; // 否则直接赋值
END_IF;
END_FOR;
END_FOR;
#byOutCRCHigh := #wTempCRC.%B0; // 取高字节
#byOutCRCLow := #wTempCRC.%B1; // 取低字节
END_FUNCTION