Arduino和EPOS之间的串行通信:CRC计算问题

时间:2016-06-04 00:01:44

标签: arduino serial-port crc

我试图通过RS232串口与一个带有Arduino Duemilanove的EPOS2电机控制器接口(因为它就是我躺在那里)。我让它在大多数情况下工作 - 当我手动计算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;
}

我使用以下链接计算适用于此数据的校验和:

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

非常感谢!!

1 个答案:

答案 0 :(得分:0)

从哪里开始。

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

其次,你的第一个单词的构建是从你的其他构建向后。您的在线CRC遇到了同样的问题,因此您显然没有可靠的测试用例。

第三个(对于测试用例不是问题),如果你有一个奇数个输入字节,你正在进行comms的越界访问以填写最后一个字。并且您运行CRC位太多次,除非规范在这种情况下指向某种填充。 (您的文档链接已损坏,因此我无法查看应该发生的事情。)即使这样,您也会使用随机数据进行填充而不是零。

无论如何,整个单词转换是浪费时间。考虑到字节的正确排序,您可以一次执行一个字节。这也避免了奇数个字节的问题。这将从你给出在线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;
}