【问题标题】:How to generate a CRC-16 from C#如何从 C# 生成 CRC-16
【发布时间】:2014-05-16 14:57:03
【问题描述】:

我正在尝试使用 C# 生成 CRC-16。我用于 RS232 的硬件要求输入字符串为 HEX。下面的截图显示了正确的转换,为了测试,我需要 8000 为 0xC061,但是生成 CRC-16 的 C# 方法必须能够转换任何给定的 HEX 字符串。

我尝试过使用 Nito.KitchenSink.CRC

我也试过下面的,当输入 8000 时会生成 8009 -

public string CalcCRC16(string strInput)
    {
        ushort crc = 0x0000;
        byte[] data = GetBytesFromHexString(strInput);
        for (int i = 0; i < data.Length; i++)
        {
            crc ^= (ushort)(data[i] << 8);
            for (int j = 0; j < 8; j++)
            {
                if ((crc & 0x8000) > 0)
                    crc = (ushort)((crc << 1) ^ 0x8005);
                else
                    crc <<= 1;
            }
        }
        return crc.ToString("X4");
    }

    public Byte[] GetBytesFromHexString(string strInput)
    {
        Byte[] bytArOutput = new Byte[] { };
        if (!string.IsNullOrEmpty(strInput) && strInput.Length % 2 == 0)
        {
            SoapHexBinary hexBinary = null;
            try
            {
                hexBinary = SoapHexBinary.Parse(strInput);
                if (hexBinary != null)
                {
                    bytArOutput = hexBinary.Value;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        return bytArOutput;
    }

【问题讨论】:

  • 好的,所以有一些代码可以生成 CRC(我假设)。具体的问题/疑问是什么?
  • 问题是生成的CRC不正确使用上面的代码。我将使用其当前输出更新问题。
  • 输入“8000” - 是十进制 8000、十六进制 8000 还是字符串“8000”?
  • 设备要求为HEX
  • @MattBaughan 不,这不是问题;计算机实际上不会以十六进制或十进制或其他任何方式说话。他们只有数字。我需要知道的是:you(不是机器)所说的 8000 是什么意思? CRC 在字节上运行。我需要知道我们正在散列的字节序列。我什至无需尝试就可以将 8000 解释为大约 15 个字节的序列。我需要知道哪个。

标签: c# crc crc16


【解决方案1】:

我们来了;请注意,这是 CRC-16 的特定风格 - 仅说“CRC-16”会令人困惑。这从 http://www.sanity-free.com/ 借用了一些实现细节 - 请注意,我已将其设为 static 而不是基于实例的。

using System;

static class Program
{
    static void Main()
    {
        string input = "8000";
        var bytes = HexToBytes(input);
        string hex = Crc16.ComputeChecksum(bytes).ToString("x2");
        Console.WriteLine(hex); //c061
    }
    static byte[] HexToBytes(string input)
    {
        byte[] result = new byte[input.Length / 2];
        for(int i = 0; i < result.Length; i++)
        {
            result[i] = Convert.ToByte(input.Substring(2 * i, 2), 16);
        }
        return result;
    }

    public static class Crc16
    {
        const ushort polynomial = 0xA001;
        static readonly ushort[] table = new ushort[256];

        public static ushort ComputeChecksum(byte[] bytes)
        {
            ushort crc = 0;
            for (int i = 0; i < bytes.Length; ++i)
            {
                byte index = (byte)(crc ^ bytes[i]);
                crc = (ushort)((crc >> 8) ^ table[index]);
            }
            return crc;
        }

        static Crc16()
        {
            ushort value;
            ushort temp;
            for (ushort i = 0; i < table.Length; ++i)
            {
                value = 0;
                temp = i;
                for (byte j = 0; j < 8; ++j)
                {
                    if (((value ^ temp) & 0x0001) != 0)
                    {
                        value = (ushort)((value >> 1) ^ polynomial);
                    }
                    else
                    {
                        value >>= 1;
                    }
                    temp >>= 1;
                }
                table[i] = value;
            }
        }
    }
}

【讨论】:

  • 嗨,这对我不起作用,这条线 result[i] = Convert.ToByte(input.Substring(2 * i, 2), 16); 第二个参数期待 System.IFormatProvider 值,其中 16 显然不是其中之一。
  • @Shaun 方法肯定存在于完整的框架中:msdn.microsoft.com/en-us/library/c7xhf79k(v=vs.110).aspx - 你可能在使用 .net 核心吗?还是另一个简化的框架?
  • 似乎计算错误的值。至少它们与我从 Atmel AVR 上的 CRC16 函数中得到的不匹配。现在正在寻找另一个来源。
  • @ygoe 我特意开始发帖,强调有多种称为 CRC16 的算法不兼容;知道你的意思是非常重要的。很可能,我们在这里指的是不同的。
【解决方案2】:

另外,如果你想要CRC16-CCITT。

private ushort Crc16Ccitt(byte[] bytes)
{
    const ushort poly = 4129;
    ushort[] table = new ushort[256];
    ushort initialValue = 0xffff;
    ushort temp, a;
    ushort crc = initialValue;
    for (int i = 0; i < table.Length; ++i)
    {
        temp = 0;
        a = (ushort)(i << 8);
        for (int j = 0; j < 8; ++j)
        {
            if (((temp ^ a) & 0x8000) != 0)
                temp = (ushort)((temp << 1) ^ poly);
            else
                temp <<= 1;
            a <<= 1;
        }
        table[i] = temp;
    }
    for (int i = 0; i < bytes.Length; ++i)
    {
        crc = (ushort)((crc << 8) ^ table[((crc >> 8) ^ (0xff & bytes[i]))]);
    }
    return crc;
}

【讨论】:

  • Crc16Ccitt(Encoding.ASCII.GetBytes("123456789")).ToString("X") 返回29B1。根据这个webpage,实现是不正确的。
  • initialValue 更改为0x0x1D0F 似乎可行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-09
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
  • 2018-10-01
  • 1970-01-01
相关资源
最近更新 更多