日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

通用型CRC校验算法

發(fā)布時(shí)間:2023/12/31 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 通用型CRC校验算法 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

通用型CRC校驗(yàn)算法

1、CRC校驗(yàn)簡(jiǎn)單原理
CRC校驗(yàn)方法是在通訊領(lǐng)域應(yīng)用極廣的一類數(shù)據(jù)校驗(yàn)方法,常用的包括CRC8、CRC16、CRC32(數(shù)字為生成多項(xiàng)式Gx-1),在嵌入式領(lǐng)域應(yīng)用較多(DS18B20溫度傳感器正負(fù)溫度精度校驗(yàn)(CRC查表法)),其校驗(yàn)手段極為有效,但是其本生并不具有糾錯(cuò)能力。假設(shè)有目前有效數(shù)據(jù)Kx(信息碼)有K位,生成多項(xiàng)式為Gx,經(jīng)過(guò)有限次取模運(yùn)算(等同于XOR,不借位的模2運(yùn)算),求得冗余碼(FCS序列)有N位,則最終傳輸數(shù)據(jù)為Tx=Kx+N,而接收方在收到數(shù)據(jù)后用Tx%Gx(有限次XOR)是否為0判斷數(shù)據(jù)傳輸?shù)恼_性。
具體CRC校驗(yàn)原理,還可以參看其他博客或者百度了解學(xué)習(xí)。
2、算法
經(jīng)過(guò)上述的簡(jiǎn)單說(shuō)明,應(yīng)該知道可以引入Kx、Gx、Tx、Rx,采用最高位對(duì)其(Gx補(bǔ)償)直接計(jì)算法,對(duì)數(shù)據(jù)比特串較短、時(shí)間要求不高的可以采用,使用必須要滿足以下要求:
*

① Gx補(bǔ)償位數(shù)滿足:Gx*2^(sizeof(Kx)-sizeof(Gx))。 ② 運(yùn)算次數(shù)滿足:sizeof(Kx)-sizeof(Gx)。 ③ CRC進(jìn)行XOR運(yùn)算滿足:CRC & (2^(sizeof(Kx)-1)。 ④ Rx還原滿足:CRC/2^(sizeof(Kx)-sizeof(Gx)+1)。

其中sizeof表示取得元素在二進(jìn)制下位長(zhǎng)。
3、應(yīng)用效果
(1)測(cè)試數(shù)據(jù):
①Kx=110011,Gx=11001,Rx=1001
②Kx=101001,Gx=1101,Rx=001

/**** vision:v1.0.0 Author:LHC Gx:生成碼(生成多項(xiàng)式) KX:信息碼(要發(fā)送的數(shù)據(jù)部分) TX:真實(shí)發(fā)送的數(shù)據(jù)(Kx+Rx) Rx:CRC循環(huán)冗余檢驗(yàn)碼(FCS序列) 目前Bug:單crc序列的首位或者多位為00時(shí),將不會(huì)顯示,需要按添加位數(shù)人工補(bǔ)0 Data_Test:Kx=110011,Gx=11001,Rx=1001;Kx=101001,Gx=1101,Rx=001 Ways:直接計(jì)算法(位數(shù)直接與Kx對(duì)其),在簡(jiǎn)單應(yīng)用領(lǐng)域滿足要求,不適用極限時(shí)間要求 ****/#include <stdio.h> #include <stdlib.h> #include <math.h> #include <string.h>typedef unsigned int uint_32; #define BDH_SYSTEM 2 //用于表示輸出數(shù)據(jù)進(jìn)制 uint_32 gx,kx,tx,rx; char gx_c[32],kx_c[32],rx_c[32],tx_c[32]; //最大數(shù)據(jù)串長(zhǎng)度 char flag='y';uint_32 Binnary_Change_Decimal(char p[]) //把二進(jìn)制數(shù)據(jù)串轉(zhuǎn)換為10進(jìn)制 {int length =0,i=0;uint_32 sum=0;length =strlen(p);for(i=0;i<length;i++) //此處length不包含‘/0’{if(p[i]=='1') //帶權(quán)法算出10進(jìn)制值sum =sum+(uint_32)pow(2,length-1-i); //pow函數(shù)用于計(jì)算y^x,x、y及返回值都是double型}//printf("%d\n",sizeof(sum));return sum; }void Input_Binary() //輸入為2進(jìn)制比特串 {printf("please Kx with (binary) system:\n");gets(kx_c);kx =Binnary_Change_Decimal(kx_c);tx =kx; //首次把TX值賦值為KX,方便后面擴(kuò)展printf("please Gx with (binary) system:\n");gets(gx_c);gx =Binnary_Change_Decimal(gx_c); }/*void Input_Decimal() //輸入為10進(jìn)制模式 {printf("please Kx with (decimal) system:\n");scannf("%d",&kx);printf("please Gx with (decimal) system:\n");scannf("%d",&gx); }*/uint_32 CRC_Value(uint_32 *Kx,uint_32 Gx) //通用CRC核心函數(shù) {uint_32 crc=0; //暫存每次XOR運(yùn)算后的數(shù)據(jù)char kx_c_t[32]; //用于求出10進(jìn)制轉(zhuǎn)2進(jìn)制后的數(shù)據(jù)而設(shè)定的臨時(shí)變量int length_1 =0,length_2=0,i;char Gx_Binary[32];itoa(Gx,Gx_Binary,BDH_SYSTEM); //將int型數(shù)據(jù)轉(zhuǎn)換成數(shù)據(jù)串,2表示二進(jìn)制length_1=strlen(Gx_Binary);*Kx =(*Kx)*(uint_32)pow(2,length_1-1); //還原出被除數(shù) itoa(*Kx,kx_c_t,BDH_SYSTEM);length_2 =strlen(kx_c_t);crc =*Kx; //還原后的除數(shù)為首次運(yùn)算的crcGx =Gx*(uint_32)pow(2,(length_2-length_1)); //湊出GX的長(zhǎng)度和KX一樣長(zhǎng)for(i=0;i<(length_2-length_1)+1;i++) //運(yùn)算次數(shù)9-4+1、10-5+1{//if(crc&0x100) //只要滿足被除數(shù)KX的最高位與除數(shù)相與后不為0即可參加X(jué)OR運(yùn)算,512、256if(crc&((uint_32)pow(2,length_2-1))) //2^0=1,次數(shù)起始為0{crc ^=Gx;printf("CRC1:%d\n",crc); //crc運(yùn)算步驟crc <<=1;}else //最高位不為1移位{crc <<=1;printf("CRC2:%d\n",crc);}}//printf("pow:%d\n",(uint_32)pow(2,length_1));return crc/(uint_32)pow(2,(length_2-length_1)+1); //去除運(yùn)算結(jié)束后多余的RX位數(shù)//此處必須注意運(yùn)算結(jié)束后CRC都會(huì)被<<1,所以還原的CRC應(yīng)在原基礎(chǔ)上>>1 }void main() {while(flag=='y'){fflush(stdin); //清空緩沖區(qū)Input_Binary();rx =CRC_Value(&kx,gx);itoa(kx,kx_c,BDH_SYSTEM); //把真實(shí)的KX算出itoa(rx,rx_c,BDH_SYSTEM);itoa(tx,tx_c,BDH_SYSTEM);strcat(tx_c,rx_c); //此處Tx為字符串的簡(jiǎn)單拼接printf("\noutput (Kx):%s\n",kx_c); //輸出為2進(jìn)制printf("output (GX):%s\n",gx_c);printf("output (Tx):%s\n",tx_c);printf("output (RX):%s\n",rx_c);tx =Binnary_Change_Decimal(tx_c);if(tx%gx==0) //檢測(cè)數(shù)據(jù)是否出錯(cuò)printf("\nRX=%d,data is true!\n",(tx%gx));elseprintf("data have errors! please cheak!\n");printf("Have a want to continue?(y/n)\n");scanf("%s",&flag);} }

(2)運(yùn)行效果

圖3.1 測(cè)試1

圖3.2 測(cè)試2

4、說(shuō)明
首先,為什么我要大費(fèi)周章的開(kāi)發(fā)這樣一個(gè)程序呢?原因其實(shí)很簡(jiǎn)單,網(wǎng)絡(luò)上關(guān)于CRC校驗(yàn)的原代碼的確是很多,原理更是不計(jì)其數(shù),但是有三點(diǎn)需要注意,其一,CRC校驗(yàn)是有很多標(biāo)準(zhǔn)(CRC—16/IBM、CRC-8等)的,而這些標(biāo)準(zhǔn)的區(qū)別就在于采用的生成多項(xiàng)式不同,比如說(shuō)CRC-8的Gx為:X8+X2+X+1(100000101,注意最高位和最低位為1),這就會(huì)造成你的直接引用卻無(wú)法得到預(yù)期的結(jié)果,在者CRC校驗(yàn)本身并不難,而難的是如何用計(jì)算機(jī)實(shí)現(xiàn),因?yàn)槟阋紤]很多因素,最多的就是數(shù)據(jù)邊界問(wèn)題(char類型數(shù)據(jù)在Keil 5中容納數(shù)據(jù)為255),這個(gè)自己體會(huì)了;其二,當(dāng)你去不斷參考別人的經(jīng)驗(yàn)代碼的時(shí)候,你會(huì)發(fā)現(xiàn)這樣一句話“CRC為嵌入式開(kāi)發(fā)人員的法寶之一,但僅有少數(shù)人能掌握其核心算法!”,真的有這么難嗎,前輩的答案顯然是正確的,當(dāng)你瀏覽很多個(gè)碼齡超過(guò)4年以上的前輩的代碼后你會(huì)發(fā)現(xiàn),難于理解,因?yàn)閿?shù)學(xué)思維極強(qiáng),最后結(jié)果就會(huì)是直接不想看甚至放棄了,但是我編寫(xiě)的則不同,簡(jiǎn)單,易于理解,起源于謝希仁計(jì)網(wǎng),通用型極高;其三,純屬個(gè)人愛(ài)好,還有就是特別討厭直接引用別人代碼,而不知所云(可能是個(gè)人強(qiáng)迫癥),以及編寫(xiě)過(guò)后對(duì)收獲成果的一種成就感促使我這么做。
還有一點(diǎn)需要說(shuō)明的是,從圖3.2可以看出,最后的Tx是錯(cuò)誤的,原因是C98編譯器只統(tǒng)計(jì)數(shù)據(jù)的有效位,原Rx=001,有效數(shù)據(jù)為1,所以00被丟棄了,造成Kx%Gx出錯(cuò),這個(gè)是我故意留于檢測(cè)用,改正僅需加入2個(gè)0即可。
最后,我的成功是站在巨人的肩膀上的,我姑且這么說(shuō)吧,模型參考了一位前輩的,但是前輩的核心思想有問(wèn)題,其核心是自己總結(jié)的,這篇博客將會(huì)是我在CSDN的“LHC_黎明之光”博客號(hào)首篇原創(chuàng)文章,前路漫漫,望我們一同成長(zhǎng)學(xué)習(xí)吧!如果發(fā)現(xiàn)錯(cuò)誤的話,歡迎給我留言哦。

總結(jié)

以上是生活随笔為你收集整理的通用型CRC校验算法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。