您的位置 首页 硬件

STM32F10x 学习笔记4(CRC核算单元 续)

上篇博客给出了STM32F10X系列单片机中CRC单元的用法。还指出了这个CRC单元计算的结果与常见的CRC32算法得到的结果不相同。但是为…

上篇博客给出了 STM32F10X 系列单片机CRC 单元的用法。还指出了这个CRC 单元核算的成果与常见的CRC32 算法得到的成果不相同。可是为什么不相同,是什么原因形成的却没有写出来。这儿再补一篇,把这些都说清楚。

下面先给个crc32的核算函数,这个函数核算的成果与STM32F单片机上硬件单元的核算成果相同。

  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. }

在我写的文章《写给嵌入式程序员的循环冗余校验(CRC)算法入门引导》(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,用来核算的数据
  32. *@paranBytes,数据的长度
  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

对应的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,用来核算的数据
  41. *@paranBytes,数据的长度
  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给出的并不相同。之所以会这样是由于字节序的原因。能够举个比方来阐明这个问题。比方咱们有一片内存区域要核算CRC值。这片内存区域的开始地址是0x1000,共有8个字节。用crcCompute()函数核算时是依照地址次序顺次传入各个字节。也便是先核算0x1000处的字节,再核算0x0001处的字节,以此类推最终核算0x1007地址处的字节。而STM32的硬件CRC单元是以32位的字为单位核算的。咱们知道CRC实际上是个多项式的除法运算,而除法运算是从高位算起的。也便是相当于它是依照0x1003、0x1002、0x1001、0x1000这个次序核算榜首个字,然后依照0x1007、0x1006、0x1005、x1004的次序核算第二个字。因而。咱们要是预先将字节序互换一下得到成果就没有问题了。这就有了下面的改造。其间remainder传入0xffffffff。由于STM32中的CRC余数初始值为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()*/

我们能够验证这个函数的核算成果与STM32上的成果彻底相同。

写到这儿本该就完毕了,不过我要多说一句,之所以要这么费事的互换字节序,都是小端(littleendian)惹的祸。要是都选用大端格局就没这些费事的转换了。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/qianrushi/yingjian/264203.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部