【分享】Modbus CRC校验自己的学习笔记

已锁定

刚刚入门

  • 帖子

    2022
  • 精华

    23
  • 被关注

    119

论坛等级:至圣

注册时间:2009-10-24

白金 白金 如何晋级?

【分享】Modbus CRC校验自己的学习笔记

2598

7

2015-07-03 15:36:20

原来自己做的Modbus CRC校验的学习笔记,后面的程序也是整合网上的资源在TIASTEP7测试过的,东西大家可能觉得简单,主要还是支持下论坛的“分享”活动。其实分享是互联网时代的精髓之一,内容里有不到之处请大家批评改正,谢谢!
1. 1字节的CRC-16校验步骤
以数据16#4E为例 16#4E二进制就是 0100 1110
① 装载一个16位寄存器,所有数位均为1,即1111 1111 1111 1111
② 该16位寄存器的8位字节与数据16#4E的8位字节进行“异或”,结果放到这个16位寄存器中
1111 1111 1111 1111
0100 1110
1111 1111 1011 0001--(16位寄存器)
把这个16位寄存器向右移一位,0111 1111 1101 1000
因为本次向右(标记位)移出的数位是1,则生成多项式1010000000000001
将该多项式与16位寄存器进行异或
1010 0000 0000 0001
0111 1111 1101 1000
1101 1111 1101 1001--(16位寄存器)
③ 16位寄存器第2次右移一位,0110 1111 1110 1100
本次向右(标记位)移出的数位是1,则生成多项式1010000000000001
将该多项式与16位寄存器进行异或
1010 0000 0000 0001
0110 1111 1110 1100
1100 1111 1110 1101--(16位寄存器)
④ 第3次右移一位,0110 0111 1111 0110
本次向右(标记位)移出的数位是1,则生成多项式1010000000000001
将该多项式与16位寄存器进行异或
1010 0000 0000 0001
0110 0111 1111 0110
1100 0111 1111 0111--(16位寄存器)
⑤ 第4次右移一位 0110 0011 1111 1011
本次向右(标记位)移出的数位是1,则生成多项式1010000000000001
将该多项式与16位寄存器进行异或
1010 0000 0000 0001
0110 0011 1111 1011
1100 0011 1111 1010--(16位寄存器)
⑥ 第5次右移一位 0110 0001 1111 1101
本次向右(标记位)移出的数位是0, 0110 0001 1111 1101-(16位寄存器)
⑦ 第6次右移一位 0011 0000 1111 1110
本次向右(标记位)移出的数位是1,则生成多项式1010000000000001
将该多项式与16位寄存器进行异或
1010 0000 0000 0001
0011 0000 1111 1110
1001 0000 1111 1111--(16位寄存器)
⑧ 第7次右移一位 0100 1000 0111 1111
本次向右(标记位)移出的数位是1,则生成多项式1010000000000001
将该多项式与16位寄存器进行异或
1010 0000 0000 0001
0100 1000 0111 1111
1110 1000 0111 1110--(16位寄存器)
⑨ 第8次右移一位 0111 0100 0011 1111
本次向右(标记位)移出的数位是0, 0111 0100 0011 1111这个值就是这个数据的CRC校验值 16#743F
2. CRC-16校验的FC功能(STL编辑,TIASTEP7下测试过)
//Input:MSG(ANY)
LEN(INT)
Output:CRC_OUT(Word)
Temp:CRC(Word)
DB_NC(Word)
LOOP1_COUNT(Word)
LOOP2_COUNT(Word)//
L W#16#FFFF
T #CRC //初始化校验寄存器
L P##MSG //取ANY型的数据MSG的地址
LAR1 //将地址装入AR1
L W [ AR1 , P#4.0 ] //获取数据块号
T #DB_NO //获取的数据块号装入DB_NO
L 0 //装载常数0
<>I //如果数据块号不为0
OPN DB [ #DB_NO] //打开数据块
L D [ AR1 , P#6.0 ] //将ANY型数据MSG和后四个字节
LAR1 //作为指针值装入AR1
L #LEN //装载参与CRC计算的字节长度
RPT1: T #LOOP1_COUNT //送给外循环计数临时变量
L #CRC //装载当前校验寄存器CRC值
L B [ AR1 , P#0.0 ] //装载当前指针指向的数据值
XOW //二者进行异或
T #CRC //异或结果装入到校验寄存器CRC中
L 8 //装载移位的位数8
RPT2: T #LOOP2_COUNT //送给内循环计数临时变量
L #CRC //装载当前校验寄存器CRC值
AW W#16#1 //将当前CRC值与1进行“与”操作
L W#16#0
==I //如结果为0,即CRC最低位不为1
JC B00 //跳转到分支B00
L #CRC //如CRC最低位为1,装载CRC值
SRW 1 //将CRC值右移1位
L W#16#A001 //生成多项式1010000000000001
XOW //二者进行异或
T #CRC //异或结果装入到校验寄存器CRC中
JU B01 //无条件跳转到B01分支
B00: L #CRC //装载当前校验寄存器CRC值
SRW 1 //将CRC值右移1位
T #CRC //结果装入到校验寄存器CRC中
B01: L #LOOP2_COUNT //装载内循环计数
LOOP RPT2 //内循环计数减一,并执行下一内循环RPT2
+AR1 P#1.0 //指针指向MSG的下一字节
L #LOOP1_COUNT //装入外循环计数
LOOP RPT1 //外循环计数减一,并执行下一外循环RPT1
L #CRC
T #CRC_OUT //最终结果输出
3. CRC-16校验的FC功能(SCL编辑,TIASTEP7下测试过)
//input: db_offset(int)
Length(int)
Output: low_crc(Byte)
High_crc(Byte)
Temp: i(int)
J(int)
Crc_v(DWord)//
#crc_v := WORD#16#FFFF;
FOR #i := 0 TO #length - 1 BY 1 DO
#crc_v := #crc_v XOR BYTE_TO_DWORD("DB_CRC1"."BYTE"[#db_offset + #i]);
FOR #j := 0 TO 7 BY 1 DO
IF ((#crc_v & 1) <> 0) THEN
#crc_v := SHR(IN := #crc_v, N := 1) XOR word#16#A001;
ELSE
#crc_v := SHR(IN := #crc_v, N := 1);
END_IF;
END_FOR;
END_FOR;
#low_crc := DWORD_TO_BYTE(#crc_v & 16#00FF);
#crc_v := ROR(IN := #crc_v, N := 8);
#high_crc := DWORD_TO_BYTE(#crc_v);
【分享】Modbus CRC校验自己的学习笔记 已锁定
编辑推荐: 关闭

请填写推广理由:

本版热门话题

SIMATIC S7-1200系列

共有15100条技术帖

相关推荐

热门标签

相关帖子推荐

guzhang

恭喜,你发布的帖子

评为精华帖!

快扫描右侧二维码晒一晒吧!

再发帖或跟帖交流2条,就能晋升VIP啦!开启更多专属权限!

  • 分享

  • 只看
    楼主

top
您收到0封站内信:
×
×
信息提示
很抱歉!您所访问的页面不存在,或网址发生了变化,请稍后再试。