一、stm32的CRC" B$ }) Q: j4 l. E7 [
1.1 CRC的简介及MCU关联说明 T0 \5 g% N* m! O* t4 E# s9 J9 M
STM32的CRC(Cyclic Redundancy Check,循环冗余校验)计算单元使用一个固定的多项式发生器,从一个32位的数据字产生一个CRC码。在业务开发应用中,会基于CRC的技术用于验证数据传输或存储完整性。在EN/IEC60335-1标准的范围内,它们提供了一种验证闪存(flash)完整性的方法。CRC计算单元帮助计算运行时软件的签名,并与在链接和生成该软件时产生的签名比较验证。5 {# x) w6 m) I2 m
cubeIDE开发, stm32调试信息串口通信输出显示_py_free的博客-CSDN博客_调试信息输出到串口" e# E% g, w# \- c
! _ d p* S. V3 y
现双击.ioc文件,打开CubeMX配置界面,开启CRC计算功能,参数保持默认设置。
3 I: S. W2 o/ C3 N7 t* @
! f6 y# ]% s J
, C- v7 U5 p- H- {) h0 W! Q8 J
# m+ f( p3 Z6 k2 ~! @ 保存及生成输出代码
6 |4 m4 P& X) ?7 W3 C* K, L- C9 _* j5 ^" T
2.2 CRC的HLA库分析1 N9 w/ v$ V8 a4 u( W1 g. S
cubeMX生成代码时,会在Core源码目录下的Inc及Src目录,分别生成crc.h和crc.c驱动文件。
' B1 [ }, e. |' r% h3 B$ [& J6 |+ C8 W; n+ j$ ^
在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函数。3 k- p, ?4 g& I4 j, L
6 G. z8 U7 C( p% b+ Q0 [
% G) w% g. w+ r8 \, H
( y+ {6 s. e+ X& Z- ~
在stm32l4xx_hal_crc.c源文件中定义了HAL_CRC_Init函数,它做以下事情:诊断配置参数是否合规;调用HAL_CRC_MspInit函数完成CRC时钟开启;最后将依据参数写入CRC寄存器,如果采用默认多项式参数,写入默认多项式数值,否则调用多项式配置函数,写入用户定义数值。
4 r+ B6 u+ F1 E% i/ _4 E, V! c7 L9 z& F. q- Z) R7 b' U, i$ T& p
. a) i0 U" O) U: ?4 S: Q$ s; A
6 I9 T3 r5 c: R4 p7 V* }1 B 再回到crc.c内,HAL_CRC_MspInit函数实现了CRC时钟启动设置。1 W) c/ o8 E' d5 }
h; u& p! `( i; A3 ?; u
& E3 n. X' E3 O/ b: F
& S3 |& Y; k2 v# g3 V: T 另外HLA库提供了用户自定义设置多项式参数、输入数据反转及输入数据反转的函数,方便开发这在程序代码中按需变更CRC计算方式,这些函数作为扩展功能放置在stm32l4xx_hal_crc_ex.h/c内。
% C1 e2 {& @/ b, s2 @8 m3 [1 A5 K! ?6 o- E/ U. v
@+ E ^" c( x9 }, I9 K9 X/ w5 w
$ x( q6 K9 l2 m; K! ?8 f' E
2.3 CRC计算功能及调用设计/ x5 l5 x6 E3 s1 R% }! W \: H* }
在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 Q, m. v3 t1 ~7 U! ]8 r- Z
: D, ] a5 @' ?. `. X
5 r) n4 S' C+ h* K/ O( Y! n: Q7 s& u
$ \$ U: E7 e4 \: q1 j
4 ]$ S2 \" j$ r 在main.c文件中,加入驱动文件支持
5 N$ {. [. @$ l- /* Private includes ----------------------------------------------------------*/( }9 g. q* e5 P. v0 r- J9 Q
- /* USER CODE BEGIN Includes */
, T3 A" u e% y7 ?, c - #include "../../ICore/key/key.h"
. K; }# @. g8 V, m# H; [ - #include "../../ICore/led/led.h"
$ }5 |5 W3 J+ U; q# n% ^- N) l - #include "../../ICore/print/print.h"
' m( D' f9 F9 U+ ^, f2 [- G - #include "../../ICore/usart/usart.h"$ W- h; t, t/ t3 X0 ]0 b
- #include "../../ICore/delay/delay.h"8 E/ A- N* V; q- k O
- /* USER CODE END Includes */
复制代码 % N& `+ m& V. q$ @2 V
V9 }( ~% ^! {8 \8 E+ r 在main.c文件中,加入CRC句柄(寄存器)声明
# o8 m3 _$ Y$ w& a- /* Private user code ---------------------------------------------------------*/
7 w* H9 `7 G* c8 f, Q) U- j' i - /* USER CODE BEGIN 0 */$ `+ X! Y0 {6 I ~" o: @
- extern CRC_HandleTypeDef hcrc;$ X# s$ c7 C4 @: w+ |* k
- /* USER CODE END 0 */
复制代码 f' |& |2 s/ [
在main函数中,加入外设驱动启用(主要是串口调试中断开启)及相关初始设置,添加了一组3个长度32bit宽的数据数组用于测试。
2 ~1 L a, h9 ^' |1 V, q2 Y- /* Initialize all configured peripherals */
& O6 z$ A# H0 G. Q g. J - MX_GPIO_Init();
! ?: k" `- e0 O6 n* s8 i - MX_LPUART1_UART_Init();
! b1 o. J8 z' K$ r$ J) u- Q - MX_CRC_Init();' H# d9 W4 J. ~1 l* {& R8 \
- /* USER CODE BEGIN 2 */
+ k& ~8 v0 z% z - ResetPrintInit(&hlpuart1);4 f2 I+ ^) P0 l% S! F! }
- HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再开启接收中断4 d% C( D% [2 Y. o3 [
- HLPUSART_RX_STA = 0;
& ] _* c z& s. Q: Y - //
/ _* ]/ A/ I- q& }) @ - printf("app restart now!\r\n");' w( @+ k, C9 d1 I" Q9 {
- uint32_t crc_input[3] = {0X12345678,0X23456789,0X34567890};
* B7 |" ~# {( w5 i$ V - uint32_t crc_output = 0x00;
5 @% o% C7 c/ M1 x& J - uint32_t crc_index = 0;' f. P7 A$ B$ h1 \* |
- uint8_t crc_mode = 0;% x1 X1 r- b h
- /* USER CODE END 2 */
复制代码 在main函数循环体中,通过按钮调用CRC计算功能,并通过lpuar1串口输出显示计算结果。8 J6 n) s6 Z- [2 Y! R" l
- /* Infinite loop */. ]- g4 q% q1 J
- /* USER CODE BEGIN WHILE */5 e1 @6 l$ `/ a6 J! J8 S
- while (1)
' J# Q/ h3 L$ w& B8 r - {
0 X8 M( ]& }! J+ v" d8 o - if(HLPUSART_RX_STA&0xC000){//溢出或换行,重新开始
7 {% T8 o9 F. \. w8 r0 n" ` - //printf("%.*s\r\n",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);
- p5 l4 f3 z% I0 s/ W - HLPUSART_RX_STA=0;//接收错误,重新开始
4 |: Z% K, Q( m& ?' e3 K - HAL_Delay(100);//等待
; \. ^3 g: P" d; h7 b" x. E, b1 c - }4 Z6 W1 q$ y8 K3 \; r8 Q
- if(KEY_0())& z3 }1 W1 \. G$ F: r+ h
- {- ` q3 X5 L2 i/ y+ e P
- crc_output = HAL_CRC_Accumulate(&hcrc,crc_input,3); Y3 \# n$ x. i6 ]8 g
- printf("crc_Accumulate_output:0X%08lX\r\n",crc_output);
7 A0 ]& n4 m' r9 `/ H - }
8 r4 ~+ ]1 e# E% i) p: u - if(KEY_1())
: _5 }. x/ K: K' ]6 m | - {
; {! s% I( [ ^2 ]( R( \& C% K9 d - crc_output = HAL_CRC_Calculate(&hcrc,crc_input,3);, d6 G6 {, L; X4 K/ s& V
- printf("crc_Calculate_output:0X%08lX\r\n",crc_output);
2 G6 G ^4 E9 X( I& V# p2 P @( K) t7 u& [; S - }3 l/ l$ b' n5 F
- if(KEY_2())0 R H% Z' L( A3 W
- {
! g& `7 {. ?4 ]+ e* B - crc_mode = (crc_index)%6;
* c- J+ N# j( w! Y9 P - switch(crc_mode){
% g( L3 Z) n: C' v# A4 u - case 0:! C" T7 |# Q& r/ C
- HAL_CRCEx_Output_Data_Reverse(&hcrc,CRC_OUTPUTDATA_INVERSION_ENABLE);
1 s& L# l% c7 d+ Q' W- |% y - printf("Output_Data_Reverse:0X%08lXU\r\n",CRC_OUTPUTDATA_INVERSION_ENABLE);
5 E( \2 w5 W. q - break;# h- q; M/ K) _3 e0 `* i: `3 y
- case 1:# ?4 |/ Q3 ]& B9 Z3 p) n6 X
- HAL_CRCEx_Output_Data_Reverse(&hcrc,CRC_OUTPUTDATA_INVERSION_DISABLE);, s: e& @& ?6 x# e$ g
- printf("Output_Data_Reverse:0X%08XU\r\n",CRC_OUTPUTDATA_INVERSION_DISABLE);
+ ` O5 ? Z3 y' L6 c8 i - break;' V! x' E9 K2 s' e' u
- case 2:" Y" d! u- s/ u2 q' Z7 d
- HAL_CRCEx_Input_Data_Reverse(&hcrc,CRC_INPUTDATA_INVERSION_BYTE);
8 }, Q! U8 J, D9 S4 ~& ?! X- N - printf("Input_Data_Reverse:0X%08lXU\r\n",CRC_INPUTDATA_INVERSION_BYTE);8 Z5 s9 @+ [# R O2 P
- break;
, @7 A7 u7 k9 @3 E+ u7 n3 D& q" l - case 3:
0 T8 m, D6 I" o) p+ {- n - HAL_CRCEx_Input_Data_Reverse(&hcrc,CRC_INPUTDATA_INVERSION_HALFWORD);
* D) s# P5 q x6 @+ A5 E& P+ H - printf("Input_Data_Reverse:0X%08lXU\r\n",CRC_INPUTDATA_INVERSION_HALFWORD);
# @+ b& Y7 z- r- Z* y: e7 p2 @/ A - break;, O5 c0 k3 M+ c' U' d i v- s
- case 4:& x* X) Y# N" q& j# f
- HAL_CRCEx_Input_Data_Reverse(&hcrc,CRC_INPUTDATA_INVERSION_WORD);# h/ y- q1 k( z/ L6 e2 k" S
- printf("Input_Data_Reverse:0X%08lXU\r\n",CRC_INPUTDATA_INVERSION_WORD);% {9 a' e3 k3 { I0 V c" t
- break;
+ K2 \. `! P! q* r1 ` - case 5:4 H% N. @( R3 v8 q9 \
- HAL_CRCEx_Polynomial_Set(&hcrc,DEFAULT_CRC32_POLY,CRC_POLYLENGTH_16B);
8 `5 k- N) q3 X" `6 c& V - printf("Polynomial_Set:0X%04XU\r\n",DEFAULT_CRC32_POLY);
' t8 p8 }( R4 A; c4 Z/ V - break;4 z! p3 b! y7 ^
- default:2 p k# G7 W) u- ^
- break;
& { ^ @/ K. {3 c6 X: P - }, _2 a; N. l+ f8 W: x8 D; i
- crc_index++;
f/ H8 W& q# Q' S$ e, i/ j - }
: t; Z$ H# S5 f, q8 r' H9 W - /* USER CODE END WHILE */
复制代码 3 {' V+ l9 X! P- j# J, j
三、编译及测试
. R, ]8 N0 r. o R$ ^" \( `, g 3.1 编译下载2 _( A% e& q4 I) V0 U
$ n; P/ O4 C; \8 ~4 ~
$ p; c* r& U0 F* j1 [* G0 |# a& x# u6 c5 d/ F& F; P5 E2 g4 e3 G
3.2 测试
. r t- `6 U% e& A3 v 程序开启时,默认多项式参数是0x04C11DB7U,无输入、输出反转。每按键一次KEY2改变输入反转模式或输出反转模式或多项式参数 ,然后各按键一次KEY0和KEY1, log输出如下:
, Z% R% i& J# v& r
4 j3 s( O( d. I. h
' M# O; P2 y& j- V; }1 V
/ F/ u2 g5 S# G& x/ ? 案例只是抛砖引玉,更多CRC功能及应用拓展请自行上手代码实践。2 h: x( Q' f" u$ m. K
————————————————
& x& e1 ^: H% G2 M/ c* Z1 h版权声明:py_free-物联智能) ^; ^7 G& K2 `
如有侵权请联系删除5 o6 k! K$ X' l7 O- e9 }. i
; c4 a3 B# I3 K* N
4 A! s, s a7 ^6 ?: ~) ~ |
感谢分享 我想请问一下怎么用自带的CRC计算CRC16 数组类型是uint8的