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

发布者:vettykatty最新更新时间:2016-05-05 来源: eefocus关键字:STM32F10x  CRC  计算单元 手机看文章 扫描二维码
随时随地手机看文章
上篇博客给出了 STM32F10X 系列单片机中CRC 单元的用法。还指出了这个CRC 单元计算的结果与常见的CRC32 算法得到的结果不相同。但是为什么不相同,是什么原因造成的却没有写出来。这里再补一篇,把这些都说清楚。

 

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

 

  1. uint32_t crc32(uint32_t *addr, int num, uint32_t crc)  
  2. {  
  3.     int i;  
  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.   
  3. #ifndef CRC32_H_INCLUDED  
  4. #define CRC32_H_INCLUDED  
  5.   
  6. #ifdef __cplusplus  
  7. #if __cplusplus  
  8. extern "C"{  
  9.     #endif  
  10.     #endif /* __cplusplus */  
  11.   
  12.   
  13. #include  
  14.   
  15. /* 
  16. * The CRC parameters. Currently configured for CRC32. 
  17. * CRC32=X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X1+X0 
  18. */  
  19.   
  20. #define POLYNOMIAL          0x04C11DB7  
  21. #define INITIAL_REMAINDER   0xFFFFFFFF  
  22. #define FINAL_XOR_VALUE     0x00000000  
  23.   
  24. /* 
  25. * The width of the CRC calculation and result. 
  26. * Modify the typedef for an 8 or 32-bit CRC standard. 
  27. */  
  28. typedef uint32_t width_t;  
  29. #define WIDTH (8 * sizeof(width_t))  
  30. #define TOPBIT (1 << (WIDTH - 1))  
  31.   
  32. /** 
  33.  * Initialize the CRC lookup table. 
  34.  * This table is used by crcCompute() to make CRC computation faster. 
  35.  */  
  36. void crcInit(void);  
  37.   
  38. /** 
  39.  * Compute the CRC checksum of a binary message block. 
  40.  * @para message, 用来计算的数据 
  41.  * @para nBytes, 数据的长度 
  42.  * @note This function expects that crcInit() has been called 
  43.  *       first to initialize the CRC lookup table. 
  44.  */  
  45. width_t crcCompute(unsigned char * message, unsigned int nBytes, width_t remainder);  
  46.   
  47.   
  48. #ifdef __cplusplus  
  49.     #if __cplusplus  
  50. }  
  51. #endif  
  52. #endif /* __cplusplus */  
  53.   
  54. #endif // CRC32_H_INCLUDED  

 

对应的C程序如下:

 

  1. #include "crc32.h"  
  2. /* 
  3. * An array containing the pre-computed intermediate result for each 
  4. * possible byte of input. This is used to speed up the computation. 
  5. */  
  6. static width_t crcTable[256];  
  7.   
  8. /** 
  9.  * Initialize the CRC lookup table. 
  10.  * This table is used by crcCompute() to make CRC computation faster. 
  11.  */  
  12. void crcInit(void)  
  13. {  
  14.     width_t remainder;  
  15.     width_t dividend;  
  16.     int bit;  
  17.     /* Perform binary long division, a bit at a time. */  
  18.     for(dividend = 0; dividend < 256; dividend++)  
  19.     {  
  20.         /* Initialize the remainder.  */  
  21.         remainder = dividend << (WIDTH - 8);  
  22.         /* Shift and XOR with the polynomial.   */  
  23.         for(bit = 0; bit < 8; bit++)  
  24.         {  
  25.             /* Try to divide the current data bit.  */  
  26.             if(remainder & TOPBIT)  
  27.             {  
  28.                 remainder = (remainder << 1) ^ POLYNOMIAL;  
  29.             }  
  30.             else  
  31.             {  
  32.                 remainder = remainder << 1;  
  33.             }  
  34.         }  
  35.         /* Save the result in the table. */  
  36.         crcTable[dividend] = remainder;  
  37.     }  
  38. } /* crcInit() */  
  39.   
  40. /** 
  41.  * Compute the CRC checksum of a binary message block. 
  42.  * @para message, 用来计算的数据 
  43.  * @para nBytes, 数据的长度 
  44.  * @note This function expects that crcInit() has been called 
  45.  *       first to initialize the CRC lookup table. 
  46.  */  
  47. width_t crcCompute(unsigned char * message, unsigned int nBytes, width_t remainder)  
  48. {  
  49.     unsigned int offset;  
  50.     unsigned char byte;  
  51.     //width_t remainder = INITIAL_REMAINDER;  
  52.     /* Divide the message by the polynomial, a byte at a time. */  
  53.     for( offset = 0; offset < nBytes; offset++)  
  54.     {  
  55.         byte = (remainder >> (WIDTH - 8)) ^ message[offset];  
  56.         remainder = crcTable[byte] ^ (remainder << 8);  
  57.     }  
  58.     /* The final remainder is the CRC result. */  
  59.     return (remainder ^ FINAL_XOR_VALUE);  
  60. } /* 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_t stm32crc32(uint32_t * message, unsigned int nWords, uint32_t remainder)  
  2. {  
  3.     unsigned int offset;  
  4.     unsigned char byte;  
  5.     unsigned char *p = (unsigned char *)message;  
  6.     //width_t remainder = INITIAL_REMAINDER;  
  7.     /* Divide the message by the polynomial, a byte at a time. */  
  8.     for( offset = 0; offset < nWords; offset++)  
  9.     {  
  10.         byte = (remainder >> (WIDTH - 8)) ^ p[3];  
  11.         remainder = crcTable[byte] ^ (remainder << 8);  
  12.   
  13.         byte = (remainder >> (WIDTH - 8)) ^ p[2];  
  14.         remainder = crcTable[byte] ^ (remainder << 8);  
  15.   
  16.         byte = (remainder >> (WIDTH - 8)) ^ p[1];  
  17.         remainder = crcTable[byte] ^ (remainder << 8);  
  18.   
  19.         byte = (remainder >> (WIDTH - 8)) ^ p[0];  
  20.         remainder = crcTable[byte] ^ (remainder << 8);  
  21.   
  22.         p += 4;  
  23.     }  
  24.     /* The final remainder is the CRC result. */  
  25.     return (remainder);  
  26. } /* crcCompute() */  

 

大家可以验证这个函数的计算结果与STM32上的结果完全一样。

写到这里本该就结束了,不过我要多说一句,之所以要这么麻烦的调换字节序,都是小端(little endian)惹的祸。要是都采用大端格式就没这些麻烦的转换了。

关键字:STM32F10x  CRC  计算单元 引用地址:STM32F10x 学习笔记4(CRC计算单元 续)

上一篇:STM32F10x 学习笔记5(USART实现串口通讯 1)
下一篇:STM32F10x 学习笔记3(CRC计算单元)

推荐阅读最新更新时间:2024-03-16 14:52

STM32F10x处理器在应用中编程的实现方法
引 言 Cortex-M3是首款基于ARMv7-M体系结构的32位标准处理器,RISC结构,包含高效灵活的Thumb-2指令集,拥有杰出的低功耗特性,为微控制器系统、汽车车身控制系统、工业控制系统和无线网络等嵌入式应用量身设计。ST公司推出基于Cortex-M3内核的STM32系列处理器,凭借其出众的性能、创新的外设、优越的功耗控制,得到众多工程师的青睐。 针对嵌入式应用的特点,STM32处理器提供功能强大的硬件调试接口——JTAG接口和串行接口,极大方便了设计,缩短了产品的开发周期。不仅如此,STM32处理器内嵌的闪存存储器允许在电路编程(In-Circuit Pro-gramming,ICP)和在应用中编程(In-Ap
[单片机]
<font color='red'>STM32F10x</font>处理器在应用中编程的实现方法
自学STM32F10x单片机需要注意的地方
由于之前一直使用PIC和51的芯片,从没接触过STM32系列的芯片,近期着手学习STM32F10x的芯片,通过学习后发现STM32的中断系统比较特殊(与PIC和51相比较........),有着不同的响应方式,看了几遍相关的手册和视频资料,还是有些稀里糊涂,通过实际写代码配置芯片后,逐渐有点眉目了,因此想记录下来,算是总结笔记。当然文章中有存在描述错误和不足的地方,还请大家指正。(可能有些地方理解的方式存在问题,望指教。) STM32采用了ARM Cortex_M3内核,而Cortex_M3内核具有256个中断源,其中内核自己的有16个中断源和外部设备的(最多)240个中断源,每个中断源都具有自己独立的中断优先级控制寄存器,该
[单片机]
自学<font color='red'>STM32F10x</font>单片机需要注意的地方
40位以内任意长度的CRC计算及校验的实现
1 引言    循环冗余校验码,简称CRC码,是常用的检测错误码,它在数据通信中得到了非常广泛的应用。不同CRC码的生成多项式各不相同,CRC码的比特数也不同,且在有的通信协议中要求将余数寄存器先初始化为全0,另外的则须初始化为全1。因此,在程序设计时必须充分利用CRC码的共性及所用DSP的指令特点。 2 用TMS320C5000实现不同CRC计算的设计思想 CRC码的计算及校验都用到模2的多项式除法,而多项式除法可以采用带反馈的移位寄存器来实现,因此,用DSP来实现CRC计算的关键是通过DSP来模拟一个移位寄存器(也就是模拟手写多项式除法)。考虑到TMS320C5000系列DSP的累加器A和B均为40位,
[网络通信]
单片机CRC源码
1 /****************************************************************************************** 2 * 函数功能:CRC校验用函数 3 * 函数输入:puchMsgg是要进行CRC校验的消息,usDataLen是消息中字节数 4 * 函数输出:计算出来的CRC校验码。 5 ****************************************************************8*************************/ 6 uint16_t CRC16(uint8_t *puchMsgg,uint
[单片机]
STM32F10X软加密方法及实例代码
  ///////////tst//STM32F10X软加密方法及实例代码//////////////////////////////   #define ID_ENCRYPT_EOR_RESULT_ADDRESS (0x0800F000)   #define ID_ENCRYPT_ADD_RESULT_ADDRESS (0x0800F004)   volatile uint32 gU32IdAdressVar;//这里一定要定义此变量,否则会被优化器优化掉   void Stm32F10xEncryptDemo(void)   {   uint32 *u32IdAddress;   uint32 u32EorRslt, u3
[单片机]
STM32F10x 学习笔记7独立看门狗IWDG 模块
按照STM32参考手册的说法: 独立看门狗(IWDG)由专用的低速时钟(LSI)驱动,即使主时钟发生故障它也仍然有效。IWDG最适合应用于那些需要看门狗作为一个在主程序之外,能够完全独立工作,并且对时间精度要求较低的场合。WWDG最适合那些要求看门狗在精确计时窗口起作用的应用程序。 简单的说,STM32 中的IWDG 其核心就是一个12bits的向下递减的计数器,当计数器计数到零时就会触发系统复位。因此,要在每次计数到零之前将其复位到一个初始值。这个初始值就在重装载寄存器(IWDG_RLR)中存放,其默认值为0xFFF,我们也可以将其改为其他值。 计数器的时钟由LSI时钟经过分频后提供,预分频因子由预分频寄存器(IWDG
[单片机]
<font color='red'>STM32F10x</font> 学习笔记7独立看门狗IWDG 模块
STM32F10X USART 中断接受+发送,测试无误
硬件平台:STM32F10X USART模块 + JLink+USB转TTL小板 软件平台:Keil 4 前一个程序只是作为下位机的MCU将数据发送给串口助手,也就是上位机,相当于单工通信,对于一个完整的通信来说只是完成了一半的功能。 这是一个完整的通信例程,作为下位机的单片机可以将数据发送给上位机,也可以检测上位机是否发了数据回来。中断方式检测,如果接收到数据,则将数据发送给上位机,相当于半双工模式。 其实与基础的51串口通信无实质区别,只是STM32相关寄存器配置稍微复杂些而已。相比于前一个发送程序,只是在中断检测和主函数里做了相应的修改而已,RCC模块、USART模块与GPIO模块配置基本没变。 二、发送程序例程 程序涉及
[单片机]
STM32CubeMX配置硬件CRC
实验目的: 通过STM32CubeMX进行简单配置生成HAL库实现硬件CRC32校验的功能。 一、STM32CubeMX配置如下: 二、生成的HAL库源码如下: 三、Debug结果如下: 对字符串 DA0000000000 进行CRC32计算结果如下: 四、在线工具CRC校验结果如下: 完美,收工!
[单片机]
STM32CubeMX配置硬件<font color='red'>CRC</font>
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved