Modbus-crc16校验原理和方法(含测试代码以及演算过程)

Modbus-crc16校验原理和方法(含测试代码以及演算过程)

1.modbus基础知识

1.1什么是modbus

1. Modbus是一种串行通信协议,最初由Modicon(目前属于施耐德电气公司)于1979年开发

2. Modbus协议是应用在Modicon产品上的,后来才被移植到其他产品上

3. Modbus协议的通信接口可以有多种选择,如RS232、RS485、以太网等

1.2 协议特点

支持主从方式,即主站、从站Modbus协议主要分为两种格式,即Modbus RTU和Modbus ASCII,Modbus RTU使用二进制格 式传输数据,而Modbus ASCII则将数据以ASCII码形式进行传输。此外,Modbus还可以通过TCP/IP协议进行网络通信,称为Modbus TCP/IP。

1.3 协议格式

1. 起始地址(也就是常说的站号)

2. 功能码 (01,03,06,10,16等等)

3. 数据内容

4. 校验码(CRC16校验)

2.modbus-crc16校验原理方法以及手算验证

2.1 校验方法

CRC计算方法:

1.预置1个16位的寄存器为十六进制FFFF(即全为1);称此寄存器为CRC寄存器;

2.把第一个8位二进制数据(既通讯信息帧的第一个字节)与16位的CRC寄存器的低8位相异或,把结果放于CRC寄存器;

3.把CRC寄存器的内容右移一位(朝低位)用0填补最高位,并检查右移后的移出位;

4.如果移出位为0:重复第3步(再次右移一位);如果移出位为1:CRC寄存器与多项式A001(1010 0000 0000 0001)进行异或;

5.重复步骤3和4,直到右移8次,这样整个8位数据全部进行了处理;

6.重复步骤2到步骤5,进行通讯信息帧下一个字节的处理;

7.将该通讯信息帧所有字节按上述步骤计算完成后,得到的16位CRC寄存器的高、低字节进行交换;

2.2 校验参考代码

/*

* @name CRC_Check

* @brief CRC校验

* @param CRC_Ptr->数组指针,LEN->长度

* @retval CRC校验值

*/

uint16_t CRC_Check(uint8_t *CRC_Ptr,uint8_t LEN)

{

uint16_t CRC_Value = 0;

uint8_t i = 0;

uint8_t j = 0;

CRC_Value = 0xffff;

for(i=0;i

{

CRC_Value ^= *(CRC_Ptr+i);

for(j=0;j<8;j++)

{

if(CRC_Value & 0x00001)

CRC_Value = (CRC_Value >> 1) ^ 0xA001;

else

CRC_Value = (CRC_Value >> 1);

}

}

CRC_Value = ((CRC_Value >> 8) + (CRC_Value << 8)); //交换高低字节

return CRC_Value;

}

2.3 手算校验过程

我们以这个数据包为例,来分析一下校验过程:

Tx:000002-01 03 00 00 00 0A C5 CD

01 起始地址 03功能码 C5 CD 校验码

第一个数据为0x01 ,与0xffff,进行异或运算,得到的数值为0xfffe

0xfffe与0x01进行相与运算,得到的数值为0,所以直接向右移1位,得到的结果为0111 1111 1111 1111

现在是第一个数据向右移出1位了,重复上述过程

0111 1111 1111 1111(0x7ffff)与0x01相与,得到的结果为1,所以向右移出一位,得到的结果为0011 1111 1111 1111与0xA001进行异或运算得到的结果为1001 1111 1111 1110(0x9FFE)

1-5的运算过程如下图(演算的正式过程)

现在第一个数据向右移出2位了,重复上述过程

经过演算第一个最后的结果为807E,草图如下(演算的草图)

为了方便演示,我们直接写成C程序跑一下上述过程,看下对不对

经过程序运算,算的的第一个数据0x01的校验码为0x807e,与我们手算的结果一致

接下来拿807e作为tmp的数值,接着运行下一个数据0x03,同理接着运行至最后一个数据0x0A,得到最终的crc计算结果C5CD

最终的运行结果为

modbus测试程序

#include

int main(void)

{

// Tx:000000-01 03 00 00 00 0A C5 CD

unsigned short tmp = 0xffff;

unsigned short val = 0;

unsigned char buff[6] = {0};

buff[0] = 0x01;

buff[1] = 0x03;

buff[2] = 0x00;

buff[3] = 0x00;

buff[4] = 0x00;

buff[5] = 0x0A;

for(int n = 0; n < 6; n++)

{

tmp = buff[n] ^ tmp;

printf("异或数据为:%x\n",tmp);

for(int i = 0;i < 8;i++){ /*此处的8 -- 指每一个char类型又8bit,每bit都要处理*/

printf("遍历层数为:%d\t\t最后一位的数为:%d",i*n, tmp & 0x01);

printf("\t当前tmp为:%x\n",tmp );

if(tmp & 0x01){

tmp = tmp >> 1;

tmp = tmp ^ 0xa001;

}

else{

tmp = tmp >> 1;

}

}

printf("第%d个数据通过crc16校验后为 %x\n",n,tmp);

}

/*将CRC校验的高低位对换位置*/

val = tmp >> 8;

val = val | (tmp << 8);

printf("交换后为: %X\n",val);

return 0;

}

最后

1.单片机连续发送时,两帧之间的时间大于等于为3.5个字符

2.如有错误,欢迎批评指正

相关推荐

中国男足世预赛C组赛程揭晓:力争前二名晋级,能否逆袭强敌韩国与泰国?
2026世界杯已出线名单-2026世界杯出线规则
bt365注册

2026世界杯已出线名单-2026世界杯出线规则

06-30 👁️‍🗨️ 9848
中通服软件公司笔试面试 回忆版
bt365注册

中通服软件公司笔试面试 回忆版

07-11 👁️‍🗨️ 5788
法国尼斯自由行旅游攻略 | 景点、美食、交通全都有!
365彩票app下载苹果版

法国尼斯自由行旅游攻略 | 景点、美食、交通全都有!

07-16 👁️‍🗨️ 7157
无线信号弱,网络不好
bt365注册

无线信号弱,网络不好

06-28 👁️‍🗨️ 4062
Zorro2 (佐罗切割) v2.0_beta(汉化)
线上365bet正网

Zorro2 (佐罗切割) v2.0_beta(汉化)

07-04 👁️‍🗨️ 5676
仙境传说战斗时长怎么提升(仙境传说的规则?)
365彩票app下载苹果版

仙境传说战斗时长怎么提升(仙境传说的规则?)

07-14 👁️‍🗨️ 9059
仙境传说战斗时长怎么提升(仙境传说的规则?)
365彩票app下载苹果版

仙境传说战斗时长怎么提升(仙境传说的规则?)

07-14 👁️‍🗨️ 9059
突尼斯世界杯历史记录(探索突尼斯在世界杯中的历史及成就)