一、stm32的CRC7 C. ?# j) {: `% C0 p- N
1.1 CRC的简介及MCU关联说明' U9 V* h" } w
STM32的CRC(Cyclic Redundancy Check,循环冗余校验)计算单元使用一个固定的多项式发生器,从一个32位的数据字产生一个CRC码。在业务开发应用中,会基于CRC的技术用于验证数据传输或存储完整性。在EN/IEC60335-1标准的范围内,它们提供了一种验证闪存(flash)完整性的方法。CRC计算单元帮助计算运行时软件的签名,并与在链接和生成该软件时产生的签名比较验证。# g8 X) F K; Q5 F) n# X9 y
cubeIDE开发, stm32调试信息串口通信输出显示_py_free的博客-CSDN博客_调试信息输出到串口
% ?' M! c/ G; L3 _* M# l% u
" t/ u! |; ^; K6 G2 h 现双击.ioc文件,打开CubeMX配置界面,开启CRC计算功能,参数保持默认设置。8 d. _) Q! q+ L+ E) r2 Q8 T; X% w
0 {/ f( V. }3 `, d: Z
/ Q* [- ?4 S# a9 L7 x* ^0 `1 \' K5 L
: N. D0 | T5 N% a' l
保存及生成输出代码) m; ~3 }; F, H! d% [
4 n0 w D5 ?- w w1 a8 c K
2.2 CRC的HLA库分析
/ U9 `7 c, P* l/ ?# ? cubeMX生成代码时,会在Core源码目录下的Inc及Src目录,分别生成crc.h和crc.c驱动文件。" a |* H- a0 n" z8 p7 r
. A# h: x8 g- K 在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函数。( Z& ^8 l/ A! P8 r2 N N. q# h
/ q# {. j1 \' j# u' P
7 [& r d! M/ ^. C# H- t) i0 u6 A/ V" m7 r& b
在stm32l4xx_hal_crc.c源文件中定义了HAL_CRC_Init函数,它做以下事情:诊断配置参数是否合规;调用HAL_CRC_MspInit函数完成CRC时钟开启;最后将依据参数写入CRC寄存器,如果采用默认多项式参数,写入默认多项式数值,否则调用多项式配置函数,写入用户定义数值。
& t7 f' x ]: t. p1 h
1 x' k4 q1 J3 ~) y/ F$ y3 r
+ {2 c8 j( B1 v$ I
* ?& b0 F2 x* H& [" ~# m
再回到crc.c内,HAL_CRC_MspInit函数实现了CRC时钟启动设置。
5 U% g# b1 t3 |6 K+ a$ i' j1 M/ R7 S3 A' a
) n, k; M; [. |) P- w
$ ^0 h; |* p/ K; e& m) R 另外HLA库提供了用户自定义设置多项式参数、输入数据反转及输入数据反转的函数,方便开发这在程序代码中按需变更CRC计算方式,这些函数作为扩展功能放置在stm32l4xx_hal_crc_ex.h/c内。
0 X' p+ p! h: M, p/ s" P. B3 ^4 l
, q4 T8 ^( s+ n2 W
, l, p2 x8 e: W0 E1 v
! `+ J- O. V% i
2.3 CRC计算功能及调用设计
O. ]- m! O! I+ H/ j3 ^ 在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的部分是每次计算一组数据前,都会进行数据寄存器重置
# H W5 h- J/ u0 t; `; T; X0 w, s3 y( ~
# N1 J: _. ^: U j% b# q
2 v+ G& s0 r; }+ R& A) b
9 N, {! T1 w; M- ]( S
$ c, H v3 i4 u A ] R 在main.c文件中,加入驱动文件支持
' d3 p$ m/ J( k! G+ i2 V1 a9 a- /* Private includes ----------------------------------------------------------*/
( R8 `( W8 R9 }6 i& r0 g - /* USER CODE BEGIN Includes */
8 F! \4 b2 k: Q" F# C0 T - #include "../../ICore/key/key.h"1 e2 j( M0 h$ i; A# v1 q; K8 s. s% y
- #include "../../ICore/led/led.h"& h5 v6 h/ ?! [" X' n
- #include "../../ICore/print/print.h"& d$ g# a* Z1 L) K# u
- #include "../../ICore/usart/usart.h"
( v* n- `8 g' K, p# T6 q7 Q - #include "../../ICore/delay/delay.h"
' `7 n' i0 S0 T - /* USER CODE END Includes */
复制代码 + k8 q) {( l, r& H' a5 i6 u
% i4 F4 p* O: E- B/ J% `8 c
在main.c文件中,加入CRC句柄(寄存器)声明1 O, |. P1 q9 I
- /* Private user code ---------------------------------------------------------*/
0 z9 @! I* k' R - /* USER CODE BEGIN 0 */
9 `9 \+ f- u& P S! z - extern CRC_HandleTypeDef hcrc;
8 w, Q t* W8 t - /* USER CODE END 0 */
复制代码
' @, R% b6 H" @3 `# {( _ 在main函数中,加入外设驱动启用(主要是串口调试中断开启)及相关初始设置,添加了一组3个长度32bit宽的数据数组用于测试。, m& O4 d0 W( s; v5 [2 h
- /* Initialize all configured peripherals */7 H% {$ {$ x6 F' H/ q
- MX_GPIO_Init();
/ Z* q# w' J) }$ }1 R - MX_LPUART1_UART_Init();* D+ K, r0 D) l, k4 n/ x
- MX_CRC_Init();
# G" [9 l- C) S5 N - /* USER CODE BEGIN 2 */0 a* _2 q2 E" w
- ResetPrintInit(&hlpuart1);8 M: ]6 V6 t* |6 m: _$ n! A
- HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再开启接收中断) F2 J6 n8 Y2 _" H) e! T( K% i1 ~
- HLPUSART_RX_STA = 0;
* K9 H4 L& K* ~ - //
8 t9 t: ^. \$ G7 a - printf("app restart now!\r\n");9 G. D( l& q; J8 `& B
- uint32_t crc_input[3] = {0X12345678,0X23456789,0X34567890};
% E" I# f Z# ]2 \0 Y! X$ t - uint32_t crc_output = 0x00;2 I: {, I0 T/ N7 H) p/ s- N, Z* h+ Y
- uint32_t crc_index = 0;
: Y, }' Y) D4 l) c. N - uint8_t crc_mode = 0;
* K; B0 I$ ? ^- Y - /* USER CODE END 2 */
复制代码 在main函数循环体中,通过按钮调用CRC计算功能,并通过lpuar1串口输出显示计算结果。
# m5 j( B" N& c- {! e- /* Infinite loop */& n" x8 r6 A! K+ E" e1 i. T
- /* USER CODE BEGIN WHILE */
1 a7 W# X) g9 O - while (1): l* G, L: ~$ a8 G" W
- {
5 ~; y" n" b5 L N& ?, U - if(HLPUSART_RX_STA&0xC000){//溢出或换行,重新开始% ^# K4 Y; d: q) i- K0 m
- //printf("%.*s\r\n",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);0 B3 l% x) A5 E: J1 M/ M
- HLPUSART_RX_STA=0;//接收错误,重新开始
- h' P q7 P, I+ B+ r+ z2 G - HAL_Delay(100);//等待& \, X% e7 }. r& C% Q) P
- }0 v2 L( h) T* ~! P: y
- if(KEY_0())) ^% L B0 V8 m1 u& ^* t7 W* w* t2 q
- {
% ~! M# l5 Z0 s, a% g1 X/ [/ L7 \ - crc_output = HAL_CRC_Accumulate(&hcrc,crc_input,3);
6 C; W) h3 v; _, X; G; l; x - printf("crc_Accumulate_output:0X%08lX\r\n",crc_output);0 M, ~2 \6 K& _- b- E( k
- }
9 e7 H7 Z% Z1 b. x& i: ? - if(KEY_1())6 A/ v/ h/ i# Y4 t0 j* l; u' _
- {
+ b) J, q0 S& ~# t7 ` - crc_output = HAL_CRC_Calculate(&hcrc,crc_input,3);
! n9 @5 ~: l4 V7 j; ^$ F; l# y - printf("crc_Calculate_output:0X%08lX\r\n",crc_output);9 g3 \6 ~5 h0 H: q4 s% y+ _
- }' J5 F6 Y1 m: N) i6 s4 _' G
- if(KEY_2())( n! N+ R) y. D( P) d
- {6 Q, f( z4 o* g$ X4 a- N% G
- crc_mode = (crc_index)%6;
7 K( v m6 U0 e2 ?: W* |" w, y - switch(crc_mode){* X H, m; A5 Z, A3 A9 z' ^: v4 {
- case 0:3 D& H* T6 j, x9 a, H# ~5 K' G
- HAL_CRCEx_Output_Data_Reverse(&hcrc,CRC_OUTPUTDATA_INVERSION_ENABLE);
" v: A' |" e, F$ ^ B9 ~ - printf("Output_Data_Reverse:0X%08lXU\r\n",CRC_OUTPUTDATA_INVERSION_ENABLE);7 ?1 ~* ]' Y4 B# S' U
- break;0 |, ]( l4 q5 c* q: P; u% h
- case 1:
+ T' {4 K% ^2 b - HAL_CRCEx_Output_Data_Reverse(&hcrc,CRC_OUTPUTDATA_INVERSION_DISABLE);
: v* T3 u7 e4 `6 x/ s5 a - printf("Output_Data_Reverse:0X%08XU\r\n",CRC_OUTPUTDATA_INVERSION_DISABLE);. @6 t k) p7 D2 d( D
- break;+ O) B! D3 j! k
- case 2:: Y! d; [- a/ A; x1 K
- HAL_CRCEx_Input_Data_Reverse(&hcrc,CRC_INPUTDATA_INVERSION_BYTE);) C9 l# N" d h9 L
- printf("Input_Data_Reverse:0X%08lXU\r\n",CRC_INPUTDATA_INVERSION_BYTE);
: }0 d. q0 r4 B! ~( P- O6 v' ]2 N/ P - break;& [5 l; E0 {0 h' K6 S" X. ?4 s
- case 3:
7 \1 O2 `3 x8 g+ K5 E - HAL_CRCEx_Input_Data_Reverse(&hcrc,CRC_INPUTDATA_INVERSION_HALFWORD);
- c1 f; w3 W4 g9 y( h - printf("Input_Data_Reverse:0X%08lXU\r\n",CRC_INPUTDATA_INVERSION_HALFWORD);! W6 i3 C0 L2 y$ N C
- break;
5 C9 J6 _7 g9 |# g4 A - case 4:) C0 \9 }' d/ H! o+ z, f2 @( d
- HAL_CRCEx_Input_Data_Reverse(&hcrc,CRC_INPUTDATA_INVERSION_WORD);$ u {' Y8 _7 k j. e9 r+ y
- printf("Input_Data_Reverse:0X%08lXU\r\n",CRC_INPUTDATA_INVERSION_WORD);
/ Z! s' B$ K0 K% K1 W" b - break;, n1 v# @% n! j7 W/ \5 y- p
- case 5:
( W7 ^* d+ O9 t$ C5 s - HAL_CRCEx_Polynomial_Set(&hcrc,DEFAULT_CRC32_POLY,CRC_POLYLENGTH_16B);% R* W9 G5 [( z4 J# r
- printf("Polynomial_Set:0X%04XU\r\n",DEFAULT_CRC32_POLY);5 I! z# b3 {8 S$ Z7 h% N3 A
- break;
( ]/ h2 s1 Q7 Z6 D) I( W - default:
# h; X F2 B$ G* s - break;
' Q5 Y. I; Y* c( Y! D; l, L! Z - }* Q2 H5 }& c$ k/ N+ t
- crc_index++;+ o, i" n3 x. G1 C
- }
; B8 P8 f, [8 \/ |( R0 N! w8 `2 ? - /* USER CODE END WHILE */
复制代码 $ ~) O! z4 f4 C6 l
三、编译及测试
6 z. ~0 a9 W& I' ? 3.1 编译下载9 P Q) ~" x( J z/ _7 A
- {$ D( c# k& U
: _, R% V* b2 x( C! h
# x4 P. M7 X* h$ m: @, @ 3.2 测试
8 a2 b) y" V( f/ S" T( {8 _4 H d( v 程序开启时,默认多项式参数是0x04C11DB7U,无输入、输出反转。每按键一次KEY2改变输入反转模式或输出反转模式或多项式参数 ,然后各按键一次KEY0和KEY1, log输出如下:& D. }) F4 @$ T4 W& E% _9 t$ O0 P, F
# {) O( H- N5 ^+ Z O: |3 W
. Y1 L! e6 a5 ?. Y
1 b$ s; E# ?1 { } q% N
案例只是抛砖引玉,更多CRC功能及应用拓展请自行上手代码实践。
" e# q9 {. h0 v3 j————————————————' d- G: L! P3 T7 a
版权声明:py_free-物联智能5 F1 L3 w( o9 Q4 m( c4 |# L
如有侵权请联系删除
$ j7 e0 C/ p" q
' K0 P0 c9 e9 G% ~. r# T8 I0 d$ q: E( V: e, W& l; w& K
|
感谢分享 我想请问一下怎么用自带的CRC计算CRC16 数组类型是uint8的