STM32F10x 學(xué)習(xí)筆記4(CRC計算單元 續(xù))
下面先給個crc32的計算函數(shù),這個函數(shù)計算的結(jié)果與STM32F單片機上硬件單元的計算結(jié)果相同。
- 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);
- }
在我寫的文章《寫給嵌入式程序員的循環(huán)冗余校驗(CRC)算法入門引導(dǎo)》(http://blog.csdn.net/liyuanbhu/article/details/7882789)中給了個利用查表法計算crc的程序。那個程序稍微修改一點就能計算CRC32。下面給出改動后的程序。
- //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,用來計算的數(shù)據(jù)
- *@paranBytes,數(shù)據(jù)的長度
- *@noteThisfunctionexpectsthatcrcInit()hasbeencalled
- *firsttoinitializetheCRClookuptable.
- */
- width_tcrcCompute(unsignedchar*message,unsignedintnBytes,width_tremainder);
- #ifdef__cplusplus
- #if__cplusplus
- }
- #endif
- #endif/*__cplusplus*/
- #endif//CRC32_H_INCLUDED
對應(yīng)的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,用來計算的數(shù)據(jù)
- *@paranBytes,數(shù)據(jù)的長度
- *@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()*/
不過用這個程序直接計算得到的CRC值與STM32給出的并不相同。之所以會這樣是因為字節(jié)序的原因。可以舉個例子來說明這個問題。比如我們有一片內(nèi)存區(qū)域要計算CRC值。這片內(nèi)存區(qū)域的起始地址是0x1000,共有8個字節(jié)。用crcCompute()函數(shù)計算時是按照地址順序依次傳入各個字節(jié)。也就是先計算0x1000處的字節(jié),再計算0x0001處的字節(jié),以此類推最后計算0x1007地址處的字節(jié)。而STM32的硬件CRC單元是以32位的字為單位計算的。我們知道CRC實際上是個多項式的除法運算,而除法運算是從高位算起的。也就是相當(dāng)于它是按照0x1003、0x1002、0x1001、0x1000這個順序計算第一個字,然后按照0x1007、0x1006、0x1005、x1004的順序計算第二個字。因此。我們要是預(yù)先將字節(jié)序調(diào)換一下得到結(jié)果就沒有問題了。這就有了下面的改造。其中remainder傳入0xffffffff。因為STM32中的CRC余數(shù)初始值為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()*/
大家可以驗證這個函數(shù)的計算結(jié)果與STM32上的結(jié)果完全一樣。
寫到這里本該就結(jié)束了,不過我要多說一句,之所以要這么麻煩的調(diào)換字節(jié)序,都是小端(littleendian)惹的禍。要是都采用大端格式就沒這些麻煩的轉(zhuǎn)換了。
評論