1、CRC计算公式' R6 O1 I5 K, f! q% e, D {, Z. Q9 `( Z0 C
所有的STM32芯片都内置了一个硬件的CRC计算模块,可应用到通信程序中,这个CRC计算模块使用常见的、在以太网中使用的计算多项式:
5 U6 l0 { c1 I$ C( h1 C% @7 }7 AX32 + X26 + X23 + X22 + X16 + X12 + X11 + X10 +X8 + X7 + X5 + X4 + X2 + X + 1
# z6 p/ R, o% V9 x0 ? 写成16进制就是:0x04C11DB72 U. e+ y8 n0 U( E: A$ V/ z; @
2、使用这个内置CRC模块操作步骤:
2 W9 \9 d9 N) i3 H4 t0 o5 z# D 复位CRC模块(设置CRC_CR=0x01),这个操作把CRC计算的余数初始化为0xFFFFFFFF7 c) p) k3 u& ?4 a5 }! L
把要计算的数据按每32位分割为一组数据字,并逐个地把这组数据字写入CRC_DR寄存器(既下图中的绿色框); v; L1 I6 h P, l
写完所有的数据字后,就可以从CRC_DR寄存器(既下图中的兰色框)读出计算的结果。& Z8 c) k+ v3 Y, t: `
注意:虽然读写操作都是针对CRC_DR寄存器,但实际上是访问的不同物理寄存器。8 K( H7 J" Y% \6 f; o
3、C语言描述的这个计算模块算法。可放在通信的另一端,对通信的正确性进行验证:2 k! m9 s, D- q0 n7 Z' j; r- `
- <font color="#000"><font face="" "=""> DWORD dwPolynomial = 0x04c11db7;</font></font>
& X/ b+ }. B x( h' t - <font color="#000"><font face="" "=""> DWORD cal_crc(DWORD *ptr, int len)</font></font>
! h+ h. Z: Q- A9 C - <font color="#000"><font face="" "=""> {</font></font>
# \# k6 |/ S1 L6 W# n8 O. Q - <font color="#000"><font face="" "=""> DWORD xbit;</font></font>
2 m# U1 w- V6 T! c# k4 z - <font color="#000"><font face="" "=""> DWORD data;</font></font>
4 P3 t& A3 C5 {# a - <font color="#000"><font face="" "=""> DWORD CRC = 0xFFFFFFFF; // init</font></font>2 D, j& `3 f5 U5 Y
- <font color="#000"><font face="" "=""> while (len--) </font></font>1 h2 {; k$ p+ z7 [9 Z
- <font color="#000"><font face="" "=""> { </font></font>
% ~' i: ?! @4 y6 Y - <font color="#000"><font face="" "=""> xbit = 1 << 31;</font></font>
2 g9 |) R) s: L; N- X+ ~! I$ |2 D' d - <font color="#000"><font face="" "=""> data = *ptr++;</font></font>
8 d0 [ n/ K* B: N - <font color="#000"><font face="" "=""> for (int bits = 0; bits < 32; bits++) </font></font>
, m9 `5 Z; r) q2 f7 V O - <font color="#000"><font face="" "=""> {</font></font>
) T, ~: K {6 X! x% A& n - <font color="#000"><font face="" "=""> if (CRC & 0x80000000) </font></font>
3 {6 Q& F! m% T' o. w - <font color="#000"><font face="" "=""> {</font></font>
3 x5 W: b& O8 m1 e - <font color="#000"><font face="" "=""> CRC <<= 1;</font></font>
- K1 P5 Q) Z O+ S/ X/ `% T - <font color="#000"><font face="" "=""> CRC ^= dwPolynomial;</font></font>" v9 _( d% q% J( z1 }
- <font color="#000"><font face="" "=""> }else</font></font>
1 w3 |4 D7 | `& j - <font color="#000"><font face="" "=""> CRC <<= 1;</font></font>" Q' U& E- c- X, E( d2 V1 w* d
- <font color="#000"><font face="" "=""> if (data & xbit)</font></font>- z, q. J* H/ K) t! W2 c7 W0 x
- <font color="#000"><font face="" "=""> CRC ^= dwPolynomial;</font></font>0 a( p, Z2 H, a; V1 J% p
- <font color="#000"><font face="" "=""> xbit >>= 1;</font></font>. g. R9 r+ N0 h( v N' `
- <font color="#000"><font face="" "=""> }</font></font>- L* L8 o5 N$ ]- d8 D- ]
- <font color="#000"><font face="" "=""> }</font></font>
( G, B) Z& ]3 s - <font color="#000"><font face="" "=""> return CRC;</font></font>
' L; T6 ~ r3 a- I! ^ - <font color="#000"><font face="" "=""> }</font></font>
复制代码 + ~) [' W, s+ q' ~" A
注意:
7 U$ f6 c2 ^4 S' T1)、上述算法中变量CRC,在每次循环结束包含了计算的余数,它始终是向左移位(既从最低位向最高位移动),溢出的数据位被丢弃。
! F# D. a. k: l% Y& z$ ^* H- B) `2)、输入的数据始终是以32位为单位,如果原始数据少于32位,需要在低位补0,当然也可以高位补0。
8 S: M3 X$ M9 d) A- q8 C6 A1 x; ?3)、假定输入的DWORD数组中每个分量是按小端存储。
' q# T; e' v/ N$ C. \0 q F4)、输入数据是按照最高位最先计算,最低位最后计算的顺序进行。
d/ W; N5 J2 ]1 S) B例如:$ o/ r U: @4 m8 Y* R
如果输入0x44434241,内存中按字节存放的顺序是:0x41, 0x42, 0x43, 0x44。计算的结果是:0xCF534AE1
4 J2 I1 S" j! g; Y如果输入0x41424344,内存中按字节存放的顺序是:0x44, 0x43, 0x42, 0x41。计算的结果是:0xABCF9A63
: v# ?% c) r& n; F, ]9 Q4 L! U |