STM32F10x 學(xué)習筆記4(CRC計算單元 續)
下面先給個(gè)crc32的計算函數,這個(gè)函數計算的結果與STM32F單片機上硬件單元的計算結果相同。
- uint32_tcrc32(uint32_t*addr,intnum,uint32_tcrc)
- {
- inti;
- for(;num>0;num--)
- {
- crc=crc^(*addr++);
- for(i=0;i<32;i++)
- {
- if(crc&0x80000000)
- crc=(crc<<1)^POLY;
- else
- crc<<=1;
- }
- crc&=0xFFFFFFFF;
- }
- return(crc);
- }
在我寫(xiě)的文章《寫(xiě)給嵌入式程序員的循環(huán)冗余校驗(CRC)算法入門(mén)引導》(http://blog.csdn.net/liyuanbhu/article/details/7882789)中給了個(gè)利用查表法計算crc的程序。那個(gè)程序稍微修改一點(diǎn)就能計算CRC32。下面給出改動(dòng)后的程序。
- //crc32.h
- #ifndefCRC32_H_INCLUDED
- #defineCRC32_H_INCLUDED
- #ifdef__cplusplus
- #if__cplusplus
- extern"C"{
- #endif
- #endif/*__cplusplus*/
- #include
- /*
- *TheCRCparameters.CurrentlyconfiguredforCRC32.
- *CRC32=X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X1+X0
- */
- #definePOLYNOMIAL0x04C11DB7
- #defineINITIAL_REMAINDER0xFFFFFFFF
- #defineFINAL_XOR_VALUE0x00000000
- /*
- *ThewidthoftheCRCcalculationandresult.
- *Modifythetypedefforan8or32-bitCRCstandard.
- */
- typedefuint32_twidth_t;
- #defineWIDTH(8*sizeof(width_t))
- #defineTOPBIT(1<<(WIDTH-1))
- /**
- *InitializetheCRClookuptable.
- *ThistableisusedbycrcCompute()tomakeCRCcomputationfaster.
- */
- voidcrcInit(void);
- /**
- *ComputetheCRCchecksumofabinarymessageblock.
- *@paramessage,用來(lái)計算的數據
- *@paranBytes,數據的長(cháng)度
- *@noteThisfunctionexpectsthatcrcInit()hasbeencalled
- *firsttoinitializetheCRClookuptable.
- */
- width_tcrcCompute(unsignedchar*message,unsignedintnBytes,width_tremainder);
- #ifdef__cplusplus
- #if__cplusplus
- }
- #endif
- #endif/*__cplusplus*/
- #endif//CRC32_H_INCLUDED
對應的C程序如下:
- #include"crc32.h"
- /*
- *Anarraycontainingthepre-computedintermediateresultforeach
- *possiblebyteofinput.Thisisusedtospeedupthecomputation.
- */
- staticwidth_tcrcTable[256];
- /**
- *InitializetheCRClookuptable.
- *ThistableisusedbycrcCompute()tomakeCRCcomputationfaster.
- */
- voidcrcInit(void)
- {
- width_tremainder;
- width_tdividend;
- intbit;
- /*Performbinarylongdivision,abitatatime.*/
- for(dividend=0;dividend<256;dividend++)
- {
- /*Initializetheremainder.*/
- remainder=dividend<<(WIDTH-8);
- /*ShiftandXORwiththepolynomial.*/
- for(bit=0;bit<8;bit++)
- {
- /*Trytodividethecurrentdatabit.*/
- if(remainder&TOPBIT)
- {
- remainder=(remainder<<1)^POLYNOMIAL;
- }
- else
- {
- remainder=remainder<<1;
- }
- }
- /*Savetheresultinthetable.*/
- crcTable[dividend]=remainder;
- }
- }/*crcInit()*/
- /**
- *ComputetheCRCchecksumofabinarymessageblock.
- *@paramessage,用來(lái)計算的數據
- *@paranBytes,數據的長(cháng)度
- *@noteThisfunctionexpectsthatcrcInit()hasbeencalled
- *firsttoinitializetheCRClookuptable.
- */
- width_tcrcCompute(unsignedchar*message,unsignedintnBytes,width_tremainder)
- {
- unsignedintoffset;
- unsignedcharbyte;
- //width_tremainder=INITIAL_REMAINDER;
- /*Dividethemessagebythepolynomial,abyteatatime.*/
- for(offset=0;offset
- {
- byte=(remainder>>(WIDTH-8))^message[offset];
- remainder=crcTable[byte]^(remainder<<8);
- }
- /*ThefinalremainderistheCRCresult.*/
- return(remainder^FINAL_XOR_VALUE);
- }/*crcCompute()*/
不過(guò)用這個(gè)程序直接計算得到的CRC值與STM32給出的并不相同。之所以會(huì )這樣是因為字節序的原因??梢耘e個(gè)例子來(lái)說(shuō)明這個(gè)問(wèn)題。比如我們有一片內存區域要計算CRC值。這片內存區域的起始地址是0x1000,共有8個(gè)字節。用crcCompute()函數計算時(shí)是按照地址順序依次傳入各個(gè)字節。也就是先計算0x1000處的字節,再計算0x0001處的字節,以此類(lèi)推最后計算0x1007地址處的字節。而STM32的硬件CRC單元是以32位的字為單位計算的。我們知道CRC實(shí)際上是個(gè)多項式的除法運算,而除法運算是從高位算起的。也就是相當于它是按照0x1003、0x1002、0x1001、0x1000這個(gè)順序計算第一個(gè)字,然后按照0x1007、0x1006、0x1005、x1004的順序計算第二個(gè)字。因此。我們要是預先將字節序調換一下得到結果就沒(méi)有問(wèn)題了。這就有了下面的改造。其中remainder傳入0xffffffff。因為STM32中的CRC余數初始值為0xffffffff。
- uint32_tstm32crc32(uint32_t*message,unsignedintnWords,uint32_tremainder)
- {
- unsignedintoffset;
- unsignedcharbyte;
- unsignedchar*p=(unsignedchar*)message;
- //width_tremainder=INITIAL_REMAINDER;
- /*Dividethemessagebythepolynomial,abyteatatime.*/
- for(offset=0;offset
- {
- byte=(remainder>>(WIDTH-8))^p[3];
- remainder=crcTable[byte]^(remainder<<8);
- byte=(remainder>>(WIDTH-8))^p[2];
- remainder=crcTable[byte]^(remainder<<8);
- byte=(remainder>>(WIDTH-8))^p[1];
- remainder=crcTable[byte]^(remainder<<8);
- byte=(remainder>>(WIDTH-8))^p[0];
- remainder=crcTable[byte]^(remainder<<8);
- p+=4;
- }
- /*ThefinalremainderistheCRCresult.*/
- return(remainder);
- }/*crcCompute()*/
大家可以驗證這個(gè)函數的計算結果與STM32上的結果完全一樣。
寫(xiě)到這里本該就結束了,不過(guò)我要多說(shuō)一句,之所以要這么麻煩的調換字節序,都是小端(littleendian)惹的禍。要是都采用大端格式就沒(méi)這些麻煩的轉換了。
評論