一、stm32的CRC
3 b6 A# u; p, G 1.1 CRC的简介及MCU关联说明
6 @6 I1 _: y8 z. W0 C STM32的CRC(Cyclic Redundancy Check,循环冗余校验)计算单元使用一个固定的多项式发生器,从一个32位的数据字产生一个CRC码。在业务开发应用中,会基于CRC的技术用于验证数据传输或存储完整性。在EN/IEC60335-1标准的范围内,它们提供了一种验证闪存(flash)完整性的方法。CRC计算单元帮助计算运行时软件的签名,并与在链接和生成该软件时产生的签名比较验证。
# C D" N& s; ccubeIDE开发, stm32调试信息串口通信输出显示_py_free的博客-CSDN博客_调试信息输出到串口
& Y9 ]+ E/ P; P( \8 H& Q6 `& W0 X# K0 j
现双击.ioc文件,打开CubeMX配置界面,开启CRC计算功能,参数保持默认设置。
( t1 l+ x. ]7 T; w* a$ {- @. ~8 K9 z9 m: J0 B) a1 z
9 X: S' j$ K6 B& C! v0 w' g' A* Y& t9 C6 U; t5 W+ B. C8 C
保存及生成输出代码
4 o$ `9 u1 h% k% `' D Z+ F+ r% F9 B6 ~' v- C
2.2 CRC的HLA库分析; D, h' _+ U/ B+ ~) |
cubeMX生成代码时,会在Core源码目录下的Inc及Src目录,分别生成crc.h和crc.c驱动文件。
* z: W. S/ j6 E3 f- N6 I# X- [) E
' y$ h' d3 u+ |5 y d8 r* R 在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函数。2 n* @/ X! I; d+ y( M
) L9 T9 P- `& O( V& i8 G
1 v1 t# G) {/ L* v0 [; K+ F) ~9 u
在stm32l4xx_hal_crc.c源文件中定义了HAL_CRC_Init函数,它做以下事情:诊断配置参数是否合规;调用HAL_CRC_MspInit函数完成CRC时钟开启;最后将依据参数写入CRC寄存器,如果采用默认多项式参数,写入默认多项式数值,否则调用多项式配置函数,写入用户定义数值。* F8 G& p5 |$ S' p1 n- d
0 Z* O/ s# M9 k
$ r7 P0 T5 G, U% X. j6 u% S! F: E5 }: ^; X$ f: u7 j
再回到crc.c内,HAL_CRC_MspInit函数实现了CRC时钟启动设置。" e$ t% m4 G& N% ?, v( t' }4 I
( Y( }3 B. q9 g5 w$ C% j
. c1 c1 B( J/ X% U* G" |5 b
3 W- F' d6 s0 B 另外HLA库提供了用户自定义设置多项式参数、输入数据反转及输入数据反转的函数,方便开发这在程序代码中按需变更CRC计算方式,这些函数作为扩展功能放置在stm32l4xx_hal_crc_ex.h/c内。
B, B3 q4 @. ^1 O4 D' Q6 w6 ^! ~* a
! E5 c7 H Z# q9 O( v6 p
" [1 V( N3 Z* k2 [( m5 n- i: P
2.3 CRC计算功能及调用设计
/ M1 _) c1 k7 i 在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的部分是每次计算一组数据前,都会进行数据寄存器重置: ^1 }# u) z8 V; R, O Q
% i! q1 X9 b4 x
1 G: i% }( n" m0 l3 F8 }
$ I0 C& b: L7 K) ]( A; y
I( M1 I. m$ E2 n, b1 Q2 W0 }- [
( b6 r9 x% M. c* Y* q 在main.c文件中,加入驱动文件支持 x7 d' g7 b b1 S
- /* Private includes ----------------------------------------------------------*/
0 x+ F2 C& y- T) N4 @! E - /* USER CODE BEGIN Includes */
' {8 K5 R' ]% ^7 N$ j# |! V) F: l - #include "../../ICore/key/key.h"
$ U! s2 I- c) y+ j) f, F' N* b& m - #include "../../ICore/led/led.h"
3 a" c9 G) X$ k# q - #include "../../ICore/print/print.h"
?. r/ u/ P0 M+ }4 d3 U# z* @+ J+ g+ s - #include "../../ICore/usart/usart.h"
3 O* u/ }+ D' V+ _+ |; a0 p1 \ - #include "../../ICore/delay/delay.h"
& B, {' [* c5 U7 L8 L - /* USER CODE END Includes */
复制代码
% y( F0 z7 V5 u( f( g7 ]: ]( R8 Q1 o+ [9 u) Q
在main.c文件中,加入CRC句柄(寄存器)声明; K' G& P. N; }4 i- w
- /* Private user code ---------------------------------------------------------*/* i, ~, l7 ?9 X! h0 N
- /* USER CODE BEGIN 0 */
+ H" B, s$ r! T9 r* A+ b/ M - extern CRC_HandleTypeDef hcrc;0 C/ z: A& Z( B& Q$ p, w
- /* USER CODE END 0 */
复制代码
) x1 Q6 Q6 R5 W5 P6 A 在main函数中,加入外设驱动启用(主要是串口调试中断开启)及相关初始设置,添加了一组3个长度32bit宽的数据数组用于测试。
5 F n9 v7 X3 q9 _- /* Initialize all configured peripherals */4 j# a: l8 c7 S& p: _: u9 ]
- MX_GPIO_Init();' i! s! `; t) z$ o1 r$ g) }
- MX_LPUART1_UART_Init();/ F8 u4 }$ X) @
- MX_CRC_Init();! Z/ B C P1 k. P( G) L
- /* USER CODE BEGIN 2 */
! D) h' O3 c4 S7 Z8 ?/ d( Q- ^ - ResetPrintInit(&hlpuart1);) c r0 O! Q S: X
- HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再开启接收中断8 e5 n* _8 E" C5 T2 c" j
- HLPUSART_RX_STA = 0;; l* b1 e5 {" b" H% u" y9 t4 e, b
- //: ?+ a& h, N% f @) a
- printf("app restart now!\r\n");6 X* p: w/ n, `
- uint32_t crc_input[3] = {0X12345678,0X23456789,0X34567890};9 ^0 d9 t V2 u
- uint32_t crc_output = 0x00;
. J& G) }% h, i, R6 b& ? - uint32_t crc_index = 0;
. K# ~( B5 r/ s$ t; N - uint8_t crc_mode = 0;0 F( {5 K2 G. s7 L3 w7 x9 _
- /* USER CODE END 2 */
复制代码 在main函数循环体中,通过按钮调用CRC计算功能,并通过lpuar1串口输出显示计算结果。; n$ {* c% |* z, S! o5 X
- /* Infinite loop */( a4 L0 T8 Q/ w% [1 d; \2 T" o" l
- /* USER CODE BEGIN WHILE */" F6 s3 _' ~ t+ u' e; V* V% |
- while (1)
3 V: K) a6 e! W3 p% d4 T- z - {/ z+ k5 g: K6 k+ B- Y
- if(HLPUSART_RX_STA&0xC000){//溢出或换行,重新开始: T! e, h. ^- m7 L
- //printf("%.*s\r\n",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);4 @# ~% {# E. Q: z
- HLPUSART_RX_STA=0;//接收错误,重新开始6 N+ \1 M. U7 T2 e6 i
- HAL_Delay(100);//等待1 d: w- i( ^0 T
- }# I+ N# d( f& k
- if(KEY_0())$ g3 z) R: f( H6 A9 X# q& Q
- {; G% i8 J" o/ s' k2 y, E! W
- crc_output = HAL_CRC_Accumulate(&hcrc,crc_input,3);
0 E1 s( }' V; _6 W/ ~* v% S - printf("crc_Accumulate_output:0X%08lX\r\n",crc_output);
# n2 m6 W" s4 u# m- i - }
( p5 f( ^) |+ ?3 L5 a - if(KEY_1())
+ a+ L8 ~1 ?- V- O - {
* i; X$ q- p+ G - crc_output = HAL_CRC_Calculate(&hcrc,crc_input,3);9 s3 F4 _ Z: n* s2 x4 M G
- printf("crc_Calculate_output:0X%08lX\r\n",crc_output);
0 z5 L! v4 ~/ }+ T" o1 X: o - }' k9 Y3 }9 d' A+ q4 \) _: V/ @
- if(KEY_2())
8 T( g) z! P+ E _4 k# J - {
6 J8 N/ ?9 q! N1 Y" T m - crc_mode = (crc_index)%6;
4 l, N* b& B1 X% E/ V6 J - switch(crc_mode){
& F4 k* B* W: g/ D8 M* i - case 0:* w4 ]$ p" I2 z4 ], |
- HAL_CRCEx_Output_Data_Reverse(&hcrc,CRC_OUTPUTDATA_INVERSION_ENABLE);
9 U, \& s* F. \7 N7 a - printf("Output_Data_Reverse:0X%08lXU\r\n",CRC_OUTPUTDATA_INVERSION_ENABLE);
8 Q5 w: p6 L" y6 N" F - break;; ~. z: `$ ?' |# a
- case 1:* [$ E" I# W/ M6 t
- HAL_CRCEx_Output_Data_Reverse(&hcrc,CRC_OUTPUTDATA_INVERSION_DISABLE);
$ x* f' f$ k$ f. Y2 P6 X - printf("Output_Data_Reverse:0X%08XU\r\n",CRC_OUTPUTDATA_INVERSION_DISABLE);
' \4 }! {, p9 }) i' I& r- y2 s - break;% k2 ^: e m; J8 `* P, r% `
- case 2:
, e% w& C- N) Y S1 _2 P" ^ - HAL_CRCEx_Input_Data_Reverse(&hcrc,CRC_INPUTDATA_INVERSION_BYTE);; m- A ^/ u! [4 I6 E+ a
- printf("Input_Data_Reverse:0X%08lXU\r\n",CRC_INPUTDATA_INVERSION_BYTE);/ f4 K4 b6 X g
- break;% B! o& u/ i9 B
- case 3:
1 p- U7 S3 Z4 A) Y5 m. h& r2 D - HAL_CRCEx_Input_Data_Reverse(&hcrc,CRC_INPUTDATA_INVERSION_HALFWORD);
* ?% w7 c2 Y4 o$ q( V6 f - printf("Input_Data_Reverse:0X%08lXU\r\n",CRC_INPUTDATA_INVERSION_HALFWORD);4 g9 N" |- U8 {2 u0 @1 U% G: b" B, P
- break;! |/ u/ `) ?" o( M u) ]
- case 4:
% G1 |+ L5 t% F+ r1 }, b; { - HAL_CRCEx_Input_Data_Reverse(&hcrc,CRC_INPUTDATA_INVERSION_WORD);
7 V6 n" o" k! p9 {& E - printf("Input_Data_Reverse:0X%08lXU\r\n",CRC_INPUTDATA_INVERSION_WORD);1 ^1 D/ {+ \* Y
- break; m3 w5 V* Q1 }7 a6 F
- case 5:
) l5 U `/ G% W - HAL_CRCEx_Polynomial_Set(&hcrc,DEFAULT_CRC32_POLY,CRC_POLYLENGTH_16B);, y" l4 P7 n0 [7 p6 f$ o5 r1 t
- printf("Polynomial_Set:0X%04XU\r\n",DEFAULT_CRC32_POLY);
3 H9 V9 F9 T, J, \' `0 m - break;; h+ i1 U, \) U$ V, Q; s1 |( `7 g! X
- default:
2 n% B. }4 H6 n4 S" O$ U - break;
9 M$ s k* D; ]. E2 E- a5 I3 N; W - }
. a9 }: p. I! K) s8 @$ u - crc_index++;% A* N" L# z/ H! J. o
- }* K! o1 K3 Y9 ~6 _; y" W
- /* USER CODE END WHILE */
复制代码
" z6 v! g t- Q8 c! v三、编译及测试2 E% }& [7 @9 s$ U7 t" f3 f
3.1 编译下载; g: h3 ^. X0 j4 O" l/ h' H( O+ P
1 r" ]! }+ ]$ x; _7 z- p
- \8 t E. @( F* B, R
& c6 k3 ]. r, L2 A- q& \+ B 3.2 测试
' Z( ^. o- J6 z- e, v ]- n( Y4 F 程序开启时,默认多项式参数是0x04C11DB7U,无输入、输出反转。每按键一次KEY2改变输入反转模式或输出反转模式或多项式参数 ,然后各按键一次KEY0和KEY1, log输出如下:+ i5 Z. S$ _; z x5 w1 f
V; {8 m. ]* n7 p) w8 F" Z
# U% L4 T( Y/ x0 z% L. K
& ~0 T; q* r3 ~ J" i4 p L 案例只是抛砖引玉,更多CRC功能及应用拓展请自行上手代码实践。9 V; \. K/ Y9 W0 E
————————————————
: A$ }2 S3 Q+ W版权声明:py_free-物联智能
3 G- c8 x% {8 C5 j# d- t+ x4 U如有侵权请联系删除
1 @ V+ e; E9 E5 @. `( @+ V/ J( E7 g$ T* t6 O3 r9 q
$ h3 E, ]; W, x g: l; R |
感谢分享 我想请问一下怎么用自带的CRC计算CRC16 数组类型是uint8的