CRC16-HJ212版
最近在开发中用到了HJ212环保数据传输标准,其中数据发送到上位机需要一道CRC16校验算法,开始以为是几种主流标准CRC16之一,但是运行之后无法得到官方的校验值十六进制1C80,对应十进制7296。
--待校验数据,正确校验结果为0x1C80
QN=20160801085857223;ST=32;CN=1062;PW=100000;MN=010000A8900016F000169DC0;Flag=5;CP=&&RtdInterval=30&&
因为我的开发语言是Lua,网上搜索了下也没有找到Lua版本的,无奈只能重写一次了,参照官方给出的C语言版本
CRC16 校验字节的生成步骤如下:
1) CRC16 校验寄存器赋值为 0xFFFF;
2) 取被校验串的第一个字节赋值给临时寄存器;
3) 临时寄存器与 CRC16 校验寄存器的高位字节进行“异或”运算,赋值给 CRC16 校验寄存器;
4) 取 CRC16 校验寄存器最后一位赋值给检测寄存器;
5) 把 CRC16 校验寄存器右移一位;
6) 若检测寄存器值为 1,CRC16 校验寄存器与多项式 0xA001 进行“异或”运算,赋值给 CRC16
校验寄存器;
7) 重复步骤 4~6,直至移出 8 位;
8) 取被校验串的下一个字节赋值给临时寄存器;
9) 重复步骤 3~8,直至被校验串的所有字节均被校验;
10) 返回 CRC16 校验寄存器的值。
校验码按照先高字节后低字节的顺序存放
C语言版本[官方]
unsigned int CRC16_Checkout ( unsigned char *puchMsg, unsigned int usDataLen )
{
unsigned int i,j,crc_reg,check;
crc_reg = 0xFFFF;
for(i=0;i<usDataLen;i++)
{
crc_reg = (crc_reg>>8) ^ puchMsg[i];
for(j=0;j<8;j++)
{
check = crc_reg & 0x0001;
crc_reg >>= 1;
if(check==0x0001){crc_reg ^= 0xA001; }
}
}
return crc_reg;
}
Lua5.3
local function crc212(data212)
local crc_reg=0xFFFF
local check
for s in string.gmatch(data212, ".") do
crc_reg= (crc_reg >> 8) ~ string.byte(s)
for i=0,7 do
check = crc_reg & 0x0001
crc_reg = crc_reg >> 1
if check==0x0001 then crc_reg = crc_reg ~ 0xA001 end
end
end
return crc_reg
end
另外,LuatOS框架基于5.3开发,可是我在vscode模拟器环境下开发时,遇到太多版本不一致了,比如5.3种中的位运算符号提示非法,而我用5.1的位运算符却又编译通过了,其中Lua5.1-5.3的位运算符每个版本都不一样,踩坑,同样的问题在load( ) 以及loadstring( )上。
Lua5.1
local function crc212(data212)
local crc_reg=0xFFFF
local check
for s in string.gmatch(data212, ".") do
crc_reg=bit.rshift(crc_reg,8)
crc_reg=bit.bxor(crc_reg,string.byte(s))
for i=0,7 do
check =bit.band(crc_reg,0x0001)
crc_reg = bit.rshift(crc_reg,1)
if check==0x0001 then crc_reg =bit.bxor(crc_reg,0xA001) end
end
end
return crc_reg
end
此外这里还写了一份Java版本的,位运算符基本和C是一致的,平平无奇
Java
public static int crc212(String data212) {
int crc_reg=0xFFFF;
int check;
byte[] dataByte=data212.getBytes();
for (int i = 0; i < data212.length(); i++) {
crc_reg= (crc_reg >>8) ^ dataByte[i];
for (int j = 0; j < 8; j++) {
check=crc_reg & 0x0001;
crc_reg >>=1;
if (check==0x0001) {crc_reg^=0xA001;}
}
}
return crc_reg;
};