3

我必须为固件更新创建一个 CRC16 校验和。当我发送此数据时(从十六进制字符串转换为字节 [])

020000810000120000000002F001128100000C9462050C9481050C9481050C9481050C9481050C9481050C9481050C9481050C9481050C9481050C9481050C9

我从控制器得到以下 CRC16

-17514

现在我尝试在 Java 中检查这一点,但我无法获得相同的值。

这是 C 中的原始函数:

static uint16_t crc16_update(uint16_t crc, uint8_t a)
{
  crc ^= a;
  for (unsigned i = 0; i < 8; ++i) {
    if (crc & 1)
      crc = (crc >> 1) ^ 0xA001;
    else
      crc = (crc >> 1);
  }
  return crc;
}


static uint16_t crc16(const uint8_t *b, size_t l)
{
  uint16_t crc = 0;
  while (l-- > 0)
    crc = crc16_update(crc, *b++);
  return crc;
}

这是我在java中转换的函数:

public static int crc16_update(int crc, int a) {
    crc ^= a;
    for (int i = 0; i < 8; ++i) {
        if ((crc & 1) != 0) {
            crc = (crc >> 1) ^ 0xA001;
        } else {
            crc = (crc << 1);
        }
    }
    return crc;
}

public static int crc16(byte[] bytes) {
    int crc = 0;
    for (byte b:bytes) {
        crc = crc16_update(crc, b);
    }
    return crc;
}

...但它不起作用。它出什么问题了?

4

4 回答 4

1
public static int crc16_update(int crc, int a) {
    crc ^= a;
    for (int i = 0; i < 8; ++i) {
        if ((crc & 1) != 0) {
            crc = (crc >> 1) ^ 0xA001;
        } else {
            crc = (crc << 1);

正如looper 所提到的,你>> 1在 C 代码中有一个。

        }
    }
    return crc;
}

现在对于另一个功能:

public static int crc16(byte[] bytes) {
    int crc = 0;
    for (byte b:bytes) {
        crc = crc16_update(crc, b);

crc16_update在 Java 中采用 aint作为第二个参数,uint8_t在 C 中采用 a。当字节b设置了其最高有效/符号位时,该值为负数,因此当转换int为 的参数时crc16_update,符号扩展,因此您得到很多 1-您在 C 中没有的位。

您需要屏蔽除最低有效位 8 之外的所有位,

crc16_update(crc, ((int)b) & 0xFF);
于 2012-11-23T13:38:51.797 回答
0

尝试使用>>>运算符。

在 Java 中,这是无符号移位运算符,而不是>>保留符号。

另请注意,它uint16_t是 16 位类型,就像short在 Java 中一样。在重写在位级别上工作的算法时,尝试使用适当的位长度。

于 2012-11-23T12:50:03.817 回答
0

你的问题不是整数在java中签名,而是你使用了错误的数据类型。int有 32 位,您使用的算法对类型的数据大小很敏感。用于short16 位和byte8 位。

>>>如@Anony-Mousse 所述,在必要时还可以使用。

于 2012-11-23T12:52:21.490 回答
0

我找到了正确的方法。现在它工作了!我认为问题在于实习生在 short 和 int 之间进行转换。

public static int crc16_update(int crc, byte a) {
    crc ^= ((a+128) & 0xff);
    for (int i = 0; i < 8; ++i) {
        if ((crc & 1) != 0) {
            crc = ((crc >>> 1) ^ 0xA001) & 0xffff;
        }
        else {
            crc = (crc >>> 1) & 0xffff;
        }
    }
    return crc;
}

public static short crc16(byte[] bytes) {
    int crc = 0;
    for (byte b : bytes) {
        crc = crc16_update(crc, b);
    }
    return (short) crc;
}
于 2012-11-24T11:42:00.643 回答