我刚刚开始研究CRC以及如何在软件中实现它。我的信息来源主要是以下文件。这里提到了一些用于生成器多项式的CRC计算的简单算法。我想用C ++语言编写此算法。我已经使用此在线计算器对生成多项式x ^ 5 + x ^ 4 + x ^ 2 +1(CRC-5)(芯片使用的生成多项式)进行了测试,并且可以正常工作。
#include <iostream>
using namespace std;
int main() {
uint8_t data_byte = 0x31;
// polynom x^5 + x^4 + x^2 + 1
uint16_t polynom = 0x35;
// register contains 0 at the beginning
uint32_t crc = 0;
uint32_t message = 0;
// shift the message byte to left by so many bits which is needed for generator polynomial
message = (data_byte << 5);
// now the message byte is 13 bits long
uint8_t processed_bit = 13;
while(processed_bit > 0) {
// prepare free space for new bit from the message byte
crc = crc << 1;
// find out value of current msb in the message byte
message = message << 1;
if(message & 0x2000) {
// msb in message byte is "1"
// lsb in register is set to "1"
crc |= 1U;
} else {
// msb in message byte is "0"
// lsb in register is set to "0"
crc &= ~1U;
}
// remove msb from message byte
message = message & ~0x2000;
if(crc & 0x20) {
// subtract current multiple of the generator polynomial
crc = crc ^ polynom;
}
// remove msb from the register
crc = crc & ~0x20;
processed_bit--;
}
cout << "CRC: " << (int)crc << endl;
return 0;
}
很明显,该程序就执行时间而言无效。因此,我一直在考虑从此角度改进它的可能性。我知道可以使用包含预先计算的提醒的查找表的一种变体,但我想避免使用此方法。从执行时间的角度来看,有人知道如何改进上述算法吗?在此先感谢你的任何建议。
快速浏览即可看到一些不必要的陈述。你不需要crc &= ~1U;
,因为crc = crc << 1;
已经在其中放置了零。你不需要message = message & ~0x2000;
,因为你只需要看一眼即可。只是让其他位向上和向后移动。你不需要crc = crc & ~0x20;
,因为与多项式的异或运算已经完成了。
如果阅读了链接的文档,你将发现不需要再处理五个位(总共13个位)。你只需要处理八个消息位。同时阅读该文档,你无需一次输入一个消息位。你可以将消息字节直接异或或直接放入CRC寄存器,然后处理寄存器中的所有8位。
最后,你可以通过查表来显着加快计算速度,一次处理八个位,而不是一次处理一个位。你链接的文档中也对此进行了漂亮的描述。你可以在此处找到代码,以自动生成用于计算的表和C代码。
最后,如果你没有计算正确的开始,那么这一切都无关紧要。你需要首先使用芯片中的数据来验证计算结果。我找到了该文档,其中包含有关该芯片的CRC计算的详细信息。你需要花一些时间并详细了解它。
为了直接回答你的问题,这里有一些代码可以完成你的代码,但是要简单得多。此外,它还可以工作在n位上,而不仅仅是8位。它执行n个循环,而不是n + 5个循环:
// Return a CRC-5 of the low n bits of data. The remaining bits of data must be
// zero. n must be in [5..32].
uint8_t crc5(uint32_t data, int n) {
int shift = n - 5;
uint32_t poly = (uint32_t)0x15 << shift;
uint32_t top = (uint32_t)1 << (n - 1);
do {
data = data & top ? (data << 1) ^ poly : data << 1;
} while (--n);
return (data >> shift) & 0x1f;
}
更简单,更快捷的是,相当于你将其限制为展开的八位:
uint8_t crc5_8(uint8_t data) {
data = data & 0x80 ? (data << 1) ^ 0xa8 : data << 1;
data = data & 0x80 ? (data << 1) ^ 0xa8 : data << 1;
data = data & 0x80 ? (data << 1) ^ 0xa8 : data << 1;
data = data & 0x80 ? (data << 1) ^ 0xa8 : data << 1;
data = data & 0x80 ? (data << 1) ^ 0xa8 : data << 1;
data = data & 0x80 ? (data << 1) ^ 0xa8 : data << 1;
data = data & 0x80 ? (data << 1) ^ 0xa8 : data << 1;
data = data & 0x80 ? (data << 1) ^ 0xa8 : data << 1;
return data >> 3;
}
但是,任何人都无法计算出所需的芯片。
无法将此进一步优化为以下多项式特定的序列:和,移位,xor语句。由于存在3个非零项x ^ 4 + x ^ 2 +1,我在考虑3个序列集,
and
因此不需要一些序列,因为不需要的位将被移出。去吧......
由于可能会为8位数据生成5位CRC,因此可能会超过3组。我在想类似于针对表查找进行的硬件优化。在这种情况下,可以使用相同的代码(与CRC多项式中的01模式相对应)计算成对的比特。