我要连接到一个设备(MODBUS协议),我必须计算CRC(CRC16)。有此协议的标准实现,但是我有使用此公式创建我CRC:奇怪的CRC计算
X15 + X2 + 1(有一个与此公式标准实现:X16 + X15 + X2 + 1)
我已经测试了不同的CRC值,但他们都没有给我正确的答案。我应该向端口写入一些字节,并且在该字节串的末尾,我应该写入两个CRC字节以获取我的设备信息。
我要连接到一个设备(MODBUS协议),我必须计算CRC(CRC16)。有此协议的标准实现,但是我有使用此公式创建我CRC:奇怪的CRC计算
X15 + X2 + 1(有一个与此公式标准实现:X16 + X15 + X2 + 1)
我已经测试了不同的CRC值,但他们都没有给我正确的答案。我应该向端口写入一些字节,并且在该字节串的末尾,我应该写入两个CRC字节以获取我的设备信息。
你的问题是什么? 我假设您的问题是“如何在消息结尾计算MODBUS CRC,以便电缆另一端的MODBUS设备将其识别为有效的MODBUS消息?”
在我实现另一个校验和或CRC函数之前,我试着首先获取测试向量, 。
您是否有任何有效消息的例子,包括最终的正确/期望的CRC?
根据Wikipedia:cyclic redundancy check, “由于高序位始终为1,并且由于n位CRC必须由第(n + 1)比特的除数,其溢出的n位寄存器所定义,一些作者认为没有必要提到除数的高位。“因此,说MODBUS使用“X^15 + X^2 + 1”多项式(由于它是16位CRC,因此理解为X^16)的作者指的是与其他作者完全相同的多项式即MODBUS使用“X^16 + X^15 + X^2 + 1”多项式。两位作者都将编写生成完全相同CRC的代码,并且可以相互交互操作。
另外,在“前进”方向计算标准MODBUS CRC的人经常使用魔术常数“0x8005”。 那些在“反向”方向计算标准MODBUS CRC的人经常使用魔术常数“0xA001”代替(“0x8005”的位反转)。 两个人都编写的代码能够生成完全相同的CRC字节,并且可以相互交互操作。
MODBUS CRC计算有许多在线实现;也许你可能会发现其中一个有用。
abcdefghi:有许多选项 http://www.zorc.breitbandkatze.de/crc.html
在线CRC计算 http://www.lammertbies.nl/comm/info/crc-calculation.html
和许多人一样,没有特定的顺序
许多实现是面向字节的,它运行快一点,但需要一个大的查找表 (和它的对我来说远不是显而易见的查找表如何测试是否有效)。
许多实现是面向比特的,其产生短得多的程序大小 和具有更少的尘土飞扬角落里的错误可以潜伏(但采取只要计算校验和大约8倍),如下面的:
// warning: untested code
// optimized for size rather than speed
// (i.e., uses a bit-oriented calculation rather than table-driven calculation)
uint16_t modbusCRC(uint8_t* data, int length) {
uint16_t crc = 0xFFFF;
for(int pos = 0; pos<length; pos++){
crc ^= (uint16_t)data[pos];
for(int i=0; i<8; i++){
if(crc & 1){ // LSB is set
crc >>= 1; // Shift right
crc ^= 0xA001; // XOR 0xA001
}else{ // LSB is not set
crc >>= 1;
};
};
};
return crc;
}
int main(void){
uint8_t message[80] = { // 6-byte test vector
0x11, 0x03, 0x00, 0x6B, 0x00, 0x03
};
int message_length = 6;
uint16_t the_CRC = modbusCRC(message, message_length); // find CRC of the message
message[message_length++] = the_CRC & 0xFF; // send low byte first
message[message_length++] = the_CRC >> 8; // then send high byte
assert(0x76 == message[6]); // test against known-good CRC
assert(0x87 == message[7]);
send_message(message, message_length); // send all 8 bytes of the message,
// including the two MODBUS CRC bytes.
// (Must send *all* 8 bytes of the message,
// even though there are multiple 0x00 bytes).
}
“二进制MODBUS”(“Modbus RTU帧格式”)将消息的所有数据作为原始8位字节发送,包括2个CRC字节。
“ASCII MODBUS”(“Modbus ASCII帧格式”)以大致简单的ASCII文本(包括8位校验和)发送消息。 (校验和传输为2个字节 - 作为2个ASCII十六进制字符)。
那么问题是什么? – Amy
我的问题是关于使用X15 + X2 + 1公式找到CRC的正确方法,我应该如何将这些字节写入我的端口?我使用C#(VS2010),我应该使用port.write还是port.writeline?我应该如何将这些字节传递给端口? ascii字符串还是hex?谢谢 –
您应该将字节作为原始二进制字符串(您可以从字节数组中形成)传递,既不是ASCII字符串也不是十六进制。你可以使用Port.Write。您可能需要使用[Port.ByteArrayToString](http://franson.com/serialtools/reference_manual.asp?class=Port&item=ByteArrayToString&platform=net)。 –