你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于STM32CubeIDE的CRC计算及HAL库经验分享

[复制链接]
攻城狮Melo 发布时间:2023-4-6 14:41
一、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
c2c4d48e9acf416aa8e43b1cf9391ed5.png
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
d447f0adad3c4f9aa48ac88d10bf3b9e.png
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
fa9844c76e13484bbe0f4e62143ef7d2.png
$ 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
aa24df14830748a89db2472c225db0b4.png . 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
51d647ac690f4e0dbc794e47689c52c0.png ! 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
49ccb6008c534c3a9a559f9fa892450c.png 1 G: i% }( n" m0 l3 F8 }

$ I0 C& b: L7 K) ]( A; y
c8d3148af0fb4b1f9d90b0eab6e72fa8.png   I( M1 I. m$ E2 n, b1 Q2 W0 }- [

( b6 r9 x% M. c* Y* q         在main.c文件中,加入驱动文件支持  x7 d' g7 b  b1 S
  1. /* Private includes ----------------------------------------------------------*/
    0 x+ F2 C& y- T) N4 @! E
  2. /* USER CODE BEGIN Includes */
    ' {8 K5 R' ]% ^7 N$ j# |! V) F: l
  3. #include "../../ICore/key/key.h"
    $ U! s2 I- c) y+ j) f, F' N* b& m
  4. #include "../../ICore/led/led.h"
    3 a" c9 G) X$ k# q
  5. #include "../../ICore/print/print.h"
      ?. r/ u/ P0 M+ }4 d3 U# z* @+ J+ g+ s
  6. #include "../../ICore/usart/usart.h"
    3 O* u/ }+ D' V+ _+ |; a0 p1 \
  7. #include "../../ICore/delay/delay.h"
    & B, {' [* c5 U7 L8 L
  8. /* USER CODE END Includes */
复制代码

% y( F0 z7 V5 u( f( g
7 ]: ]( R8 Q1 o+ [9 u) Q
        在main.c文件中,加入CRC句柄(寄存器)声明
; K' G& P. N; }4 i- w
  1. /* Private user code ---------------------------------------------------------*/* i, ~, l7 ?9 X! h0 N
  2. /* USER CODE BEGIN 0 */
    + H" B, s$ r! T9 r* A+ b/ M
  3. extern CRC_HandleTypeDef hcrc;0 C/ z: A& Z( B& Q$ p, w
  4. /* USER CODE END 0 */
复制代码

) x1 Q6 Q6 R5 W5 P6 A        在main函数中,加入外设驱动启用(主要是串口调试中断开启)及相关初始设置,添加了一组3个长度32bit宽的数据数组用于测试。
5 F  n9 v7 X3 q9 _
  1. /* Initialize all configured peripherals */4 j# a: l8 c7 S& p: _: u9 ]
  2.   MX_GPIO_Init();' i! s! `; t) z$ o1 r$ g) }
  3.   MX_LPUART1_UART_Init();/ F8 u4 }$ X) @
  4.   MX_CRC_Init();! Z/ B  C  P1 k. P( G) L
  5.   /* USER CODE BEGIN 2 */
    ! D) h' O3 c4 S7 Z8 ?/ d( Q- ^
  6.   ResetPrintInit(&hlpuart1);) c  r0 O! Q  S: X
  7.   HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)&HLPUSART_NewData, 1); //再开启接收中断8 e5 n* _8 E" C5 T2 c" j
  8.   HLPUSART_RX_STA = 0;; l* b1 e5 {" b" H% u" y9 t4 e, b
  9.   //: ?+ a& h, N% f  @) a
  10.   printf("app restart now!\r\n");6 X* p: w/ n, `
  11.   uint32_t crc_input[3] = {0X12345678,0X23456789,0X34567890};9 ^0 d9 t  V2 u
  12.   uint32_t crc_output = 0x00;
    . J& G) }% h, i, R6 b& ?
  13.   uint32_t crc_index = 0;
    . K# ~( B5 r/ s$ t; N
  14.   uint8_t crc_mode = 0;0 F( {5 K2 G. s7 L3 w7 x9 _
  15.   /* USER CODE END 2 */
复制代码
       在main函数循环体中,通过按钮调用CRC计算功能,并通过lpuar1串口输出显示计算结果。; n$ {* c% |* z, S! o5 X
  1. /* Infinite loop */( a4 L0 T8 Q/ w% [1 d; \2 T" o" l
  2.   /* USER CODE BEGIN WHILE */" F6 s3 _' ~  t+ u' e; V* V% |
  3.   while (1)
    3 V: K) a6 e! W3 p% d4 T- z
  4.   {/ z+ k5 g: K6 k+ B- Y
  5.             if(HLPUSART_RX_STA&0xC000){//溢出或换行,重新开始: T! e, h. ^- m7 L
  6.                     //printf("%.*s\r\n",HLPUSART_RX_STA&0X0FFF, HLPUSART_RX_BUF);4 @# ~% {# E. Q: z
  7.                     HLPUSART_RX_STA=0;//接收错误,重新开始6 N+ \1 M. U7 T2 e6 i
  8.                     HAL_Delay(100);//等待1 d: w- i( ^0 T
  9.             }# I+ N# d( f& k
  10.           if(KEY_0())$ g3 z) R: f( H6 A9 X# q& Q
  11.           {; G% i8 J" o/ s' k2 y, E! W
  12.                   crc_output = HAL_CRC_Accumulate(&hcrc,crc_input,3);
    0 E1 s( }' V; _6 W/ ~* v% S
  13.                   printf("crc_Accumulate_output:0X%08lX\r\n",crc_output);
    # n2 m6 W" s4 u# m- i
  14.           }
    ( p5 f( ^) |+ ?3 L5 a
  15.           if(KEY_1())
    + a+ L8 ~1 ?- V- O
  16.             {
    * i; X$ q- p+ G
  17.                   crc_output = HAL_CRC_Calculate(&hcrc,crc_input,3);9 s3 F4 _  Z: n* s2 x4 M  G
  18.                   printf("crc_Calculate_output:0X%08lX\r\n",crc_output);
    0 z5 L! v4 ~/ }+ T" o1 X: o
  19.             }' k9 Y3 }9 d' A+ q4 \) _: V/ @
  20.           if(KEY_2())
    8 T( g) z! P+ E  _4 k# J
  21.             {
    6 J8 N/ ?9 q! N1 Y" T  m
  22.                   crc_mode = (crc_index)%6;
    4 l, N* b& B1 X% E/ V6 J
  23.                   switch(crc_mode){
    & F4 k* B* W: g/ D8 M* i
  24.                   case 0:* w4 ]$ p" I2 z4 ], |
  25.                           HAL_CRCEx_Output_Data_Reverse(&hcrc,CRC_OUTPUTDATA_INVERSION_ENABLE);
    9 U, \& s* F. \7 N7 a
  26.                           printf("Output_Data_Reverse:0X%08lXU\r\n",CRC_OUTPUTDATA_INVERSION_ENABLE);
    8 Q5 w: p6 L" y6 N" F
  27.                           break;; ~. z: `$ ?' |# a
  28.                   case 1:* [$ E" I# W/ M6 t
  29.                           HAL_CRCEx_Output_Data_Reverse(&hcrc,CRC_OUTPUTDATA_INVERSION_DISABLE);
    $ x* f' f$ k$ f. Y2 P6 X
  30.                           printf("Output_Data_Reverse:0X%08XU\r\n",CRC_OUTPUTDATA_INVERSION_DISABLE);
    ' \4 }! {, p9 }) i' I& r- y2 s
  31.                           break;% k2 ^: e  m; J8 `* P, r% `
  32.                   case 2:
    , e% w& C- N) Y  S1 _2 P" ^
  33.                           HAL_CRCEx_Input_Data_Reverse(&hcrc,CRC_INPUTDATA_INVERSION_BYTE);; m- A  ^/ u! [4 I6 E+ a
  34.                           printf("Input_Data_Reverse:0X%08lXU\r\n",CRC_INPUTDATA_INVERSION_BYTE);/ f4 K4 b6 X  g
  35.                             break;% B! o& u/ i9 B
  36.                   case 3:
    1 p- U7 S3 Z4 A) Y5 m. h& r2 D
  37.                           HAL_CRCEx_Input_Data_Reverse(&hcrc,CRC_INPUTDATA_INVERSION_HALFWORD);
    * ?% w7 c2 Y4 o$ q( V6 f
  38.                           printf("Input_Data_Reverse:0X%08lXU\r\n",CRC_INPUTDATA_INVERSION_HALFWORD);4 g9 N" |- U8 {2 u0 @1 U% G: b" B, P
  39.                           break;! |/ u/ `) ?" o( M  u) ]
  40.                   case 4:
    % G1 |+ L5 t% F+ r1 }, b; {
  41.                           HAL_CRCEx_Input_Data_Reverse(&hcrc,CRC_INPUTDATA_INVERSION_WORD);
    7 V6 n" o" k! p9 {& E
  42.                           printf("Input_Data_Reverse:0X%08lXU\r\n",CRC_INPUTDATA_INVERSION_WORD);1 ^1 D/ {+ \* Y
  43.                             break;  m3 w5 V* Q1 }7 a6 F
  44.                   case 5:
    ) l5 U  `/ G% W
  45.                           HAL_CRCEx_Polynomial_Set(&hcrc,DEFAULT_CRC32_POLY,CRC_POLYLENGTH_16B);, y" l4 P7 n0 [7 p6 f$ o5 r1 t
  46.                           printf("Polynomial_Set:0X%04XU\r\n",DEFAULT_CRC32_POLY);
    3 H9 V9 F9 T, J, \' `0 m
  47.                             break;; h+ i1 U, \) U$ V, Q; s1 |( `7 g! X
  48.                   default:
    2 n% B. }4 H6 n4 S" O$ U
  49.                           break;
    9 M$ s  k* D; ]. E2 E- a5 I3 N; W
  50.                   }
    . a9 }: p. I! K) s8 @$ u
  51.                   crc_index++;% A* N" L# z/ H! J. o
  52.             }* K! o1 K3 Y9 ~6 _; y" W
  53.     /* 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
2f90fd2c88724e4fb13b8f1519dc258b.png - \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
11bedbc3fabc45af9a5b6994f93756d8.png
# 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
95e75996ff634be49a0bdafe213fd714.png
9d05f96509f146cba1ad0e0173c0923f.png
2f6ac844f7204475a733919129f29f72.png
4042774bbead4d149cc6f77becd178f4.png
47c61625b35c47a9a195d49d9fea6816.png
9c8aaa5f064a4682a3008c3b3f719478.png
e080d4f00f0c4e96b60c20d0abcab316.png
10a2e9189ff54e4b9e56fb7a81cd7bdd.png
d2bfcb5550e3433b83f52a06009840ba.png
3375d9c11b994ce8b8b7bcc88fb265e7.png
44de2117e5d64f13929724cf8a947de2.png
35ff3ea4e1844acc8c7ca553941a5fc6.png
赞 收藏 1 评论1 发布时间:2023-4-6 14:41

举报

1个回答
过去痕迹 回答时间:2023-4-14 16:34:27

感谢分享 我想请问一下怎么用自带的CRC计算CRC16 数组类型是uint8的

uint32_t HAL_CRC_Calculate(CRC_HandleTypeDef *hcrc, uint32_t pBuffer[], uint32_t BufferLength); //只允许调用这个
static uint32_t CRC_Handle_16(CRC_HandleTypeDef *hcrc, uint16_t pBuffer[], uint32_t BufferLength);//调用需要修改static属性 不然不让用

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版