西门子200SMART系列PLC自由口通讯CRC校验程序。 该程序已经实测
咱们今天来聊聊西门子200SMART PLC自由口通讯里那个让人头秃的CRC校验。搞过串口通讯的老铁都知道,数据校验这玩意儿就像吃火锅必须配的蘸料,少了它数据分分钟给你表演"灵魂出窍"。
先上硬菜——实测通过的CRC校验程序:
// CRC校验子程序 VAR_IN_OUT pData : POINTER; // 数据块指针 DataLen : INT; // 数据长度 END_VAR VAR_OUT CRCResult : WORD; // 校验结果 END_VAR VAR i,j : INT; temp : WORD; END_VAR CRCResult := 16#FFFF; // CRC初始值 FOR i := 0 TO DataLen-1 DO CRCResult := CRCResult XOR BYTE_TO_WORD(pData^); pData := pData + 1; FOR j := 0 TO 7 DO temp := CRCResult; CRCResult := CRCResult SHR 1; IF (temp AND 16#0001) <> 0 THEN CRCResult := CRCResult XOR 16#A001; END_IF END_FOR END_FOR这段代码的核心在于双重循环结构。外层循环遍历每个字节,内层循环处理每个bit位。重点看这个16#A001参数,这可不是随便写的魔法数字,它对应的是CRC-16/MODBUS的多项式x^16 + x^15 + x^2 + 1(低16位正好是0xA001)。
这里有个骚操作:BYTETOWORD(pData^)。为什么要用指针操作?因为直接操作指针比用数组索引更节省内存,特别是处理长数据帧时,能有效避免200SMART的内存限制。不过新手要注意,指针操作不当可能引发"血案",建议在调试时先用数组版本验证逻辑。
再看主程序怎么调用这个子程序:
// 主程序调用示例 VAR SendBuffer : ARRAY[0..5] OF BYTE := [16#01, 16#03, 16#00, 16#00, 16#00, 16#01]; CRC : WORD; pSend : POINTER := ADR(SendBuffer); END_VAR // 调用CRC计算 CRC_Calc(pData := pSend, DataLen := 6, CRCResult => CRC); // 将CRC结果填入发送缓冲区 SendBuffer[6] := WORD_TO_BYTE(CRC AND 16#FF); // 低位在前 SendBuffer[7] := WORD_TO_BYTE(CRC SHR 8);这里有个细节魔鬼:CRC校验码的低字节在前。很多兄弟栽在这个坑里,明明计算正确却死活通讯不上。记住MODBUS协议是低位优先,和咱们平时写数字的习惯相反。
调试时建议祭出两大利器:
- 串口助手抓包看原始数据
- 用状态表监控CRC计算结果
如果发现校验码总是不对,先检查这三处:
① 初始值是不是0xFFFF
② 多项式对不对
③ 字节顺序有没有搞反
最后说个实战经验:当通讯距离超过50米时,就算CRC校验通过,也可能出现偶发性的数据错误。这时候别死磕程序,该上485中继器或者加终端电阻就得加,硬件问题软件救不了场。
代码虽短,但都是精华。下次遇到自由口通讯问题,记得先拿这个CRC程序去验身,保准能过滤掉一大半的灵异事件。