高手們,請教下關于數據校驗的CRC算法啊,好郁悶,看到CSDN論壇也有一些相關的貼,好像有兩種方法,查表法和計算法,不知這兩種方法那種好點,因為crc的帖子還是看得不是很懂,請高手們可否做一個小的程序,兩個EDIT,一個按鈕就可以,第一個edit輸入一些16進制的字符串,按按鈕,第二個edit返回這一堆數的驗證碼啊,比如:輸入030301010001,按鈕,第二個edit顯示D5D4,好像是不是又涉及到一些字符串和16進制的問題,所以不是很懂,請教請教,最好是把程序發到我郵箱啦,無限感激,謝謝謝謝,我的郵箱是[email protected]
//********************************************************
// 生成crc16校验码
// s:要校验的字符串,len:字符串的长度
// 返回值是2个字节的校验码
//********************************************************
function crc16(s:string;len:integer):word;
var
flag,c,crc:word;
i,j:integer;
begin
crc:=$0000;
for i:=1 to len do
begin
c:=ord(s[i]);
c:=c shl 8;
crc:=crc xor c;
for j:=1 to 8 do
begin
flag:=crc and $8000;
crc:=crc shl 1;
if flag>0 then crc:=crc xor $8005;
end;
end;
result:=crc;
end;
你好,謝謝你發過來的程序啊,但是還想請教下下面的問題啊
我一般是發送16進制的數據,比如03 03 01 01 00 01 校驗位(2位),這樣的格式啊,一個8個字節的,我用一些CRC校驗的工具算出來是D5 D4,但是你提供的那兩個程序計算出來都是A92610BB,不知是不是我那里說不清楚了,他那里只是寫是CRC校驗,我也不是很清楚是16,還是32啊,聽說還有8的啊,所以還想請教請教,謝謝發送格式:03 03 01 01 00 01 D5 D4
var
j, cbit, aout, crc, crc_a, crc_b: Byte;
i: Integer;
begin
crc := 0;
i := 0;
repeat
crc_a := p[i];
inc(i);
j := 8;
cbit := 1;
repeat
crc_b := crc_a;
crc_b := crc_b xor crc;
aout := crc_b and cbit;
if aout <> 0 then begin
crc := crc xor $18;
crc := crc shr 1;
crc := crc or $80;
end else begin
crc := crc shr 1;
end;
crc_a := crc_a shr 1;
dec(j);
until j = 0;
dec(len);
until len = 0;
Result := crc;
end;
我还有一个要查表的,要不要
謝謝
// 生成crc16校验码
// s:要校验的字符串,len:字符串的长度
// 返回值是2个字节的校验码
//********************************************************
function crc16(s:string;len:integer):word;
var
flag,c,crc:word;
i,j:integer;
begin
crc:=$0000;
for i:=1 to len do
begin
c:=ord(s[i]);
c:=c shl 8;
crc:=crc xor c;
for j:=1 to 8 do
begin
flag:=crc and $8000;
crc:=crc shl 1;
if flag>0 then crc:=crc xor $8005;
end;
end;
result:=crc;
end;
謝謝你的回答啊,不過好像跟kampan兄一樣的哦,因為不知道這個返回來的WORD的怎樣轉換成一個字符串用edit來顯示啊???所以還請高手們能做做個小工程發到我有限啦,謝謝
輸入:$03 03 01 01 00 01
結果:$03 03 01 01 00 01 D5 D4謝謝謝謝
var
flag,c,crc:word;
i,j:integer;
begin
crc:=$0000;
for i:=1 to len do
begin
c:=ord(s[i]);
c:=c shl 8;
crc:=crc xor c;
for j:=1 to 8 do
begin
flag:=crc and $8000;
crc:=crc shl 1;
if flag>0 then crc:=crc xor $8005;
end;
end;
result:=IntToHex(crc,2);
end;
var
flag, c, crc: word;
i, j: integer;
begin
crc := $0000;
for i := 1 to (len div 2) do
begin
//c := ord(s[i]); c := strtoint('$' + copy(s, (2*i-1), 2)); //16进制转10进制,每两位 c := c shl 8;
crc := crc xor c;
for j := 1 to 8 do
begin
flag := crc and $8000;
crc := crc shl 1;
if flag > 0 then crc := crc xor $8005;
end;
end;
result := IntToHex(crc, 2);
end;
你好,谢谢回答,但是我调用的时候算出来怎么不对的呢?奇怪
我在edit1输入030301010001,按钮动作写:edit2.Text:=crc16(edit1.Text,6);
但是edit2运行的结果是8A39,而不是D5 D4啊 ,D5 D4 才是对的啊?
继续请教谢谢
如果我一边是用C语言写的校验程序,用的校验因子表进行校验的,一边是用DELPHI写的校验程序,假如就用
这位大哥的: //********************************************************
// 生成crc16校验码
// s:要校验的字符串,len:字符串的长度
// 返回值是2个字节的校验码
//********************************************************
function crc16(s:string;len:integer):word;
var
flag,c,crc:word;
i,j:integer;
begin
crc:=$0000;
for i:=1 to len do
begin
c:=ord(s[i]);
c:=c shl 8;
crc:=crc xor c;
for j:=1 to 8 do
begin
flag:=crc and $8000;
crc:=crc shl 1;
if flag>0 then crc:=crc xor $8005;
end;
end;
result:=crc;
end;这样校验码一样吗?
高手們,請教下關于數據校驗的CRC16算法啊,好郁悶,看到CSDN論壇也有一些相關的貼,好像有兩種方法,查表法和計算法,不知這兩種方法那種好點,因為crc16的帖子還是看得不是很懂,請高手們可否做一個小的程序,兩個EDIT,一個按鈕就可以,第一個edit輸入一些16進制的字符串,按按鈕,第二個edit返回這一堆數的驗證碼啊,比如:輸入030301010001,按鈕,第二個edit顯示D5D4,好像是不是又涉及到一些字符串和16進制的問題,所以不是很懂,請教請教,最好是把程序發到我郵箱啦,無限感激,謝謝謝謝,
我的郵箱是[email protected]輸入:$03 03 01 01 00 01
結果:$03 03 01 01 00 01 D5 D4
http://www.metersnet.com/download/modbus.pdf2.错误校验
冗余循环码(CRC)包含2个字节,即16位二进制。CRC码由发送设备计算,放置于发送信息的尾部。接收信息的设备再重新计算接收到信息的 CRC码,比较计算得到的CRC码是否与接收到的相符,如果两者不相符,则表明出错。
CRC码的计算方法是,先预置16位寄存器全为1。再逐步把每8位数据信息进行处理。在进行CRC码计算时只用8位数据位,起始位及停止位,如有奇偶校验位的话也包括奇偶校验位,都不参与CRC码计算。
在计算CRC码时,8位数据与寄存器的数据相异或,得到的结果向低位移一字节,用0填补最高位。再检查最低位,如果最低位为1,把寄存器的内容与预置数相异或,如果最低位为0,不进行异或运算。
这个过程一直重复8次。第8次移位后,下一个8位再与现在寄存器的内容相相异或,这个过程与以上一样重复8次。当所有的数据信息处理完后,最后寄存器的内容即为CRC码值。CRC码中的数据发送、接收时低字节在前。
计算CRC码的步骤为:
1) 预置16位寄存器为十六进制FFFF(即全为1)。称此寄存器为CRC寄存器;
2) 把第一个8位数据与16位CRC寄存器的低位相异或,把结果放于CRC寄存器;
3) 把寄存器的内容右移一位(朝低位),用0填补最高位,检查最低位;
4) 如果最低位为0:重复第3步(再次移位); 如果最低位为1:CRC寄存器与多项式A001(1010 0000 0000 0001)进行异或;
5) 重复步骤3和4,直到右移8次,这样整个8位数据全部进行了处理;
6) 重复步骤2到步骤5,进行下一个8位数据的处理;
7) 最后得到的CRC寄存器即为CRC码。(二)、CRC校验码计算
UINT crc
void calccrc(BYTE crcbuf)
{
BYTE i;
crc=crc ^ crcbuf;
for(i=0;i<8;i++)
{
BYTE TT;
TT=crc&1;
crc=crc>>1;
crc=crc&0x7fff;
if (TT==1)
crc=crc^0xa001;
crc=crc&0xffff;
}
}
delphi代码function crc16(s: string; len: integer): string;
var
flag, c, crc: word;
i, j: integer;
begin
crc := $FFFF;
for i := 1 to (len div 2) do
begin
c := strtoint('$' + copy(s, (2 * i - 1), 2)); //16进制转10进制,每两位
crc := crc xor c;
for j := 1 to 8 do
begin
flag := crc and 1;
crc := crc shr 1;
if flag = 1 then crc := crc xor $A001;
end;
end;
result := IntToHex(crc, 2);
end;你再看看吧
var
flag, c, crc: word;
i, j: integer;
begin
crc := $FFFF;
for i := 1 to (len div 2) do
begin
c := strtoint('$' + copy(s, (2 * i - 1), 2)); //16进制转10进制,每两位
crc := crc xor c;
for j := 1 to 8 do
begin
flag := crc and 1;
crc := crc shr 1;
crc := crc and $7FFF;
if flag = 1 then
begin
crc := crc xor $A001;
crc := crc and $FFFF;
end;
end;
end;
result := IntToHex(crc, 2);
end;
function crc16(s: string; len: integer): string;
var
flag, c, crc: word;
i, j: integer;
begin
crc := $FFFF;
for i := 1 to (len div 2) do
begin
c := strtoint('$' + copy(s, (2 * i - 1), 2)); //16进制转10进制,每两位
crc := crc xor c;
for j := 1 to 8 do
begin
flag := crc and 1;
crc := crc shr 1;
crc := crc and $7FFF;
if flag = 1 then
begin
crc := crc xor $A001;
crc := crc and $FFFF;
end;
end;
end;
crc := ((crc and $FF00) shr 8) + ((crc and $FF) shl 8);
result := IntToHex(crc, 2);
end;
var
CRC16Lo, CRC16Hi, CL, CH, UseHi, UseLo: Dword;
i, index: integer;
begin
CRC16Lo := $FF; //CRC16Lo为CRC寄存器低8位
CRC16Hi := $FF; //CRC16Hi为CRC寄存器高8位
CL := $1;
CH := $A0; // A001 H 是CRC-16多项式代码
for i := 1 to Length(Data) do begin
CRC16Lo := CRC16Lo xor ord(Data[i]); //每一个数据与CRC寄存器异或
for index := 0 to 7 do begin
UseHi := CRC16Hi;
UseLo := CRC16Lo;
CRC16Hi := CRC16Hi shr 1;
CRC16Lo := CRC16Lo shr 1; //右移一位
if ((UseHi and $1) = $1) then //如果高位字节最后一位是1的话
CRC16Lo := CRC16Lo or $80; //低位字节右移后前面补1 if ((UseLo and $1) = $1) then begin//如果LSB 为1,则与多项式进行异或
CRC16Hi := CRC16Hi xor CH;
CRC16Lo := CRC16Lo xor CL;
end;
end;
end; Result := Char(CRC16Lo) + Char(CRC16Hi);
end; //计算CRC校验
CRCData:=ModBusCRC(sendbuf);
//加上CRC校验
sendbuf:=sendbuf+CRCData;