一、stm32的CRC0 [0 o! v3 s/ Q) }. M& e
1.1 CRC的简介及MCU关联说明
$ I( x" s2 e5 W# Z4 P STM32的CRC(Cyclic Redundancy Check,循环冗余校验)计算单元使用一个固定的多项式发生器,从一个32位的数据字产生一个CRC码。在业务开发应用中,会基于CRC的技术用于验证数据传输或存储完整性。在EN/IEC60335-1标准的范围内,它们提供了一种验证闪存(flash)完整性的方法。CRC计算单元帮助计算运行时软件的签名,并与在链接和生成该软件时产生的签名比较验证。
6 D; B6 q" |0 _7 ~cubeIDE开发, stm32调试信息串口通信输出显示_py_free的博客-CSDN博客_调试信息输出到串口
8 E. g+ f( @1 i3 X
; Q1 A' t+ l1 b- j0 ^( ] 现双击.ioc文件,打开CubeMX配置界面,开启CRC计算功能,参数保持默认设置。
" T. }( v( M* E1 ^+ k4 b0 [1 l( n3 M0 m4 `4 p0 K. B
7 h8 `$ b9 G' B. |' i9 b
4 b9 b# y( h9 ]- U+ I6 M 保存及生成输出代码
3 y- B& Q% Q; m% R7 L" G; @' p6 {
5 b4 n" H/ G a; I6 q 2.2 CRC的HLA库分析- Q: _) y9 J4 i7 B. o/ @
cubeMX生成代码时,会在Core源码目录下的Inc及Src目录,分别生成crc.h和crc.c驱动文件。
3 ]1 _3 k( e, p+ M2 g& b% w/ y% |! E/ q
在crc.c文件中,主要定义了MX_CRC_Init函数和HAL_CRC_MspInit函数。MX_CRC_Init主要做两件事情,一是将CubeMX上配置的参数传递给CRC缓存Init和生成CRC句柄Instance(寄存器),二是调用HLA库的HAL_CRC_Init来实现真正的初始化设定。HAL_CRC_MspInit是HLA内的弱函数,根据实际配置CubeMX会生成新的函数,完成真正的MCU底层设置任务(MspInit,MCU Specific Package init,即指和MCU相关的初始化),覆盖原来的弱函数,而在HAL_CRC_Init函数中会调用到HAL_CRC_MspInit函数。; f: ]4 g% D! T
* u9 a6 H9 K# O2 H& v
# R' i1 W' W) m9 n" R! p# l% O6 d/ G1 q4 X; S- e. I3 K
在stm32l4xx_hal_crc.c源文件中定义了HAL_CRC_Init函数,它做以下事情:诊断配置参数是否合规;调用HAL_CRC_MspInit函数完成CRC时钟开启;最后将依据参数写入CRC寄存器,如果采用默认多项式参数,写入默认多项式数值,否则调用多项式配置函数,写入用户定义数值。; U4 o9 [1 H. a* i- M2 ?; k9 v1 v
& E: D6 q+ G# f" o4 m/ p: \
+ q; o: ^) T! f# h* Y6 z# o
+ I6 t9 }7 r3 e! ]- z. X 再回到crc.c内,HAL_CRC_MspInit函数实现了CRC时钟启动设置。4 T) }' s( ]& g7 M* c
3 p( q+ L' q) V0 o
) p$ W4 } Y3 B O) t& D# \
5 ~% n& A, v: q3 D2 E
另外HLA库提供了用户自定义设置多项式参数、输入数据反转及输入数据反转的函数,方便开发这在程序代码中按需变更CRC计算方式,这些函数作为扩展功能放置在stm32l4xx_hal_crc_ex.h/c内。4 z. ^' K8 o& v/ ]
/ ~. D- S' w* j$ p% f0 F: S5 V
$ o* S! @! G% D# W( X6 b \
$ h1 G/ M! d, G4 d* A# u( C6 C3 H& N
2.3 CRC计算功能及调用设计) E+ K' H9 E' V0 H$ @) |+ X
在stm32l4xx_hal_crc.c源文件除了定义初始化功外,还定义了CRC计算功能函数HAL_CRC_Accumulate和HAL_CRC_Calculate,HAL_CRC_Accumulate函数使用先前的CRC值和新的CRC值的组合来计算8、16或32位数据缓冲器的7、8、16和32位CRC值;HAL_CRC_Calculate独立于先前的CRC值,计算8、16或32位数据缓冲器的7、8、16和32位CRC值,因此它不同于HAL_CRC_Accumulate的部分是每次计算一组数据前,都会进行数据寄存器重置7 | b# J& k [7 M& `
) j+ K! @$ j+ V0 {) l5 F& a3 `/ f
+ w* k8 b# j- k1 r7 K' q
' a# L( y" u4 Q i; L3 T2 K) g
: Z4 ?6 ]& Z( i/ x- ^" ]3 x
x# V9 H; L ^" Y+ O6 D1 I 在main.c文件中,加入驱动文件支持
# y1 o0 w4 @9 _' w$ X7 p- /* Private includes ----------------------------------------------------------*/
; T( T2 T, F& d( v# q N) i3 c+ E - /* USER CODE BEGIN Includes */
8 V# Z" L, @9 {+ ^/ g1 |% I - #include "../../ICore/key/key.h"/ m0 e2 j+ f# n* O4 h& {
- #include "../../ICore/led/led.h"5 `% f0 n. u1 J5 ?9 c
- #include "../../ICore/print/print.h"! x2 d5 T# T$ O1 A( A* q
- #include "../../ICore/usart/usart.h"
$ B2 e s; [5 r& @$ Q# o+ g0 I! \ - #include "../../ICore/delay/delay.h"
$ a# E7 \" _# S6 V5 ^. x6 A+ Q - /* USER CODE END Includes */
复制代码 3 U8 O: u- V* v1 o+ K: A' y
" K4 T8 I. S2 V1 U3 x/ ] 在main.c文件中,加入CRC句柄(寄存器)声明# u5 c6 b* C* H( c( }$ l5 `
- /* Private user code ---------------------------------------------------------*/5 y- s4 @6 e8 h6 p
- /* USER CODE BEGIN 0 */8 O8 ~& [' a5 Y. b7 }6 x4 H6 k
- extern CRC_HandleTypeDef hcrc;
& f5 z% d0 w. k+ O. T' y5 _- n - /* USER CODE END 0 */
复制代码 ( R4 S/ ?6 ~$ x5 P! v) M* q ?2 E6 G. u
在main函数中,加入外设驱动启用(主要是串口调试中断开启)及相关初始设置,添加了一组3个长度32bit宽的数据数组用于测试。3 ?7 e* S; `3 a
- /* Initialize all configured peripherals */# F2 O! s1 s7 q" w- H- o
- MX_GPIO_Init();
% c; O* F: h) q" n - MX_LPUART1_UART_Init();
$ C' J" V. R Q% M - MX_CRC_Init();
. p; t) _* V! {- n8 e9 R - /* USER CODE BEGIN 2 */
7 W& b$ p' t2 k3 j: ? - ResetPrintInit(&hlpuart1);
M7 \0 j' x1 b1 V! Q, X, Y2 K% y - HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再开启接收中断
& c4 j9 `+ W# S4 m5 V - HLPUSART_RX_STA = 0;, s- H* y/ P) z9 _: o1 W
- //
/ M: n0 N3 }" x9 v1 y: D. z- D - printf("app restart now!\r\n");+ y2 t0 r$ V! N5 A/ v) g
- uint32_t crc_input[3] = {0X12345678,0X23456789,0X34567890};
. s3 N4 l r; q6 Q2 C# o M+ N% |8 a - uint32_t crc_output = 0x00;. h* n+ E0 W( s- n. @8 |) i
- uint32_t crc_index = 0;
6 d( J, Z. c* t# n% W9 | - uint8_t crc_mode = 0;
8 d4 o w3 q- N: y n: n - /* USER CODE END 2 */
复制代码 在main函数循环体中,通过按钮调用CRC计算功能,并通过lpuar1串口输出显示计算结果。" u# _: e/ v$ K
- /* Infinite loop */
; ~" [3 {' h) K3 H - /* USER CODE BEGIN WHILE */3 ]7 z5 B7 Y4 p* y; d$ k
- while (1)
' i' A8 l7 R- Y& k6 N5 j - {
9 N8 z2 J ^ G/ P! a7 e - if(HLPUSART_RX_STA&0xC000){//溢出或换行,重新开始7 K% Y3 ]3 R8 I1 r4 c
- //printf("%.*s\r\n",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);" S3 N3 ]" n) c
- HLPUSART_RX_STA=0;//接收错误,重新开始
& r* [! h; c; z - HAL_Delay(100);//等待
5 a% Z+ a6 c; d- ?" K - }
3 l. c5 b; J' j' u K - if(KEY_0())
1 N" {" o: ]) Z5 h/ \& t, r - {9 }) V/ f8 k" i! ~" p4 e$ ~
- crc_output = HAL_CRC_Accumulate(&hcrc,crc_input,3);; `: o# |$ o& Q& F# z2 A( ~
- printf("crc_Accumulate_output:0X%08lX\r\n",crc_output);/ O6 i/ q, G @; J1 V( E
- }: M& s0 P& N+ M+ k. ~0 I1 ^
- if(KEY_1())
& e( H$ f( @% i, P - {/ c* r! z% s. W: T+ x5 @7 U9 z
- crc_output = HAL_CRC_Calculate(&hcrc,crc_input,3);- i7 I; [1 L/ V+ _3 Z) r
- printf("crc_Calculate_output:0X%08lX\r\n",crc_output);
. |8 w$ W2 `) v' t( T. Q$ @6 L - }
; G- V7 ~9 H% ?( X - if(KEY_2())
4 F( K, I' ?. U1 J - {
2 w5 _4 p w0 l9 l3 d6 y/ x - crc_mode = (crc_index)%6;
- G. {" y, b& ~. ]% b* h0 m2 p - switch(crc_mode){
1 u/ |; Z* e; V2 N7 p) Z& J - case 0:
4 z5 `" t- F8 ` - HAL_CRCEx_Output_Data_Reverse(&hcrc,CRC_OUTPUTDATA_INVERSION_ENABLE);4 Q' n2 N8 {3 v) U' p- g1 v
- printf("Output_Data_Reverse:0X%08lXU\r\n",CRC_OUTPUTDATA_INVERSION_ENABLE);3 a, u! E4 e6 W7 h, x6 p* N
- break;9 x: B$ W" v. X1 o ^, ^
- case 1:& S( r H2 x6 ^. s
- HAL_CRCEx_Output_Data_Reverse(&hcrc,CRC_OUTPUTDATA_INVERSION_DISABLE);) F9 _* M4 L4 b6 [7 g. z8 a
- printf("Output_Data_Reverse:0X%08XU\r\n",CRC_OUTPUTDATA_INVERSION_DISABLE);
" }' K& z3 s: ?: M% K+ } - break;6 `. \* W. J3 H' q
- case 2:
& v0 o/ p& i, L5 k - HAL_CRCEx_Input_Data_Reverse(&hcrc,CRC_INPUTDATA_INVERSION_BYTE);4 g+ M# ^7 v! T0 s3 ?8 S1 U1 b
- printf("Input_Data_Reverse:0X%08lXU\r\n",CRC_INPUTDATA_INVERSION_BYTE);4 r3 n5 i3 k! F, b
- break;4 B0 H$ A$ d: m3 s3 i7 p" ~
- case 3:. r: D/ d' y" _6 d/ f) @
- HAL_CRCEx_Input_Data_Reverse(&hcrc,CRC_INPUTDATA_INVERSION_HALFWORD);3 F5 j0 x# B& R: }7 W0 \
- printf("Input_Data_Reverse:0X%08lXU\r\n",CRC_INPUTDATA_INVERSION_HALFWORD);
" w) d- q* H) A ~# b( B2 U0 S1 l - break;
- A2 [6 d1 S! l2 n; \' N - case 4:
( E' f. u: {( x" V3 c - HAL_CRCEx_Input_Data_Reverse(&hcrc,CRC_INPUTDATA_INVERSION_WORD);
5 C3 I, D, V5 i" h6 E1 N - printf("Input_Data_Reverse:0X%08lXU\r\n",CRC_INPUTDATA_INVERSION_WORD);% T+ M# b0 F- R0 C# k$ }! b
- break;- K0 _! o# p5 v) L- T, l' n
- case 5:# n d: r' `) \& N O
- HAL_CRCEx_Polynomial_Set(&hcrc,DEFAULT_CRC32_POLY,CRC_POLYLENGTH_16B);
B I/ f7 i6 O# x- t# U - printf("Polynomial_Set:0X%04XU\r\n",DEFAULT_CRC32_POLY);
5 G V9 u1 O9 v# ~) r - break;' B2 n2 g% i- Q. [8 p3 D S
- default:
8 M* `1 }4 H- X, @; ]3 J - break;
$ G( h! l) N, l - }" q+ M5 m/ I' Q2 K$ h
- crc_index++;* R7 p/ ?$ u8 n1 _
- }
# L- ?( J- _/ }# u4 e: z' B - /* USER CODE END WHILE */
复制代码 / P+ g4 m% W9 m& n# u1 _: @$ c9 S
三、编译及测试
) J3 a2 ?0 Q! o, g2 z6 t- p5 \; x 3.1 编译下载5 v/ @. \6 }! i3 R' n- G
9 M' o6 ~- d! X4 y
. m5 P/ F/ I" i% P% v8 p, H6 @7 v0 r
3.2 测试
$ S& q1 D; e# v9 r/ i 程序开启时,默认多项式参数是0x04C11DB7U,无输入、输出反转。每按键一次KEY2改变输入反转模式或输出反转模式或多项式参数 ,然后各按键一次KEY0和KEY1, log输出如下:: A, S p. H! @2 l3 L! v* o7 J6 @+ h) U
6 {. ^( w% r2 {2 F
0 J( x) `/ R8 F7 _7 Z. r
$ v2 K3 {. N2 Z- G/ i6 |% w 案例只是抛砖引玉,更多CRC功能及应用拓展请自行上手代码实践。
! |' P" |+ n, C1 ^9 O& X) a R$ _————————————————' h! d& J/ @$ H( a- ?
版权声明:py_free-物联智能
* F: `9 m# g% c6 i1 F4 f如有侵权请联系删除
) J0 T" B- K9 m, r9 n; F
! h. `4 k! o+ r6 Z1 y* a$ `+ _5 ]% @/ t3 l2 `
|
感谢分享 我想请问一下怎么用自带的CRC计算CRC16 数组类型是uint8的