关于CRC的问题,急急急急急急急急急急急急急急急急急急急急急急急……(200分)

  • 主题发起人 crazycock
  • 开始时间
C

crazycock

Unregistered / Unconfirmed
GUEST, unregistred user!
已知某一设备串口中传出的数据是经过CRC效验的,资料如下:
Byte Order DLE STX Command Network ID Zone ID Sector ID Data Length Data DLE ETX CRC
No Bytes 1 1 1 1 1 1 1 [0-128] 1 1 2

The CRC used is CRC-16 (CCiTT).

The CRC includes everything from the first DLE to the ETX..

Byte stuffing of DLE: Any DLE character is followed by either an STX, ETX or another DLE. If a DLE character is found in the data stream then an addition DLE character is inserted. The byte stuffing occurs between the DLE STX and the DLE ETX.

我的代码如下,想知道如何去正确算出一个CRC效验码,由于又不知道多项式是多少,所以现在急死了!!

procedure TForm1.Button2Click(Sender: TObject);
var
CRC:Integer;
i,j:INteger;
tmpInt:Integer;
LowBit:Integer;
ok:Boolean;
begin
OK:=False;
while not ok do begin
CRC:=$FFFF;
for j:=0 to ListBox1.Items.Count-1 do begin
tmpInt:=StrToInt(ListBox1.Items.Strings[j]);
CRC:=CRC xor tmpInt;
for i:=1 to 8 do begin
LowBit:=CRC and 1;
CRC:=CRC shr 1;
if LowBit=1 then begin
CRC:=CRC xor StrToInt(Edit3.Text);
end;
end;
end;
Memo1.Lines.Add('Now='+Edit3.Text+';CRC='+IntToStr(CRC));
if CRC=WantCRC then begin
ok:=True;
ShowMessage('找到了◎!!!!');
end else begin
Edit3.Text:=IntToStr(StrToInt(Edit3.Text)+1);
Gauge1.Progress:=StrToInt(Edit3.Text)*100 div $1FFFF;
if StrToInt(Edit3.Text)>$1FFFF then begin
Showmessage('没有找到????!!!!!');
exit;
end;
end;
end;
end;
我想问的问题:
(1)CRC-16(CCITT)的效验多项式是否有标准值?
(2)我的程序算法是否错误,错在哪里?(请不要跟我提查表法,请帮忙找一下错误)
(3)下面的参考资料是否有错误?
下面为CRC的计算过程:

  1.设置CRC寄存器,并给其赋值FFFF(hex)。

  2.将数据的第一个8-bit字符与16位CRC寄存器的低8位进行异或,并把结果存入CRC寄存器。

  3.CRC寄存器向右移一位,MSB补零,移出并检查LSB。

  4.如果LSB为0,重复第三步;若LSB为1,CRC寄存器与多项式码相异或。

  5.重复第3与第4步直到8次移位全部完成。此时一个8-bit数据处理完毕。

  6.重复第2至第5步直到所有数据全部处理完成。

  7.最终CRC寄存器的内容即为CRC值。
 
也请关注另外一个问题。
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1386952
 
呵呵,我刚刚做了一个程序,里面用的CRC算法好像与你的有点相似,你试试吧

procedure GetCRC(buf: array of byte;bufNums:integer; var CRCLow,
CRCHi: byte);
var
ret,i,j:integer;
// outbuf:array [1..8] of byte;//8
// inbuf:array [1..21] of byte;// 21
// CRCLow,CRCHi:byte;
CRC:word;
begin
// outbuf:=buf;
{
buf[1]:=$01;
buf[2]:=$04;
buf[3]:=$00;
buf[4]:=$00;
buf[5]:=$00;
buf[6]:=$08;
}
CRC:=$FFFF;
for i := 0 to bufNums-3 do
begin //for i
CRClow:=CRC and $FF;//取低8位
CRCHi:=CRC div 256; // 取高8位
CRCLow:=buf xor CRCLow;//
CRC:=CRCHi*256+CRCLow;//返回CRC



for j :=1 to 8 do
begin //for j
CRCLow:=CRC and $01;//取最后一位

CRC:=CRC shr 1;

if CRCLow=$01 then
begin
CRC:=CRC xor $A001;//如果最后位为1则与A001异或
end;



end;//for j


end; //for i

CRClow:=CRC and $FF;//取低8位
CRCHi:=CRC div 256; // 取高8位
// showmessage(format('%x',[crchi]));

end;//end GETCRC
 
刚才忘记解释一下,上面的程序中,buf为数据也就是从Dle到最后(包括最后两位CRC),
bufNums为buf的长度(包括CRC),返回结果为CRCHi,CRCLow
 
回resun:
拜托帮忙看一下我的另外一个帖子,也是关于CRC效验的,
http://www.delphibbs.com/delphibbs/DispQ.asp?LID=1386952
如果你能用你的程序计算出预期的效验码,就说明你的正确了。
可能我对你的程序理解不清楚,如果你能去看一下那个帖子最好了。
 
我试了一下,算不出你所给的CRC,我有个问题请教,在另外那个帖子中的
16,2,6,0,6,0,1,64,16,3,(241,36),复位
16,2,6,0,6,0,1,8,16,3,(49,144),静音
16,2,6,0,6,0,1,32,16,3,(244,105),隔离i
你是怎么得到这些值的?
 
有一个厂家提供的测试程序,可以对设备进行控制,经过测试,是可用的。
然后我找一根线,把串口1直接接到串口2,也就是说,我用一个接收程序,把串口1里测试程序发
出的命令都收下来了,就是上面那些复位、静音、隔离之类的值。
他所使用的通讯格式也符合协议的(参考第一个帖子),仅仅是他的效验码我怎么也算不出来。
大家帮忙分析一下,到底因为他所使用的多项式没有找到还是因为其他的原因,效验码不和我们算
出来的一样。
 
我试过了,从$1到$FFFF都不行,看来不是多项式的问题,应该是算法的问题,还是再找一
下其它的算法吧
 
算法不至于有问题吧,这可是厂家提供的算法呀,而且明确写着是CRC-16(CCITT)呀。
 
Indy源代码里面有,自己找吧
 
多项式编码(也叫循环冗余码,或CRC码)。多项式编码是基于将位串看成是系数为0或1的多项式,一个k位帧可以看成是从Xk-1到X0的k-1次多项式的系数序列。如果采用多项式编码的方式,发送方和接收方必须事先商定一个生成多项式G(x),生成多项式的高位和低位必须是1。要计算m位的帧M(x)的校验和,生成多项式必须比该多项式短。基本思想是:将校验和加在帧的末尾,使这个带校验和的帧的多项式能被G(x)除尽。当接收方收到带校验和的帧时,用G(x)去除它,如果有余数,则传输出错。

计算校验和的算法如下:

①.设G(x)为r阶,在帧的末尾附加r个零,使帧为m+r位,则相应的多项式是XrM(x)。

②.按模2除法用对应于G(x)的位串去除对应于XrM(x)的位串。

③.按模2减法从对应于XrM(x)的位串中减去余数。结果就是要传送带校验和的帧,叫多项式T(x)。

以下三个多项式已经成为国际标准:

crc -12 = x^12+x^11+x^3+x^2+x+1
crc -16 = x^16+x^15+x^2+1
crc -ccitt = x^16+x^12+x^5+1

这三个多项式都包含了x+1作为基本因子。当字符串长度为6位时,使用CRC-12;其余两个多项式用在字符串长度为8位的情况下。一个16位的校验和,如CRC-16或CRC-CCITT,可以捕捉到所有的单位差错和双位差错,所有奇数位数的差错,所有长度小于或等于16位的突发差错,99.997%的长度为17位的突发差错,以及99.998%的长度为18位或多于18位的突发差错。

 
// 注意:因最高位一定为“1”,故略去
const unsigned short cnCRC_16 = 0x8005;
// CRC-16 = X16 + X15 + X2 + X0
const unsigned short cnCRC_CCITT = 0x1021;
// CRC-CCITT = X16 + X12 + X5 + X0,据说这个 16 位 CRC 多项式比上一个要好
const unsigned long cnCRC_32 = 0x04C10DB7;
// CRC-32 = X32 + X26 + X23 + X22 + X16 + X11 + X10 + X8 + X7 + X5 + X4 + X2 + X1 + X0

unsigned long Table_CRC[256]; // CRC 表

// 构造 16 位 CRC 表
void BuildTable16( unsigned short aPoly )
{
unsigned short i, j;
unsigned short nData;
unsigned short nAccum;

for ( i = 0; i < 256; i++ )
{
nData = ( unsigned short )( i << 8 );
nAccum = 0;
for ( j = 0; j < 8; j++ )
{
if ( ( nData ^ nAccum ) &amp; 0x8000 )
nAccum = ( nAccum << 1 ) ^ aPoly;
else
nAccum <<= 1;
nData <<= 1;
}
Table_CRC = ( unsigned long )nAccum;
}
}

// 计算 16 位 CRC 值,CRC-16 或 CRC-CCITT
unsigned short CRC_16( unsigned char * aData, unsigned long aSize )
{
unsigned long i;
unsigned short nAccum = 0;

BuildTable16( cnCRC_16 ); // or cnCRC_CCITT
for ( i = 0; i < aSize; i++ )
nAccum = ( nAccum << 8 ) ^ ( unsigned short )Table_CRC[( nAccum >> 8 ) ^ *aData++];
return nAccum;
}

// 构造 32 位 CRC 表
void BuildTable32( unsigned long aPoly )
{
unsigned long i, j;
unsigned long nData;
unsigned long nAccum;

for ( i = 0; i < 256; i++ )
{
nData = ( unsigned long )( i << 24 );
nAccum = 0;
for ( j = 0; j < 8; j++ )
{
if ( ( nData ^ nAccum ) &amp; 0x80000000 )
nAccum = ( nAccum << 1 ) ^ aPoly;
else
nAccum <<= 1;
nData <<= 1;
}
Table_CRC = nAccum;
}
}

// 计算 32 位 CRC-32 值
unsigned long CRC_32( unsigned char * aData, unsigned long aSize )
{
unsigned long i;
unsigned long nAccum = 0;

BuildTable32( cnCRC_32 );
for ( i = 0; i < aSize; i++ )
nAccum = ( nAccum << 8 ) ^ Table_CRC[( nAccum >> 24 ) ^ *aData++];
return nAccum;
}

 
回shijunwu:
你有没有现成的程序,可以对一个字符串进行CRC16和CCITT进行效验,麻烦给我发一个。
我的信箱:crazycock@163.net
或者你到这里去看看……
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1386952
 
顶部