Arduino与EPOS串口通信:CRC计算问题

Serial Communication Between Arduino and EPOS: CRC Calculation Problems

我正在尝试通过 RS232 串行接口与 EPOS2 电机控制器和 Arduino Duemilanove 接口(因为它就是我身边的东西)。我让它在大多数情况下工作——当我手动计算 CRC 校验和时,我可以发送和接收数据——但我试图动态控制需要更改数据的电机速度,因此,更改校验和。计算校验和的文档在这里,第 24 页:

http://www.maxonmotorusa.com/medias/sys_master/8806425067550/EPOS2-Communication-Guide-En.pdf

我直接从该文档中复制代码,并将其集成到我的代码中,它没有正确计算校验和。下面是我的完整草图的简化版本(经过测试,产生 0x527C)。最奇怪的是,它在我的完整草图中计算出的值与下面的不同,但两者都是错误的。有什么明显的我遗漏的东西吗?

byte comms[6] = { 0x10, 0x01, 0x03, 0x20, 0x01, 0x02 }; // CRC should be 0xA888

void setup() {
  Serial.begin(115200);
}

void loop() {
  calcCRC(comms, 6, true);
  while(1);
}

word calcCRC(byte *comms, int commsSize, boolean talkative) {
  int warraySize = commsSize / 2 + commsSize % 2;
  word warray[warraySize];

  warray[0] = comms[0] << 8 | comms[1];
  Serial.println(warray[0], HEX);

  for (int i = 1; i <= warraySize - 1; i++) {
    warray[i] = comms[i * 2 + 1] << 8 | comms[i * 2];
    Serial.println(warray[i], HEX);
  }

  word* warrayP = warray;

  word shifter, c;
  word carry;
  word CRC = 0;


  //Calculate pDataArray Word by Word
  while (commsSize--)
  {
    shifter = 0x8000;
    c = *warrayP ++;
    do {
      carry = CRC & 0x8000;
      CRC <<= 1;
      if (c & shifter) CRC++;
      if (carry) CRC ^= 0x1021;
      shifter >>= 1;
    } while (shifter);
  }

  if (talkative) {
    Serial.print("the CRC for this data is ");
    Serial.println(CRC, HEX);
  }

  return CRC;
}

我使用下面的 link 来计算适用于此数据的校验和:

https://www.ghsi.de/CRC/index.php?Polynom=10001000000100001&Message=1001+2003+0201

非常感谢!!

从哪里开始。

首先,您正在使用 commsSize-- 作为循环,当您在 warray 中只有三个单词时,循环将执行六次。因此,您正在对 warray 进行越界访问,并且必然会得到随机结果(或崩溃)。

其次,您第一个单词的构建与其他构建相反。你的在线 CRC 也遇到了同样的问题,所以你显然连一个可靠的测试用例都没有。

第三(对于测试用例来说不是问题),如果您有奇数个字节的输入,那么您正在对 comms 进行越界访问以填写最后一个单词。而且你 运行 CRC 位的次数太多了,除非规范在这种情况下指示某种填充。 (您的文档 link 已损坏,所以我看不到应该发生什么。)即便如此,您仍在使用随机数据而不是零作为填充。

无论如何,整个单词转换都是浪费时间。给定正确的字节顺序,您可以一次只执行一个字节。这也避免了奇数字节问题。这将从您提供给在线 CRC 计算器的输入中生成 0xa888(这些字节顺序混乱,但与您提供给计算器的顺序完全相同):

unsigned char dat[6] = { 0x10, 0x01, 0x20, 0x03, 0x02, 0x01 };

unsigned crc1021(unsigned char *dat, int len) {
    unsigned crc = 0;
    while (len) {
        crc ^= *dat++ << 8;
        for (int k = 0; k < 8; k++)
            crc = crc & 0x8000 ? (crc << 1) ^ 0x1021 : crc << 1;
        len--;
    }
    return crc & 0xffff;
}