新聞中心

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

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

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

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

下面先給個(gè)crc32的計(jì)算函數(shù),這個(gè)函數(shù)計(jì)算的結(jié)果與STM32F單片機(jī)上硬件單元的計(jì)算結(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)冗余校驗(yàn)(CRC)算法入門引導(dǎo)》(http://blog.csdn.net/liyuanbhu/article/details/7882789)中給了個(gè)利用查表法計(jì)算crc的程序。那個(gè)程序稍微修改一點(diǎn)就能計(jì)算CRC32。下面給出改動(dòng)后的程序。

  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,用來計(jì)算的數(shù)據(jù)
  32. *@paranBytes,數(shù)據(jù)的長(zhǎng)度
  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

對(duì)應(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,用來計(jì)算的數(shù)據(jù)
  41. *@paranBytes,數(shù)據(jù)的長(zhǎng)度
  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()*/

不過用這個(gè)程序直接計(jì)算得到的CRC值與STM32給出的并不相同。之所以會(huì)這樣是因?yàn)樽止?jié)序的原因。可以舉個(gè)例子來說明這個(gè)問題。比如我們有一片內(nèi)存區(qū)域要計(jì)算CRC值。這片內(nèi)存區(qū)域的起始地址是0x1000,共有8個(gè)字節(jié)。用crcCompute()函數(shù)計(jì)算時(shí)是按照地址順序依次傳入各個(gè)字節(jié)。也就是先計(jì)算0x1000處的字節(jié),再計(jì)算0x0001處的字節(jié),以此類推最后計(jì)算0x1007地址處的字節(jié)。而STM32的硬件CRC單元是以32位的字為單位計(jì)算的。我們知道CRC實(shí)際上是個(gè)多項(xiàng)式的除法運(yùn)算,而除法運(yùn)算是從高位算起的。也就是相當(dāng)于它是按照0x1003、0x1002、0x1001、0x1000這個(gè)順序計(jì)算第一個(gè)字,然后按照0x1007、0x1006、0x1005、x1004的順序計(jì)算第二個(gè)字。因此。我們要是預(yù)先將字節(jié)序調(diào)換一下得到結(jié)果就沒有問題了。這就有了下面的改造。其中remainder傳入0xffffffff。因?yàn)镾TM32中的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()*/

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

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



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

評(píng)論


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

關(guān)閉