一、CRC16算法快速了解
一般一些工业上仪器仪表都会选择CRC16校验,而写程序对帧数据的校验也需要选择CRC16校验看看对不对。所以选择CRC16校验还是很有必要的。
当然CRC
是2
字节的,具体存储方式大端存储还是小端存储,不同机器不一样。CRC
的初值也可能不一样有的是0x0000
,而有的又却是0xFFFF
具体怎么选还有根据实际应用环境,进行合理的测试取舍。
二、不同环境下的写法
①、51
的CRC16校验
/**
* @brief 计算CRC
* @param *modbusdata:数据指针
* @param length:数据长度
* @param
* @retval 计算的CRC值
* @example
**/
unsigned int crc16_modbus(unsigned char *modbusdata, char length)
{
char i, j;
unsigned int crc = 0xffff;//有的用ffff有的用0
for (i = 0; i < length; i++)
{
crc ^= modbusdata[i];
for (j = 0; j < 8; j++)
{
if ((crc & 0x01) == 1)
{
crc = (crc >> 1) ^ 0xa001;
}
else
{
crc >>= 1;
}
}
}
return crc;
}
②、LUA
的CRC16校验
function CRC16(modbusdata, length)
local i=0; local j=0; local crc=0; local k=1; local k=1; local l=1;
for k=1, length then
crc = bit.bxor(crc, modbusdata[k])
for l=1, 8 do
if bit.band(crc, 1) == 1 then
crc = bit.rshift(crc, 1)
crc = bit.bxor(crc, 0xa001)
else
crc = bit.rshift(crc, 1)
end
end
end
return crc
end
当然还有一种简单的直接调用API
的方法<这里>。
...
local RevLen = string.len(data)
local crc = ow.crc16(string.sub(data,1,RevLen-2))
...
但是吧,两者有点区别,API
文档也做了说明
- 第一个就是
API
函数得到的CRC
是按位反转传输的。 - 第二个就是高低字节顺序可能不一样。
③、C#
上位机的CRC16校验
private int crc16_modbus(byte[] modbusdata, int length)
{
int i,j;
int crc = 0;
try
{
for(i=0; i<length; i++)
{
crc^=modbusdata[i];
for(j=0; i<8; j++)
{
if(crc & 0x01 == 1)
{
crc = (crc >> 1) ^ 0xa001;
}
else
{
crc >>= 1;
}
}
}
}
catch(Exception)
{
throw;
}
return crc;
}
/// <CRC校验正确标志>
///
/// </summary>
private int crc16_flage(byte[] modbusdata, int length)
{
int Receive_CRC = 0, calculation = 0;//接收到的CRC,计算的CRC
Receive_CRC = crc16_modbus(modbusdata, length);
calculation = modbusdata[length + 1];
calculation <<= 8;
calculation += modbusdata[length];
if (calculation != Receive_CRC)
{
return 0;
}
return 1;
}
④、Android
上的CRC16校验
/**
* CRC检验值
* @param modbusdata
* @param length
* @return CRC检验值
*/
protected int crc16_modbus(byte[] modbusdata, int length)
{
int i=0, j=0;
int crc = 0;
try
{
for (i = 0; i < length; i++)
{
crc ^= (modbusdata[i]&(0xff));//注意这里要&0xff
for (j = 0; j < 8; j++)
{
if ((crc & 0x01) == 1)
{
crc = (crc >> 1) ;
crc = crc ^ 0xa001;
}
else
{
crc >>= 1;
}
}
}
}
catch (Exception e)
{
}
return crc;
}
/**
* CRC校验正确标志
* @param modbusdata
* @param length
* @return 0-failed 1-success
*/
protected int crc16_flage(byte[] modbusdata, int length)
{
int Receive_CRC = 0, calculation = 0;//接收到的CRC,计算的CRC
Receive_CRC = crc16_modbus(modbusdata, length);
calculation = modbusdata[length + 1];
calculation <<= 8;
calculation += modbusdata[length];
if (calculation != Receive_CRC)
{
return 0;
}
return 1;
}