当前位置: 首页 > 知识库问答 >
问题:

用C#计算CRC16

呼延升
2023-03-14

我试图将一个旧代码从C移植到C#,它基本上接收一个字符串并返回一个CRC16...

#define CRC_MASK 0x1021 /* x^16 + x^12 + x^5 + x^0 */

UINT16 CRC_Calc (unsigned char *pbData, int iLength)
{
    UINT16 wData, wCRC = 0;
    int i;

    for ( ;iLength > 0; iLength--, pbData++) {
        wData = (UINT16) (((UINT16) *pbData) << 8);
        for (i = 0; i < 8; i++, wData <<= 1) {
            if ((wCRC ^ wData) & 0x8000)
                wCRC = (UINT16) ((wCRC << 1) ^ CRC_MASK);
            else
                wCRC <<= 1;
        }
    }
    return wCRC;
}

我的移植C#代码如下:

private static ushort Calc(byte[] data)
    {
        ushort wData, wCRC = 0;
        for (int i = 0; i < data.Length; i++)
        {
            wData = Convert.ToUInt16(data[i] << 8);
            for (int j = 0; j < 8; j++, wData <<= 1)
            {
                var a = (wCRC ^ wData) & 0x8000;
                if ( a != 0)
                {
                    var c = (wCRC << 1) ^ 0x1021;
                    wCRC = Convert.ToUInt16(c);
                }
                else
                {
                    wCRC <<= 1;
                }
            }
        }
        return wCRC;
    }

测试字符串是“OPN”...它必须返回一个uint,ofc)2字节a8a9,#CRC_MASK是该计算的多项式。我确实在这里和网上找到了几个CRC16的例子,但没有一个达到这个结果,因为这个CRC计算必须与我们连接的设备匹配。

错在哪里?我真的很感激任何帮助。

_serial = new SerialPort("COM6", 19200, Parity.None, 8, StopBits.One);
        _serial.Open();
        _serial.Encoding = Encoding.GetEncoding(1252);
        _serial.DataReceived += Serial_DataReceived;
        var msg = "OPN";
        var data = Encoding.GetEncoding(1252).GetBytes(msg);
        var crc = BitConverter.GetBytes(Calc(data));
        var msb = crc[0].ToString("X");
        var lsb = crc[1].ToString("X");
        //The following line must be something like: \x16OPN\x17\xA8\xA9
        var cmd = string.Format(@"{0}{1}{2}\x{3}\x{4}", SYN, msg, ETB, msb, lsb);
        //var cmd = "\x16OPN\x17\xA8\xA9";
        _serial.Write(cmd);

cmd变量的值是我试图发送到设备的值。如果您查看注释的cmd值,这是一个工作字符串。CRC16的2个字节包含在最后两个参数(msb和lsb)中。因此,在这里的示例中,msb必须为“\xa8”,lsb必须为“\xa9”,才能使命令工作(CRC16在设备上匹配)。

有线索吗?

再次感谢。

protected string ToMessage(string data)
    {
        var msg = data + ETB;
        var crc = CRC16.Compute(msg);
        var fullMsg = string.Format(@"{0}{1}{2:X}{3:X}", SYN, msg, crc[0], crc[1]);
        return fullMsg;
    }

共有1个答案

董建德
2023-03-14

这里的问题是,包含ETB(\x17)的消息长度为4字节(前导同步字节不用于CRC):“OPN\x17”=={'O','P','N',0x17},这导致将一个{0xA8,0xA9}的CRC附加到消息中。所以CRC函数是正确的,但是原始测试数据没有包括0x17的第4个字节。

这是一个工作示例(至少在VS2015 express中)。

private static ushort Calc(byte[] data)
{
    ushort wCRC = 0;
    for (int i = 0; i < data.Length; i++)
    {
        wCRC ^= (ushort)(data[i] << 8);
        for (int j = 0; j < 8; j++)
        {
            if ((wCRC & 0x8000) != 0)
                wCRC = (ushort)((wCRC << 1) ^ 0x1021);
            else
                wCRC <<= 1;
        }
    }
    return wCRC;
}
 类似资料:
  • 问题内容: 有没有一种方法可以使用C计算文件中的行数? 问题答案: 如果要以编程方式执行此操作,请以文本模式打开文件并执行fgetc()操作,直到到达文件末尾。记下调用fgetc的次数。

  • b)从给定的timeuuid返回DateTime c)查找给定日期时间的MaxTimeUuid和MinTimeUuid 对于a)和b),我找到了这个链接,它为我提供了一个具有所需功能的结构。

  • 我有一个通过RS232 COM与计算机通信的终端。我得到的协议说,我必须发送一定的字节组合和CRC 16 IBM计算的数据在最后发送 我还得到了一个C编写的应用程序,我可以用它来测试,该应用程序编写了一个带有发送数据和接收数据的日志。在该日志中,我查看是否向终端发送了以下字符串。我还必须发送数据06 35的这个CRC16 IBM结果。 我已经设法以某种方式将作为示例给出的C方法翻译成C#。但我的结

  • 本文向大家介绍用C ++计算阶乘中的位数,包括了用C ++计算阶乘中的位数的使用技巧和注意事项,需要的朋友参考一下 给我们一个整数值,任务是首先计算一个数字的阶乘,然后计算结果中的总位数。 什么是阶乘数 数字的阶乘是通过将数字中的数字相乘,同时将数字的值减1来计算的。它由符号“!”表示 即0!,1!,2!,3!,5!,....等 0阶乘!和1!始终为1。 例如 说明-由于阶乘值6是720并且包含3

  • 最简单的经验法则之一是记住硬件喜欢数组,并且针对数组的迭代进行了高度优化。对许多问题的一个简单优化只是停止使用花哨的数据结构,只使用简单的数组(或C++中的std::vectors)。这需要一些时间来适应。 C++类是那种“奇特的数据结构”,即一种可以用数组代替的数据类型,以在C++程序中获得更高的性能吗?