CRC16校验的学习

一、CRC16算法快速了解

一般一些工业上仪器仪表都会选择CRC16校验,而写程序对帧数据的校验也需要选择CRC16校验看看对不对。所以选择CRC16校验还是很有必要的。

这里写图片描述

当然CRC2字节的,具体存储方式大端存储还是小端存储,不同机器不一样。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;
}

猜你喜欢

转载自blog.csdn.net/ReCclay/article/details/78168704