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;
}
我正在尝试通过 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;
}