首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用于计算CRC16校验和的函数

用于计算CRC16校验和的函数
EN

Stack Overflow用户
提问于 2012-05-12 22:13:48
回答 7查看 228.7K关注 0票数 56

我正在开发一个库,以便在RS232或RS485连接上提供简单可靠的通信。此代码的一部分涉及对数据使用CRC16校验和来检测线路噪声中的损坏。我已经创建了一个函数来计算CRC16校验和,但是它似乎没有输出正确的值。

我写的相关代码如下(也可以在here中找到)。

代码语言:javascript
复制
#include <stdint.h>

#define CRC16 0x8005

uint16_t gen_crc16(const uint8_t *data, uint16_t size)
{
    uint16_t out = 0;
    int bits_read = 0, bit_flag;

    /* Sanity check: */
    if(data == NULL)
        return 0;

    while(size > 0)
    {
        bit_flag = out >> 15;

        /* Get next bit: */
        out <<= 1;
        out |= (*data >> (7 - bits_read)) & 1;

        /* Increment bit counter: */
        bits_read++;
        if(bits_read > 7)
        {
            bits_read = 0;
            data++;
            size--;
        }

        /* Cycle check: */
        if(bit_flag)
            out ^= CRC16;
    }

    return out;
}

我正在对照this online CRC calculator检查我的输出。

我得出的结论是,要么是我对如何计算CRC16的理解错了,要么是在线计算器错了(前者似乎更有可能)。谁能告诉我我可能会错在哪里?

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2012-05-13 14:59:50

对于特定的CRC实现,有几个细节需要“匹配”-即使使用相同的多项式,也可能会有不同的结果,因为如何处理数据比特,使用CRC的特定初始值(有时是0,有时是0xffff)和/或颠倒CRC的比特。例如,有时一个实现将从数据字节的低位向上工作,而有时它们将从高位向下工作(就像您目前所做的那样)。

此外,在运行完所有数据位之后,您还需要“推出”CRC的最后一位。

请记住,CRC算法是为在硬件中实现而设计的,因此从软件的角度来看,一些位排序的处理方式可能没有太大意义。

如CRC16计算器页面所示,如果要将CRC16与多项式0x8005进行匹配,则需要对lammertbies.nl函数进行以下更改:

  • a)从最低有效位开始运行数据位,而不是从最高有效位开始
  • b)在完成输入数据
  • 之后,将CRC的最后16位推出CRC寄存器c)颠倒CRC位(我猜测这个位是从硬件implementations)

进位的

因此,您的函数可能如下所示:

代码语言:javascript
复制
#define CRC16 0x8005

uint16_t gen_crc16(const uint8_t *data, uint16_t size)
{
    uint16_t out = 0;
    int bits_read = 0, bit_flag;

    /* Sanity check: */
    if(data == NULL)
        return 0;

    while(size > 0)
    {
        bit_flag = out >> 15;

        /* Get next bit: */
        out <<= 1;
        out |= (*data >> bits_read) & 1; // item a) work from the least significant bits

        /* Increment bit counter: */
        bits_read++;
        if(bits_read > 7)
        {
            bits_read = 0;
            data++;
            size--;
        }

        /* Cycle check: */
        if(bit_flag)
            out ^= CRC16;

    }

    // item b) "push out" the last 16 bits
    int i;
    for (i = 0; i < 16; ++i) {
        bit_flag = out >> 15;
        out <<= 1;
        if(bit_flag)
            out ^= CRC16;
    }

    // item c) reverse the bits
    uint16_t crc = 0;
    i = 0x8000;
    int j = 0x0001;
    for (; i != 0; i >>=1, j <<= 1) {
        if (i & out) crc |= j;
    }

    return crc;
}

当我传入"123456789"时,该函数会为我返回0xbb3d

票数 64
EN

Stack Overflow用户

发布于 2014-05-19 03:43:03

下面是计算crc16 CCITT的工作代码。我测试了它,结果与http://www.lammertbies.nl/comm/info/crc-calculation.html提供的结果相匹配。

代码语言:javascript
复制
unsigned short crc16(const unsigned char* data_p, unsigned char length){
    unsigned char x;
    unsigned short crc = 0xFFFF;

    while (length--){
        x = crc >> 8 ^ *data_p++;
        x ^= x>>4;
        crc = (crc << 8) ^ ((unsigned short)(x << 12)) ^ ((unsigned short)(x <<5)) ^ ((unsigned short)x);
    }
    return crc;
}
票数 49
EN

Stack Overflow用户

发布于 2012-05-13 01:10:45

CRC-16有几个不同的变种。参见wiki page

其中每一个都将从相同的输入返回不同的结果。

所以你必须仔细地为你的程序选择一个正确的。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10564491

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档