新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > STM32F10x 學(xué)習(xí)筆記4(CRC計算單元 續(xù))

STM32F10x 學(xué)習(xí)筆記4(CRC計算單元 續(xù))

作者: 時間:2016-11-20 來源:網(wǎng)絡(luò) 收藏
上篇博客給出了 STM32F10X 系列單片機CRC 單元的用法。還指出了這個CRC 單元計算的結(jié)果與常見的CRC32 算法得到的結(jié)果不相同。但是為什么不相同,是什么原因造成的卻沒有寫出來。這里再補一篇,把這些都說清楚。

本文引用地址:http://m.butianyuan.cn/article/201611/318839.htm

下面先給個crc32的計算函數(shù),這個函數(shù)計算的結(jié)果與STM32F單片機上硬件單元的計算結(jié)果相同。

  1. uint32_tcrc32(uint32_t*addr,intnum,uint32_tcrc)
  2. {
  3. inti;
  4. for(;num>0;num--)
  5. {
  6. crc=crc^(*addr++);
  7. for(i=0;i<32;i++)
  8. {
  9. if(crc&0x80000000)
  10. crc=(crc<<1)^POLY;
  11. else
  12. crc<<=1;
  13. }
  14. crc&=0xFFFFFFFF;
  15. }
  16. return(crc);
  17. }

在我寫的文章《寫給嵌入式程序員的循環(huán)冗余校驗(CRC)算法入門引導(dǎo)》(http://blog.csdn.net/liyuanbhu/article/details/7882789)中給了個利用查表法計算crc的程序。那個程序稍微修改一點就能計算CRC32。下面給出改動后的程序。

  1. //crc32.h
  2. #ifndefCRC32_H_INCLUDED
  3. #defineCRC32_H_INCLUDED
  4. #ifdef__cplusplus
  5. #if__cplusplus
  6. extern"C"{
  7. #endif
  8. #endif/*__cplusplus*/
  9. #include
  10. /*
  11. *TheCRCparameters.CurrentlyconfiguredforCRC32.
  12. *CRC32=X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X1+X0
  13. */
  14. #definePOLYNOMIAL0x04C11DB7
  15. #defineINITIAL_REMAINDER0xFFFFFFFF
  16. #defineFINAL_XOR_VALUE0x00000000
  17. /*
  18. *ThewidthoftheCRCcalculationandresult.
  19. *Modifythetypedefforan8or32-bitCRCstandard.
  20. */
  21. typedefuint32_twidth_t;
  22. #defineWIDTH(8*sizeof(width_t))
  23. #defineTOPBIT(1<<(WIDTH-1))
  24. /**
  25. *InitializetheCRClookuptable.
  26. *ThistableisusedbycrcCompute()tomakeCRCcomputationfaster.
  27. */
  28. voidcrcInit(void);
  29. /**
  30. *ComputetheCRCchecksumofabinarymessageblock.
  31. *@paramessage,用來計算的數(shù)據(jù)
  32. *@paranBytes,數(shù)據(jù)的長度
  33. *@noteThisfunctionexpectsthatcrcInit()hasbeencalled
  34. *firsttoinitializetheCRClookuptable.
  35. */
  36. width_tcrcCompute(unsignedchar*message,unsignedintnBytes,width_tremainder);
  37. #ifdef__cplusplus
  38. #if__cplusplus
  39. }
  40. #endif
  41. #endif/*__cplusplus*/
  42. #endif//CRC32_H_INCLUDED

對應(yīng)的C程序如下:

  1. #include"crc32.h"
  2. /*
  3. *Anarraycontainingthepre-computedintermediateresultforeach
  4. *possiblebyteofinput.Thisisusedtospeedupthecomputation.
  5. */
  6. staticwidth_tcrcTable[256];
  7. /**
  8. *InitializetheCRClookuptable.
  9. *ThistableisusedbycrcCompute()tomakeCRCcomputationfaster.
  10. */
  11. voidcrcInit(void)
  12. {
  13. width_tremainder;
  14. width_tdividend;
  15. intbit;
  16. /*Performbinarylongdivision,abitatatime.*/
  17. for(dividend=0;dividend<256;dividend++)
  18. {
  19. /*Initializetheremainder.*/
  20. remainder=dividend<<(WIDTH-8);
  21. /*ShiftandXORwiththepolynomial.*/
  22. for(bit=0;bit<8;bit++)
  23. {
  24. /*Trytodividethecurrentdatabit.*/
  25. if(remainder&TOPBIT)
  26. {
  27. remainder=(remainder<<1)^POLYNOMIAL;
  28. }
  29. else
  30. {
  31. remainder=remainder<<1;
  32. }
  33. }
  34. /*Savetheresultinthetable.*/
  35. crcTable[dividend]=remainder;
  36. }
  37. }/*crcInit()*/
  38. /**
  39. *ComputetheCRCchecksumofabinarymessageblock.
  40. *@paramessage,用來計算的數(shù)據(jù)
  41. *@paranBytes,數(shù)據(jù)的長度
  42. *@noteThisfunctionexpectsthatcrcInit()hasbeencalled
  43. *firsttoinitializetheCRClookuptable.
  44. */
  45. width_tcrcCompute(unsignedchar*message,unsignedintnBytes,width_tremainder)
  46. {
  47. unsignedintoffset;
  48. unsignedcharbyte;
  49. //width_tremainder=INITIAL_REMAINDER;
  50. /*Dividethemessagebythepolynomial,abyteatatime.*/
  51. for(offset=0;offset
  52. {
  53. byte=(remainder>>(WIDTH-8))^message[offset];
  54. remainder=crcTable[byte]^(remainder<<8);
  55. }
  56. /*ThefinalremainderistheCRCresult.*/
  57. return(remainder^FINAL_XOR_VALUE);
  58. }/*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。

  1. uint32_tstm32crc32(uint32_t*message,unsignedintnWords,uint32_tremainder)
  2. {
  3. unsignedintoffset;
  4. unsignedcharbyte;
  5. unsignedchar*p=(unsignedchar*)message;
  6. //width_tremainder=INITIAL_REMAINDER;
  7. /*Dividethemessagebythepolynomial,abyteatatime.*/
  8. for(offset=0;offset
  9. {
  10. byte=(remainder>>(WIDTH-8))^p[3];
  11. remainder=crcTable[byte]^(remainder<<8);
  12. byte=(remainder>>(WIDTH-8))^p[2];
  13. remainder=crcTable[byte]^(remainder<<8);
  14. byte=(remainder>>(WIDTH-8))^p[1];
  15. remainder=crcTable[byte]^(remainder<<8);
  16. byte=(remainder>>(WIDTH-8))^p[0];
  17. remainder=crcTable[byte]^(remainder<<8);
  18. p+=4;
  19. }
  20. /*ThefinalremainderistheCRCresult.*/
  21. return(remainder);
  22. }/*crcCompute()*/

大家可以驗證這個函數(shù)的計算結(jié)果與STM32上的結(jié)果完全一樣。

寫到這里本該就結(jié)束了,不過我要多說一句,之所以要這么麻煩的調(diào)換字節(jié)序,都是小端(littleendian)惹的禍。要是都采用大端格式就沒這些麻煩的轉(zhuǎn)換了。



關(guān)鍵詞: STM32F10xCRC計算單

評論


技術(shù)專區(qū)

關(guān)閉