从字符串计算 Modbus RTU 的 CRC

calculate CRC for Modbus RTU from strings

我有字符串:02 03 04 50 00 01。我需要计算这个字符串的 CRC。

我有一个计算 CRC 的函数:

public static UInt16 ModRTU_CRC(ushort[] buf, int len)
        {
            UInt16 crc = 0xFFFF;

            for (int pos = 0; pos < len; pos++)
            {
                crc ^= (UInt16)buf[pos];

                for (int i = 8; i != 0; i--)
                {
                    if ((crc & 0x0001) != 0)
                    {
                        crc >>= 1;
                        crc ^= 0xA001;
                    }
                    else
                        crc >>= 1;
                }
            }
            return crc;
        }

我想将字符串转换为 ushort 数组:

ushort[] result = cmd.Split(' ').Select(item => Convert.ToUInt16(item, 16)).ToArray();

但是这样一个数组返回给我:2 3 4 80 0 1

请告诉我应该怎么做才能正确计算 CRC。

看来,你想合并两个byteushort,即对于给定的

  string cmd = "02 03 04 50 00 01";

你想得到

  {0x0203, 0x0405, 0x0001}

如果是你的话,

  using System.Linq;

  ...

  string cmd = "02 03 04 50 00 01";

  ushort[] result = cmd
    .Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
    .Select((value, index) => new { index, value = Convert.ToInt32(value, 16) })
    .GroupBy(item => item.index / 2, item => item.value)
    .Select(group => (UInt16)(group.Aggregate((s, a) => s * 256 + a)))
    .ToArray();

一起来看看:

  Console.WriteLine(string.Join(" ", data.Select(item => item.ToString("x4"))));

结果:

  0203 0450 0001

编辑:如果你想不合并skip项(见下面的评论),你可以尝试修改GroupBy:

  int skip = 2;

  ushort[] data = source
    .Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)
    .Select((value, index) => new { index, value = Convert.ToInt32(value, 16) })
    .GroupBy(item => item.index >= skip ? item.index / 2 : -item.index - 1, 
             item => item.value)
    .Select(group => (UInt16)(group.Aggregate((s, a) => s * 256 + a)))
    .ToArray();

  Console.WriteLine(string.Join(" ", data.Select(item => item.ToString("x4"))));

结果:0203 保持不变,04 结合 5000 01)

  0002 0003 0450 0001