一、stm32的CRC
8 V1 j1 y( n8 ` F- W: F 1.1 CRC的简介及MCU关联说明
5 n3 H# J: Z* s8 I STM32的CRC(Cyclic Redundancy Check,循环冗余校验)计算单元使用一个固定的多项式发生器,从一个32位的数据字产生一个CRC码。在业务开发应用中,会基于CRC的技术用于验证数据传输或存储完整性。在EN/IEC60335-1标准的范围内,它们提供了一种验证闪存(flash)完整性的方法。CRC计算单元帮助计算运行时软件的签名,并与在链接和生成该软件时产生的签名比较验证。, a' @. w0 ~# s3 G, O& |. W
cubeIDE开发, stm32调试信息串口通信输出显示_py_free的博客-CSDN博客_调试信息输出到串口; Q" v' s* t2 v1 H
; v8 x; l5 H! i9 U9 z% D) g4 j0 ] 现双击.ioc文件,打开CubeMX配置界面,开启CRC计算功能,参数保持默认设置。' K5 T$ k& r8 R6 ]7 r# o2 X
/ C8 H1 g$ W! j9 D" M% e, R
5 C/ ^" r, f. G1 {$ v( b8 u) Y% l) F" Z" v
) a! r9 e: b5 d7 `
保存及生成输出代码$ P9 S8 e/ b! _0 J9 s6 O R
( f6 v8 q0 n6 k; k; g0 d/ A
2.2 CRC的HLA库分析; y g* p/ y, {* Z4 y9 l9 y
cubeMX生成代码时,会在Core源码目录下的Inc及Src目录,分别生成crc.h和crc.c驱动文件。
3 l! x/ z1 ?6 p9 U: b/ O) K" z( b& R; G: m% F1 G
在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函数。: B2 l/ m9 z6 B0 x' ?
3 u3 H9 L2 l6 w# r" `4 r
3 i9 K7 L7 T+ V2 g4 O$ ~5 P
8 ~; w1 b" o' w( b" |* k+ R- i0 [& ? 在stm32l4xx_hal_crc.c源文件中定义了HAL_CRC_Init函数,它做以下事情:诊断配置参数是否合规;调用HAL_CRC_MspInit函数完成CRC时钟开启;最后将依据参数写入CRC寄存器,如果采用默认多项式参数,写入默认多项式数值,否则调用多项式配置函数,写入用户定义数值。
: O% r- j7 A- {' \) \ B. B5 {7 h+ S6 \9 ?7 J
/ g! g9 B) S- S
- d% y$ b( s) A- o
再回到crc.c内,HAL_CRC_MspInit函数实现了CRC时钟启动设置。) {, R+ i2 F+ q- k, B
( z0 c1 M7 {; j+ Q" v+ U+ Z, V1 Q
' s# D: ]. N* n/ ?, W3 Z
3 y4 _2 \2 w/ s% B X. h$ w9 q
另外HLA库提供了用户自定义设置多项式参数、输入数据反转及输入数据反转的函数,方便开发这在程序代码中按需变更CRC计算方式,这些函数作为扩展功能放置在stm32l4xx_hal_crc_ex.h/c内。2 k9 \9 z; a/ p- M7 W/ @5 a1 C/ C
/ [! q4 X7 w$ b8 K
5 ?1 ~0 L: H7 u" q2 K% s( x' M8 n
2.3 CRC计算功能及调用设计
, \7 n: I |) c- O8 u 在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的部分是每次计算一组数据前,都会进行数据寄存器重置5 A1 k, p& O: \0 x
J8 [ p& \( s' G# b9 L
( i9 G( \$ N6 O( R7 _
/ K* G& @# K2 n; \
; M& g6 t" |- T" u2 Y
$ _2 f; Q) R6 Z3 Q9 `
在main.c文件中,加入驱动文件支持0 z/ F5 l; L, J9 K5 `
- /* Private includes ----------------------------------------------------------*/* V B' R6 x2 k; e
- /* USER CODE BEGIN Includes */
5 Y+ p3 v6 N- j5 k" T$ i2 @ - #include "../../ICore/key/key.h"
& ^) r% Y" g0 A( x7 s - #include "../../ICore/led/led.h"9 o, S, l( e1 l" E
- #include "../../ICore/print/print.h"$ O/ O+ E* [4 b, |4 U8 O- C
- #include "../../ICore/usart/usart.h"4 n m4 v% A* ~: |& U( ?& {) P
- #include "../../ICore/delay/delay.h"4 B {; X" L' p$ Y# ]- y7 w
- /* USER CODE END Includes */
复制代码
( Q+ t; P7 ^8 ^9 n& W3 l- p; J- `) k/ q) q' w) j5 d3 B
在main.c文件中,加入CRC句柄(寄存器)声明
% B3 d+ @" a: H- s' C$ K. b; L v- /* Private user code ---------------------------------------------------------*/' B6 c9 P, n- z8 y9 n1 z; a
- /* USER CODE BEGIN 0 */
' i" K; t: c9 |& S @) F0 C - extern CRC_HandleTypeDef hcrc;4 r/ P1 p8 ]! l# h$ I& Q% W; J/ P: I
- /* USER CODE END 0 */
复制代码
1 s$ K" Z7 n) M8 L 在main函数中,加入外设驱动启用(主要是串口调试中断开启)及相关初始设置,添加了一组3个长度32bit宽的数据数组用于测试。 v' {6 \4 L6 X0 e n% Z X
- /* Initialize all configured peripherals */' B2 v5 X. P, ]3 y# P/ { P: C. ]
- MX_GPIO_Init();
* L1 o8 O$ c9 { _ @1 |/ p# n! Q - MX_LPUART1_UART_Init();
8 F; I# W7 o+ K9 l' e - MX_CRC_Init();
- {. [5 A! D5 D6 w2 | - /* USER CODE BEGIN 2 */% W9 i* b! K0 m* f
- ResetPrintInit(&hlpuart1);& v3 E9 t# _+ o2 z' Q
- HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再开启接收中断; v% T: I: x X9 P8 K$ E, L- a
- HLPUSART_RX_STA = 0;+ Q# T3 b) k' s8 @
- //
. W" }, W+ |) I2 Y$ h - printf("app restart now!\r\n");$ Y7 I* c. S" L3 E* _/ s h
- uint32_t crc_input[3] = {0X12345678,0X23456789,0X34567890};
; E6 i, j5 W* B4 p1 }, \, ` - uint32_t crc_output = 0x00;5 A5 o7 X, M2 x0 K0 p# X
- uint32_t crc_index = 0;
7 v$ X( E' T( ?: ~( q! J4 d( l, m4 } - uint8_t crc_mode = 0;
* P4 o! \ h: x# V& K- K& P - /* USER CODE END 2 */
复制代码 在main函数循环体中,通过按钮调用CRC计算功能,并通过lpuar1串口输出显示计算结果。
% x8 ?. r& }* S. ^7 ^& ~- /* Infinite loop *// y/ f7 ?% C6 |0 A
- /* USER CODE BEGIN WHILE */
& s1 V/ r2 E1 P, c) F - while (1)
1 G5 [0 ^: G# ]2 ? - {
0 l) ~' B0 z- Z$ ]! ^! v" @* Q- E# Q# i - if(HLPUSART_RX_STA&0xC000){//溢出或换行,重新开始5 D% b G% ?, W; E9 e# P
- //printf("%.*s\r\n",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);
' W' q! J l0 J. g; G& c# P - HLPUSART_RX_STA=0;//接收错误,重新开始2 ?8 P- u7 \ ]9 q$ |& }
- HAL_Delay(100);//等待
2 F1 v5 L2 |- x; n - }
v1 y/ H) n& t# `* @7 Q - if(KEY_0())
; d! B ?, [& F/ I$ J6 H- U - {
& i( y7 L$ z: u# b5 Z. P - crc_output = HAL_CRC_Accumulate(&hcrc,crc_input,3);
' s3 G* j2 o6 V) f/ r( y" z - printf("crc_Accumulate_output:0X%08lX\r\n",crc_output);) ^0 l) [ f; f$ I( j$ _7 W
- }
) C. R" R9 ~, v6 X - if(KEY_1())
) }/ p U1 J a - {2 G* ~3 o9 a& \/ B
- crc_output = HAL_CRC_Calculate(&hcrc,crc_input,3);, U1 o+ J# r) T. I% M; @6 r
- printf("crc_Calculate_output:0X%08lX\r\n",crc_output);6 E% \* B! l, } f$ O7 {8 E
- }
% V [: {* l+ x8 Q! m; O - if(KEY_2())
2 z3 h& I$ M1 j! p, B - {( y! o+ Z- a5 a8 F% U4 o
- crc_mode = (crc_index)%6;) u t: E" e7 d. U0 o
- switch(crc_mode){
* j4 n7 E4 k% W2 a! M - case 0:
+ o+ T. ~' ]7 H7 a1 Z8 [ - HAL_CRCEx_Output_Data_Reverse(&hcrc,CRC_OUTPUTDATA_INVERSION_ENABLE);
3 l3 I# g+ o9 c( A - printf("Output_Data_Reverse:0X%08lXU\r\n",CRC_OUTPUTDATA_INVERSION_ENABLE);
: n% b2 b1 c: G p: @ - break;
- j& }# y, X. _" u" I3 l) W' e - case 1: P8 l6 {4 {' f
- HAL_CRCEx_Output_Data_Reverse(&hcrc,CRC_OUTPUTDATA_INVERSION_DISABLE);1 H0 E" _% x/ Y# q
- printf("Output_Data_Reverse:0X%08XU\r\n",CRC_OUTPUTDATA_INVERSION_DISABLE);
/ z. {0 n) N8 R% f8 b2 E - break;7 Z0 u1 {, Q$ @
- case 2:5 x( z* X; S$ k6 J& q# C7 n# i( _9 S: ^
- HAL_CRCEx_Input_Data_Reverse(&hcrc,CRC_INPUTDATA_INVERSION_BYTE);
$ i3 h0 Q# [0 ]7 ?1 r - printf("Input_Data_Reverse:0X%08lXU\r\n",CRC_INPUTDATA_INVERSION_BYTE);
+ B5 e9 |; f4 U, H: G8 \" m: I - break;
# O# x \" H# H7 Y% n8 j: ]. N/ s- Y - case 3:6 j5 T/ y( X$ s! W- I; Z! n
- HAL_CRCEx_Input_Data_Reverse(&hcrc,CRC_INPUTDATA_INVERSION_HALFWORD);
& H+ v# y' Y) P2 z7 G6 U - printf("Input_Data_Reverse:0X%08lXU\r\n",CRC_INPUTDATA_INVERSION_HALFWORD);( e, w; O6 ]* w6 \5 I. j8 o
- break;
0 a' s" `' V6 i, v$ r6 I- A - case 4:% a# P$ M; _( }3 h- M
- HAL_CRCEx_Input_Data_Reverse(&hcrc,CRC_INPUTDATA_INVERSION_WORD);' ^2 `& I+ l; u; x4 Y
- printf("Input_Data_Reverse:0X%08lXU\r\n",CRC_INPUTDATA_INVERSION_WORD);
! w! d. S# Y, E$ ` - break;+ @3 V j" l; z6 P4 b
- case 5:0 a3 s8 z3 S* o9 P1 J# T
- HAL_CRCEx_Polynomial_Set(&hcrc,DEFAULT_CRC32_POLY,CRC_POLYLENGTH_16B);1 z( L4 Y) h* v5 E1 B
- printf("Polynomial_Set:0X%04XU\r\n",DEFAULT_CRC32_POLY);
9 ~- u3 B5 O* z" W4 X+ X+ A& d - break;+ e; @( P' j' ~( m4 m- t
- default:" e( T; ?0 ^. X4 A4 y
- break;. G9 T5 T3 n/ V+ L% K
- }
/ h1 j# ~# R- D6 R0 w% ~ - crc_index++;# u6 X! \3 q* L% g
- }
$ y3 ^; b( O% P* B4 k - /* USER CODE END WHILE */
复制代码
2 E7 M+ P' R# }4 x U [, p三、编译及测试
. R+ P3 `) _. t8 M1 k5 `: @ 3.1 编译下载6 L: F0 ~2 w4 I: q4 t+ |& T
; K/ M ]# C* |3 c6 q6 {
8 @8 r9 r6 i% I# z6 `3 s7 \) k
3.2 测试
. M$ L: u2 n1 y( n6 q+ F: u 程序开启时,默认多项式参数是0x04C11DB7U,无输入、输出反转。每按键一次KEY2改变输入反转模式或输出反转模式或多项式参数 ,然后各按键一次KEY0和KEY1, log输出如下:! ^" h- \# p5 x4 y& }0 T
1 |! k3 o' C2 q- d1 }
/ U( J) [3 ?# K1 l
3 [: L4 b9 T/ x9 y! [( j) \ 案例只是抛砖引玉,更多CRC功能及应用拓展请自行上手代码实践。: Q+ d3 K" b9 o- U
————————————————
2 w* c. X! B2 z4 U版权声明:py_free-物联智能
) y7 l2 J* h% q$ I8 }如有侵权请联系删除
+ H, `% T. u* @% V6 g7 |) a4 i$ }0 z, J( r
7 G% @$ G' c$ D5 x0 c/ ^ W; t! X/ l |
感谢分享 我想请问一下怎么用自带的CRC计算CRC16 数组类型是uint8的