计算 CAN 总线的 CRC 15
Calculate CRC 15 for CAN BUS
我需要计算 CAN 总线的 CRC 校验和。
场景:
我的输入看起来总是如下所示(其中 x
是 1
或 0
,*
多次标记 x
,|
表示一个段,-
是输入法的改变,lb
是Label
,tb
是TextBox
,cb
是ComboBox
):
lb
: 0
tb
: 11x
cb
: x
cb
: x
lb
: 1
tb
: 4x => Convert.ToString(8-64 / 8, 2).PadLeft(4, '0');
tb
:8-64x,=> 8-64 % 8 == 0
tb
: 15x => CRC of above
lb
: 1
lb
: 11
lb
: 1111111
lb
: 111
哪个returns这个布局:
0|11*x-x|x-1-4*x|64*x|15*x-1|11|1111111|111
示例:
00101010101000100100101010100101010(missing 15*x CRC sum)1111111111111
此字符串将由以下字符串扩展处理,因此最多 5 个相同的数字相互跟随:
public static string Correct4CRC(this string s)
{
return s.Replace("00000", "000001").Replace("11111", "111110");
}
在下面的方法之后 returns 除数:
public static BigInteger CreateDivisor(string s)
{
var i = BigInteger.Parse(s);
var d = BigInteger.Pow(i, 15) + BigInteger.Pow(i, 14) + BigInteger.Pow(i, 10) + BigInteger.Pow(i, 8) + BigInteger.Pow(i, 7) + BigInteger.Pow(i, 4) + BigInteger.Pow(i, 3) + 1;
return d;
}
我遇到的唯一问题是 ^
的部分:
public static string CRC(this string s)
{
var dd = s.Correct4CRC();
var dr = dd.CreateDivisor().ToString();
int drl = dr.Length;
var d = dd.Substring(0, drl).CreateDivisor();
var f = d ^ dr.CreateDivisor();
var p = true;
while (p)
{
d = dd.Substring(0, drl).CreateDivisor();
f = d ^ dr.CreateDivisor();
p = d > dd.CreateDivisor();
}
return f.ToString();
}
我知道这可能会因为请求代码而关闭,但请耐心等待,因为我真的不明白。另一个问题是,没有 真正的 文档可以帮助我解决问题。
无论如何,如果您知道一个很好的文档,可以解决我的问题,请将其添加为评论。知道了我自己去看看,自己关闭答案。
我认为您的比特填充是错误的(将 00000 替换为 000001,将 11111 替换为 111110),因为它不处理雪崩替换... 0000011110000 变为 0000011111000001。
此处http://blog.qartis.com/can-bus/ there seems to be an example. The page is then linked to http://ghsi.de/CRC/index.php?Polynom=1100010110011001&Message=2AA80生成一些用于计算 CRC-15 的 C 代码。
// 0000011110000 becomes 0000011111000001
public static string BitStuff(string bits)
{
StringBuilder sb = null;
char last = ' ';
int count = 0;
for (int i = 0; i < bits.Length; i++)
{
char ch = bits[i];
if (ch == last)
{
count++;
if (count == 5)
{
if (sb == null)
{
// The maximum length is equal to the length of bits
// plus 1 for length 5, 2 for length 9, 3 for length 13...
// This because the maximum expanion is for
// 00000111100001111... or 11111000011110000...
sb = new StringBuilder(bits.Length + (bits.Length - 1) / 4);
sb.Append(bits, 0, i);
}
sb.Append(ch);
last = ch == '0' ? '1' : '0';
sb.Append(last);
count = 1;
continue;
}
}
else
{
last = ch;
count = 1;
}
if (sb != null)
{
sb.Append(ch);
}
}
return sb != null ? sb.ToString() : bits;
}
// Taken from http://ghsi.de/CRC/index.php?Polynom=1100010110011001&Message=2AA80
public static string Crc15(string bits)
{
var res = new char[15]; // CRC Result
var crc = new bool[15];
for (int i = 0; i < bits.Length; i++)
{
bool doInvert = (bits[i] == '1') ^ crc[14]; // XOR required?
crc[14] = crc[13] ^ doInvert;
crc[13] = crc[12];
crc[12] = crc[11];
crc[11] = crc[10];
crc[10] = crc[9] ^ doInvert;
crc[9] = crc[8];
crc[8] = crc[7] ^ doInvert;
crc[7] = crc[6] ^ doInvert;
crc[6] = crc[5];
crc[5] = crc[4];
crc[4] = crc[3] ^ doInvert;
crc[3] = crc[2] ^ doInvert;
crc[2] = crc[1];
crc[1] = crc[0];
crc[0] = doInvert;
}
// Convert binary to ASCII
for (int i = 0; i < 15; i++)
{
res[14 - i] = crc[i] ? '1' : '0';
}
return new string(res);
}
然后:
string bits = "0101010101010000000"; // Example data
string crc = Crc15(bits);
bits = bits + crc;
bits = BitStuff(bits);
bits += '1'; // CRC delimiter
bits += 'x'; // ACK slot TODO
bits += '1'; // ACK delimiter
bits += "1111111"; // EOF
请注意,您必须输入 ACK 槽的值
我需要计算 CAN 总线的 CRC 校验和。
场景:
我的输入看起来总是如下所示(其中 x
是 1
或 0
,*
多次标记 x
,|
表示一个段,-
是输入法的改变,lb
是Label
,tb
是TextBox
,cb
是ComboBox
):
lb
: 0tb
: 11xcb
: xcb
: xlb
: 1tb
: 4x =>Convert.ToString(8-64 / 8, 2).PadLeft(4, '0');
tb
:8-64x,=>8-64 % 8 == 0
tb
: 15x =>CRC of above
lb
: 1lb
: 11lb
: 1111111lb
: 111
哪个returns这个布局:
0|11*x-x|x-1-4*x|64*x|15*x-1|11|1111111|111
示例:
00101010101000100100101010100101010(missing 15*x CRC sum)1111111111111
此字符串将由以下字符串扩展处理,因此最多 5 个相同的数字相互跟随:
public static string Correct4CRC(this string s)
{
return s.Replace("00000", "000001").Replace("11111", "111110");
}
在下面的方法之后 returns 除数:
public static BigInteger CreateDivisor(string s)
{
var i = BigInteger.Parse(s);
var d = BigInteger.Pow(i, 15) + BigInteger.Pow(i, 14) + BigInteger.Pow(i, 10) + BigInteger.Pow(i, 8) + BigInteger.Pow(i, 7) + BigInteger.Pow(i, 4) + BigInteger.Pow(i, 3) + 1;
return d;
}
我遇到的唯一问题是 ^
的部分:
public static string CRC(this string s)
{
var dd = s.Correct4CRC();
var dr = dd.CreateDivisor().ToString();
int drl = dr.Length;
var d = dd.Substring(0, drl).CreateDivisor();
var f = d ^ dr.CreateDivisor();
var p = true;
while (p)
{
d = dd.Substring(0, drl).CreateDivisor();
f = d ^ dr.CreateDivisor();
p = d > dd.CreateDivisor();
}
return f.ToString();
}
我知道这可能会因为请求代码而关闭,但请耐心等待,因为我真的不明白。另一个问题是,没有 真正的 文档可以帮助我解决问题。
无论如何,如果您知道一个很好的文档,可以解决我的问题,请将其添加为评论。知道了我自己去看看,自己关闭答案。
我认为您的比特填充是错误的(将 00000 替换为 000001,将 11111 替换为 111110),因为它不处理雪崩替换... 0000011110000 变为 0000011111000001。
此处http://blog.qartis.com/can-bus/ there seems to be an example. The page is then linked to http://ghsi.de/CRC/index.php?Polynom=1100010110011001&Message=2AA80生成一些用于计算 CRC-15 的 C 代码。
// 0000011110000 becomes 0000011111000001
public static string BitStuff(string bits)
{
StringBuilder sb = null;
char last = ' ';
int count = 0;
for (int i = 0; i < bits.Length; i++)
{
char ch = bits[i];
if (ch == last)
{
count++;
if (count == 5)
{
if (sb == null)
{
// The maximum length is equal to the length of bits
// plus 1 for length 5, 2 for length 9, 3 for length 13...
// This because the maximum expanion is for
// 00000111100001111... or 11111000011110000...
sb = new StringBuilder(bits.Length + (bits.Length - 1) / 4);
sb.Append(bits, 0, i);
}
sb.Append(ch);
last = ch == '0' ? '1' : '0';
sb.Append(last);
count = 1;
continue;
}
}
else
{
last = ch;
count = 1;
}
if (sb != null)
{
sb.Append(ch);
}
}
return sb != null ? sb.ToString() : bits;
}
// Taken from http://ghsi.de/CRC/index.php?Polynom=1100010110011001&Message=2AA80
public static string Crc15(string bits)
{
var res = new char[15]; // CRC Result
var crc = new bool[15];
for (int i = 0; i < bits.Length; i++)
{
bool doInvert = (bits[i] == '1') ^ crc[14]; // XOR required?
crc[14] = crc[13] ^ doInvert;
crc[13] = crc[12];
crc[12] = crc[11];
crc[11] = crc[10];
crc[10] = crc[9] ^ doInvert;
crc[9] = crc[8];
crc[8] = crc[7] ^ doInvert;
crc[7] = crc[6] ^ doInvert;
crc[6] = crc[5];
crc[5] = crc[4];
crc[4] = crc[3] ^ doInvert;
crc[3] = crc[2] ^ doInvert;
crc[2] = crc[1];
crc[1] = crc[0];
crc[0] = doInvert;
}
// Convert binary to ASCII
for (int i = 0; i < 15; i++)
{
res[14 - i] = crc[i] ? '1' : '0';
}
return new string(res);
}
然后:
string bits = "0101010101010000000"; // Example data
string crc = Crc15(bits);
bits = bits + crc;
bits = BitStuff(bits);
bits += '1'; // CRC delimiter
bits += 'x'; // ACK slot TODO
bits += '1'; // ACK delimiter
bits += "1111111"; // EOF
请注意,您必须输入 ACK 槽的值