當前位置:首頁 > 單片機 > 單片機
[導讀]CRC校驗又稱為循環(huán)冗余校驗,是數(shù)據(jù)通訊中常用的一種校驗算法。它可以有效的判別出數(shù)據(jù)在傳輸過程中是否發(fā)生了錯誤,從而保障了傳輸?shù)臄?shù)據(jù)可靠性。CRC校驗有多種方式,如:CRC8、CRC16、CRC32等等。在實際使用中,我

CRC校驗又稱為循環(huán)冗余校驗,是數(shù)據(jù)通訊中常用的一種校驗算法。它可以有效的判別出數(shù)據(jù)在傳輸過程中是否發(fā)生了錯誤,從而保障了傳輸?shù)臄?shù)據(jù)可靠性。

CRC校驗有多種方式,如:CRC8、CRC16、CRC32等等。在實際使用中,我們經(jīng)常使用CRC16校驗。CRC16校驗也有多種,如:1005多項式、1021多項式(CRC-ITU)等。在這里我們不討論CRC算法是怎樣產生的,而是重點落在幾種算法的C51程序的優(yōu)化上。

計算CRC校驗時,最常用的計算方式有三種:查表、計算、查表+計算。一般來說,查表法最快,但是需要較大的空間存放表格;計算法最慢,但是代碼最簡潔、占用空間最小;而在既要求速度,空間又比較緊張時常用查表+計算法。

下面我們分別就這三種方法進行討論和比較。這里以使用廣泛的51單片機為例,分別用查表、計算、查表+計算三種方法計算 1021多項式(CRC-ITU)校驗。原始程序都是在網(wǎng)上或雜志上經(jīng)常能見到的,相信大家也比較熟悉了,甚至就是正在使用或已經(jīng)使用過的程序。

編譯平臺采用KeilC517.0,使用小內存模式,編譯器默認的優(yōu)化方式。

常用的查表法程序如下,這是網(wǎng)上經(jīng)常能夠看到的程序范例。因為篇幅關系,省略了大部分表格的內容。

codeunsignedintCrc1021Table[256]={

0x0000,0x1021,0x2042,0x3063,...0x1ef0

};

unsignedintcrc0(unsignedchar*pData,unsignedcharnLength)

{

unsignedintCRC16=0;

while(nLength>0)

{

CRC16=(CRC16<<8)^Crc1021Table[((CRC16>>8)^*pData)&0xFF];

nLength--;

pData++;

}

returnCRC16;

}

編譯后,函數(shù)crc0的代碼為68字節(jié),加上表格占用的512字節(jié),一共使用了580個字節(jié)的代碼空間。

下面是常見的計算法的程序:

unsignedintcrc2(unsignedchar*ptr,unsignedcharcount)

{

unsignedintcrc=0;

unsignedchari;

while(count-->0)

{

crc=(crc^(((unsignedint)*ptr)<<8));

for(i=0;i<8;i++)

{

if(crc&0x8000)crc=((crc<<1)^0x1021);

elsecrc<<=1;

}

ptr++;

}

returncrc;

}

下面是常見的一種查表+計算的方法:

unsignedintcrc4(unsignedchar*ptr,unsignedcharlen){

unsignedintcrc;

unsignedcharda;

codeunsignedintcrc_ta[16]={/*CRC余式表*/

0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,

0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,

};

crc=0;

while(len-->0){

da=((crc/256))/16; /*暫存CRC的高四位*/

crc<<=4; /*CRC右移4位,相當于取CRC的低12位)*/

crc^=crc_ta[da^(*ptr/16)]; /*CRC的高4位和本字節(jié)的前半字節(jié)相加后查表*/

/*計算CRC,然后加上上一次CRC的余數(shù)*/

da=((crc/256))/16; /*暫存CRC的高4位*/

crc<<=4; /*CRC右移4位,相當于CRC的低12位)*/

crc^=crc_ta[da^(*ptr&0x0f)];/*CRC的高4位和本字節(jié)的后半字節(jié)相加后查表*/

/*計算CRC,然后再加上上一次CRC的余數(shù)*/

ptr++;

}

returncrc;

}

程序優(yōu)化策略:上面程序都只是給出了通用算法,并沒有考慮到51單片機的特點。我們知道,51單片機是8位單片機,使用的變量類型也是8位的。如果在程序中使用8位的變量速度是最快的,比使用16位的變量代碼短、效率高。在上面的程序中都使用了大量整型數(shù)類型(16位)的表格和整型數(shù)類型的變量,特別是關鍵的變量。如果我們不使用整型類型的表格和變量,而使用字節(jié)類型的表格和變量,就能夠使程序的性能得到優(yōu)化?;谶@種思路,我們將原來整型的表格拆分為兩個字節(jié)型(8位)的表格,即將原來表格的高低字節(jié)分別拆開,每個表格還是256個單元,這樣表格的大小和順序都沒有變;原來使用16位變量計算的地方,改用8位變量計算。

修改后的查表程序如下(省略了表格的內容):

codeunsignedcharcrctableh[256]={

0x00,0x10,0x20,0x30,...0x0E,0x1E,

};

codeunsignedcharcrctablel[256]={

0x00,0x21,0x42,0x63,...0xD1,0xF0,

};

unsignedintcrc1(unsignedchar*buf,unsignedcharn)

{

unsignedchart;

union{

unsignedcharc[2];

unsignedintx;

}datacrc;

crc.x=0;

while(n!=0)

{

t=crc.c[0]^*buf;

crc.c[0]=crc.c[1]^crctableh[t];

crc.c[1]=crctablel[t];

n--;

buf++;

}

return(crc.x);

}

表面上看起來,函數(shù)crc1比crc0的源代碼還長一些。但是編譯后,函數(shù)crc1的目標代碼實際為44個字節(jié),加上表格占用的512個字節(jié),一共使用了556個字節(jié),比函數(shù)crc0反而節(jié)約了24個字節(jié)。這兩個函數(shù)的運行對比情況見表一。

我們采用和上面相同的優(yōu)化方法來優(yōu)化計算法的程序,優(yōu)化后的計算法程序為:

unsignedintcrc3(unsignedchar*ptr,unsignedcharcount)

{

dataunsignedchari;

union{

unsignedcharc[2];

unsignedintx;

}datacrc;

crc.x=0;

while(count!=0)

{

crc.c[0]^=*ptr;

for(i=8;i>0;i--)

{

if(crc.c[0]&0x70)crc.x=(crc.x<<1)&0x1021;

elsecrc.x=crc.x<<1;

}

ptr++;

count--;

}

returncrc.x;

}

編譯后函數(shù)crc2的代碼長度為76,函數(shù)crc3的代碼長度為68,變化不是太大,但是執(zhí)行效率是很不一樣的,具體差別見后面的表一。

優(yōu)化后的查表+計算法的程序為:

unsignedintcrc5(unsignedchar*ptr,unsignedcharlen)

{

codeunsignedcharcrch[16]={/*CRC余式表*/

0x00,0x10,0x20,0x30,0x40,0x50,0x60,0x70,

0x81,0x91,0xa1,0xb1,0xc1,0xd1,0xe1,0xf1,

};

codeunsignedcharcrcl[16]={/*CRC余式表*/

0x00,0x21,0x42,0x63,0x84,0xa5,0xc6,0xe7,

0x08,0x29,0x4a,0x6b,0x8c,0xad,0xce,0xef,

};

union{

unsignedcharc[2];

unsignedintx;

}datacrc;

unsignedchart;

crc.x=0;

while(len!=0){

t=(crc.c[0]>>4)^(*ptr>>4);

crc.x<<=4;

crc.c[0]^=crch[t];

crc.c[1]^=crcl[t];

t=(crc.c[0]>>4)^(*ptr&0x0F);

crc.x<<=4;

crc.c[0]^=crch[t];

crc.c[1]^=crcl[t];

ptr++;

len--;

}

returncrc.x;

}

優(yōu)化前后的代碼長度分別為175字節(jié)和146字節(jié)(包括了32字節(jié)的表格空間)。

代碼測試:僅代碼長度變短是不夠的,衡量優(yōu)化后的程序一個重要的標準是看優(yōu)化前后兩個函數(shù)執(zhí)行相同的計算量使用的時間,或者說執(zhí)行的效率是否提高了。如果優(yōu)化后的函數(shù)需要時間少,就說明我們優(yōu)化后的函數(shù)確實提高了效率,否則就是反而降低了程序的效率,優(yōu)化失敗。我在KeilC51下編寫了一個測試程序,在程序中調用了上面的六個函數(shù),共同計算一個長度為200字節(jié)的CRC校驗,并記錄下每個函數(shù)使用的時間。測試方法為:使用KeilC51的軟件仿真功能(采用帶計時功能的硬件仿真器也可以),在每個函數(shù)上加上斷點,記錄下執(zhí)行到每個斷點的時間,然后前后相減就得出每個函數(shù)的執(zhí)行時間。仿真時使用的單片機型號為AT89C51,晶體頻率為12MHz。

測試文件的源代碼為:

xdataunsignedcharbuf[200];

unsignedchari;

unsignedintcrc;

externunsignedintcrc0(unsignedchar*,unsignedchar);

externunsignedintcrc1(unsignedchar*,unsignedchar);

externunsignedintcrc2(unsignedchar*,unsignedchar);

externunsignedintcrc3(unsignedchar*,unsignedchar);

externunsignedintcrc4(unsignedchar*,unsignedchar);

externunsignedintcrc5(unsignedchar*,unsignedchar);

voidmain(void)

{

for(i=0;i<200;i++)

buf[i]=i+1;

crc=crc0(buf,200);

crc=crc1(buf,200);

crc=crc2(buf,200);

crc=crc3(buf,200);

crc=crc4(buf,200);

crc=crc5(buf,200);

i=0;

}

測試結果見表一:

函數(shù)

代碼長度(字節(jié))

執(zhí)行時間(微秒)

提高效率

查表法

Crc0

68+512=580

10626

28%

Crc1

44+512=556

7622

計算法

Crc2

76

30309

13.6%

Crc3

68

26186

查表+計算

Crc4

175

24229

18.2%

Crc5

146

19822

表一:三種CRC16校驗算法及其優(yōu)化的比較

從表中可以看出,優(yōu)化后的函數(shù)執(zhí)行速度都有了明顯的提高,這說明我們的優(yōu)化是很有效的。其實優(yōu)化前后的函數(shù)區(qū)別并不大,算法都是完全一樣的,只是個別地方的寫法調整了一下,但是取得的效果是非常明顯的。現(xiàn)在很多人寫單片機的程序,都帶有寫VC或C++的習慣,而沒有考慮到51單片機的特點,從而造成了一些資源的浪費。

這三種計算方法之間的對比也很清楚,查表法使用的時間最短,查表+計算次之,計算法最長,它們的執(zhí)行效率比為1:3.4:2.6,代碼效率比為8.1:1:2.1(優(yōu)化后的函數(shù))。從代碼長度看,查表法因為使用了一個相對較大的表格,所以代碼最長,適合于代碼空間比較充足的情況;計算法沒有使用任何表格,所以代碼長度最小,適合于ROM空間比較小的情況。而查表+計算法從執(zhí)行速度和代碼長度都是處于中流,是一種很好的折衷方案。

下面是我總結的一些C51編程優(yōu)化的幾個小技巧和方法:

1.盡量使用無符號的變量;

2.盡量使用data與idata寄存器變量;它們之間的效率順序為data>idata>xdata;

3.使用最小的變量類型,能使用整型時就不要使用長整型,能使用字符型時就不要使用整型;

4.多使用局部變量,少使用全局變量、靜態(tài)變量,這樣可以充分利用Keil提供的變量覆蓋技術。同時局部變量也要盡量使用寄存器變量;

5.少使用浮點數(shù)。使用浮點數(shù)需要連接浮點庫,會增加大約1K的代碼;而且浮點運算的速度是很慢的,沒有特殊情況盡量使用定點數(shù)代替浮點數(shù);

6.沒有必要就不要使用printf等標準輸入輸出函數(shù),它會增加大約3K的代碼。

7.函數(shù)帶有的參數(shù)不要太多,多了會影響效率;

8.注意C51的特點,按照C51的特點編寫程序;

9.多用幾種方法優(yōu)化,比較后找出最佳方法;

10.注意軟件的寫法,有時一個寫法上很小的變化就會有意想不到的效果。因為Keil的優(yōu)化是與上下文的程序相關的,對于不同的情況產生不同的優(yōu)化。如果對比一下產生的匯編代碼,就能夠更加容易的找出不合理的代碼,從而有針對性的優(yōu)化了;

11.不要過于依賴C51提供的優(yōu)化功能,能夠自己優(yōu)化的地方就自己手工優(yōu)化了,程序不可能完成所有的事情;

12.不同版本的C51(特別是6.0和7.0的版本與低于6.0的版本相比)產生的優(yōu)化效果可能會不同,產生的代碼會不完全一樣,需要特別注意;

13.在循環(huán)中比較條件盡量與0作比較(這與51單片機的特點有關,對比一下編譯產生的匯編代碼就明白了),這樣可以減少代碼,加快速度。如:

將while(n>10)修改為

while(n!=0);

14.在循環(huán)中比較中不要直接使用n--或n++,而要分開寫,這樣產生的代碼較小。

如:while(n--!=0)修改為

while(n!=0)

{

n--;

...//其他代碼

}

15.盡量不要使用太復雜的表達式,雖然這樣程序簡潔,但是對程序的調試不方便。

只要能充分考慮到所使用的單片機的特點,在加上一些經(jīng)驗和技巧,就一定可以編寫出高性能的程序來。

本站聲明: 本文章由作者或相關機構授權發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內容真實性等。需要轉載請聯(lián)系該專欄作者,如若文章內容侵犯您的權益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或將催生出更大的獨角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉型技術解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術公司SODA.Auto推出其旗艦產品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關鍵字: 汽車 人工智能 智能驅動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務中斷的風險,如企業(yè)系統(tǒng)復雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務連續(xù)性,提升韌性,成...

關鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產業(yè)博覽會開幕式在貴陽舉行,華為董事、質量流程IT總裁陶景文發(fā)表了演講。

關鍵字: 華為 12nm EDA 半導體

8月28日消息,在2024中國國際大數(shù)據(jù)產業(yè)博覽會上,華為常務董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權最終是由生態(tài)的繁榮決定的。

關鍵字: 華為 12nm 手機 衛(wèi)星通信

要點: 有效應對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務引領增長 以科技創(chuàng)新為引領,提升企業(yè)核心競爭力 堅持高質量發(fā)展策略,塑強核心競爭優(yōu)勢...

關鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術學會聯(lián)合牽頭組建的NVI技術創(chuàng)新聯(lián)盟在BIRTV2024超高清全產業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術創(chuàng)新聯(lián)...

關鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(集團)股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關鍵字: BSP 信息技術
關閉
關閉