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

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

uint32_t crc32(uint32_t *addr, int num, uint32_t crc)
{int i;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);
}

在我写的文章《写给嵌入式程序员的循环冗余校验(CRC)算法入门引导》(http://blog.csdn.net/liyuanbhu/article/details/7882789) 中给了个利用查表法计算crc 的程序。那个程序稍微修改一点就能计算CRC32。下面给出改动后的程序。

//crc32.h#ifndef CRC32_H_INCLUDED
#define CRC32_H_INCLUDED#ifdef __cplusplus
#if __cplusplus
extern "C"{#endif#endif /* __cplusplus */#include<stdint.h>/*
* The CRC parameters. Currently configured for CRC32.
* CRC32=X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X1+X0
*/#define POLYNOMIAL          0x04C11DB7
#define INITIAL_REMAINDER   0xFFFFFFFF
#define FINAL_XOR_VALUE     0x00000000/*
* The width of the CRC calculation and result.
* Modify the typedef for an 8 or 32-bit CRC standard.
*/
typedef uint32_t width_t;
#define WIDTH (8 * sizeof(width_t))
#define TOPBIT (1 << (WIDTH - 1))/*** Initialize the CRC lookup table.* This table is used by crcCompute() to make CRC computation faster.*/
void crcInit(void);/*** Compute the CRC checksum of a binary message block.* @para message, 用来计算的数据* @para nBytes, 数据的长度* @note This function expects that crcInit() has been called*       first to initialize the CRC lookup table.*/
width_t crcCompute(unsigned char * message, unsigned int nBytes, width_t remainder);#ifdef __cplusplus#if __cplusplus
}
#endif
#endif /* __cplusplus */#endif // CRC32_H_INCLUDED

对应的C程序如下:

#include "crc32.h"
/*
* An array containing the pre-computed intermediate result for each
* possible byte of input. This is used to speed up the computation.
*/
static width_t crcTable[256];/*** Initialize the CRC lookup table.* This table is used by crcCompute() to make CRC computation faster.*/
void crcInit(void)
{width_t remainder;width_t dividend;int bit;/* Perform binary long division, a bit at a time. */for(dividend = 0; dividend < 256; dividend++){/* Initialize the remainder.  */remainder = dividend << (WIDTH - 8);/* Shift and XOR with the polynomial.   */for(bit = 0; bit < 8; bit++){/* Try to divide the current data bit.  */if(remainder & TOPBIT){remainder = (remainder << 1) ^ POLYNOMIAL;}else{remainder = remainder << 1;}}/* Save the result in the table. */crcTable[dividend] = remainder;}
} /* crcInit() *//*** Compute the CRC checksum of a binary message block.* @para message, 用来计算的数据* @para nBytes, 数据的长度* @note This function expects that crcInit() has been called*       first to initialize the CRC lookup table.*/
width_t crcCompute(unsigned char * message, unsigned int nBytes, width_t remainder)
{unsigned int offset;unsigned char byte;//width_t remainder = INITIAL_REMAINDER;/* Divide the message by the polynomial, a byte at a time. */for( offset = 0; offset < nBytes; offset++){byte = (remainder >> (WIDTH - 8)) ^ message[offset];remainder = crcTable[byte] ^ (remainder << 8);}/* The final remainder is the CRC result. */return (remainder ^ FINAL_XOR_VALUE);
} /* 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。

uint32_t stm32crc32(uint32_t * message, unsigned int nWords, uint32_t remainder)
{unsigned int offset;unsigned char byte;unsigned char *p = (unsigned char *)message;//width_t remainder = INITIAL_REMAINDER;/* Divide the message by the polynomial, a byte at a time. */for( offset = 0; offset < nWords; 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;}/* The final remainder is the CRC result. */return (remainder);
} /* crcCompute() */

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

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

STM32F10x 学习笔记4(CRC计算单元 续)相关推荐

  1. Word2Vec学习笔记(三)续

    三.(续)Skip-gram模型介绍 Skip-gram模型并不是和CBOW模型相反的,它们的目的都是计算出词的向量,只不过在作者的论文中给出的图看样子是反的而已.Skip-gram模型是用每个当前词 ...

  2. Java学习笔记7-面向对象(续)

    一个国家有很多省,省又分为市,市里面又分为县或者镇,省与省之间又有很多不同的特色.之所以这样去分就是因为好区分,便于管理,这种原理和Java里面的包(package)很相似. 1.package(包) ...

  3. STM32学习笔记(9)——(I2C续)读写EEPROM

    STM32学习笔记(9)--(I2C续)读写EEPROM 一.概述 1. 背景介绍 2. EEPROM简介 二.AT24C02--常用的EEPROM 1. 电路原理图 2. 写操作 (1)按字节写操作 ...

  4. STM32CubeMX学习笔记(22)——CRC接口使用

    一.CRC简介 CRC(Cyclic Redundancy Check),即循环冗余校验,是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种信道编码技术,主要用来检测或校验数据传输或者 ...

  5. 学习笔记——CRC的基本原理与实现

    文章目录 笔记前言 一.CRC是什么? 二.CRC基本原理 1.原理介绍与练习 2.CRC-8 示例代码 总结 笔记前言 此篇是学习CRC基本原理与实现的个人学习笔记,以备未来自己复习使用,也将自己学 ...

  6. 【Stage3D学习笔记续】山寨Starling(八):核心优化(批处理)的实现

    批处理是使GPU进行高效绘制的一种技术手段,也是整个渲染流程中最核心的技术,到目前为止我们并没有使用到这种技术手段,下面我们看看我们现在的渲染机制. 先想一想我们最开始是怎么向GPU绘制一幅图像的,可 ...

  7. 机器学习框架ML.NET学习笔记【5】多元分类之手写数字识别(续)

    一.概述 上一篇文章我们利用ML.NET的多元分类算法实现了一个手写数字识别的例子,这个例子存在一个问题,就是输入的数据是预处理过的,很不直观,这次我们要直接通过图片来进行学习和判断.思路很简单,就是 ...

  8. STM32学习笔记(15)——SPI协议

    STM32学习笔记(15)--SPI协议 一.SPI协议简介 1. 物理层 2. 协议层 (1) 通讯的开始与停止 (2)时钟极性CPOL.时钟相位CPHA 二.STM32的SPI外设 1. 通讯引脚 ...

  9. stm32正常运行流程图_STM32单片机学习笔记(超详细整理143个问题,学习必看)...

    原标题:STM32单片机学习笔记(超详细整理143个问题,学习必看) 1.AHB系统总线分为APB1(36MHz)和APB2(72MHz),其中2>1,意思是APB2接高速设备 2.Stm32f ...

  10. Deep Learning(深度学习)学习笔记整理系列之(三)

    Deep Learning(深度学习)学习笔记整理系列 zouxy09@qq.com http://blog.csdn.net/zouxy09 作者:Zouxy version 1.0 2013-04 ...

最新文章

  1. 《Adobe AIR权威指南》——《Flex 3权威指南》作者新作
  2. nginx could not build the server_names_hash 解决方法
  3. envi矢量图层外面有蓝色边框_晒晒装完的新房,头次见全屋浅蓝背景墙,加石膏线边框,温馨别致...
  4. C语言——整形数据的存储
  5. Chromium 操作系统即将支持所有 SBC 单板电脑
  6. 跨域解决请求限制(script标签)(热门搜索出现对应的词条)
  7. v-if 与v-show 的区别及使用场景
  8. LeakCanary——直白的展现Android中的内存泄露
  9. c语言中二维数组中产生随机数,C语言中是如何进行随机数生成的[多图]
  10. KlayGE游戏引擎
  11. android程序的建立,创建第一个Android程序 HelloWorld
  12. 全网最详细的Android Studio卸载、安装和启动教程
  13. OpenFaces 3.0 最终版本发布,支持JSF2.0
  14. Qt绘制椭圆曲线的角度问题(离心角和旋转角)
  15. 常见植被指数总结(一)
  16. 光纤收发器和交换机之间有什么区别?
  17. 海信在CES宣布推出75英寸到100英寸的全系全色激光电视产品
  18. 计算机职业素养200字,职业素养个人总结200字
  19. 神经网络中epoch、batch、batchsize
  20. 德鲁伊(Druid)后台监控配置详细操作。生产环境定位问题方法

热门文章

  1. android 学习资料整理
  2. Guitar Pro如何更改五线谱的符杆方向
  3. Python学习笔记(5)practice:shopping_cart
  4. javascript 常用方法 解析URL,补充前导字符, 省市联动, 循环替换模板
  5. 算法笔记_138:稳定婚姻问题(Java)
  6. SpringMVC, Spring和Mybatis整合案例一
  7. TreeMap按照value进行排序
  8. java-线程-使用阻塞队列(BlockingQueue)控制线程通信
  9. 内推 | 高级数据分析师(base:杭州)
  10. 【转载】Redis在windows下安装和配置