异或运算怎么理解(CRC校验原理详解)
- 100次浏览 发布时间:2024-11-06 08:35:45
0、前言
在做RS485协议时需要用到CRC校验,顺便剖析一下CRC校验过程
根据Modbus协议,常规485通讯的信息发送形式如下:
地址 功能码 数据信息 校验码
1byte 1byte nbyte 2byte
CRC校验是前面几段数据内容的校验值,计算为一个16位数据,发送时,低8位在前,高8为最后
前置知识:异或运算
异或算法有三个特征:
1、任何数和0做异或运算,结果仍然是原来的数,即a ⊕ 0 = a。
2、任何数和自身做异或运算时,结果是0,即a ⊕ a=0 。 注意a ⊕ a ⊕ a = a
3、运算规则:相同取0,相异取1
1、CRC16校验原理:
(1). CRC寄存器初始值为 0xFFFF;即16个字节全为1。
(2). CRC-16 / ModBus的二进制展开多项式为:X16+X15+X2+1,即任意一个由二进制位串组成的代码都可以和一个系数仅为‘0’和‘1’取值的多项式一一对应,
最后得出:0x8005H(1000 0000 0000 0101 B)。
(3). 通过把 0x8005H 的 “ 高位80 ” 与 “ 低位05 ” 进行互换,得到最终的多项式:0xA001H(1010 0000 0000 0001 B)。
2、计算步骤:
(1). 预置 16 位寄存器为十六进制 0xFFFF(即全为 1) ,称此寄存器为 CRC 寄存器;
(2). 把第一个 8 位数据与 16 位 CRC 寄存器的低位相异或,把结果放于 CRC 寄存器;
(3). 检测相异或后的CRC寄存器的最低位,若最低位为1,CRC寄存器先右移1位,再与多项式A001H进行异或;若为0,则CRC寄存器右移1位,无需与多项式进行异或。
(4). 重复步骤 3 ,直到右移 8 次,这样整个 8 位数据全部进行了处理;
(5). 重复步骤 2 到步骤 4,进行下一个 8 位数据的处理;
(6). 最后得到的 CRC 寄存器即为 CRC 校验码。
3、计算程序:
这段代码定义了一个名为rcr16的函数,用于计算RCR16校验。该函数接受一个指向
数据的指针和数据的长度作为参数,并返回计算得到的校验值。在setup函数中,我
们定义了一个示例数据data,并计算其校验值,并通过串口打印出来。
#include <Arduino.h>
uint16_t rcr16(uint8_t *data, uint16_t length) {
uint16_t crc = 0xFFFF;//CRC寄存器
for (uint16_t i = 0; i < length; i++) {
crc ^= (uint16_t)data[i];//把数据与16位的CRC寄存器的低8位相异或,结果存放于CRC寄存器。
for (uint8_t j = 0; j < 8; j++) {//循环8次
if (crc & 0x0001) {//判断最低位为:“1”
crc >>= 1;//先右移
crc ^= 0xA001;//再与0xA001异或
} else {//判断最低位为:“0”
crc >>= 1;//右移
}
}
}
return crc;//返回CRC校验值
}
void setup() {
Serial.begin(9600);
uint8_t data[] = {0x01,0x03,0x61,0x00,0x00,0x02};
uint16_t length = sizeof(data) / sizeof(data[0]);
uint16_t crc = rcr16(data, length);
// 打印结果
Serial.print("CRC: ");//01 03 61 00 00 02 CRC校验:F7 DB
Serial.println(crc, HEX);//输出校验值crc16(CRC16-->低位在前,高位在后)
}
void loop() {
}