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

STM32MP1 M4裸机CubeIDE开发指南-硬件随机数实验

[复制链接]
STMCU小助手 发布时间:2022-9-28 18:51
硬件随机数实验
& I: B% ^3 }. @: ]0 @: L; q: Q5 J. e( I本章,我们将介绍STM32MP157的硬件随机数发生器。我们使用KEY0按键来获取硬件随机数,并且将获取到的随机数值通过串口打印出来。同时,使用LED0指示程序运行状态。. t: D0 j2 P' `1 J" G; `( z

5 R* v9 q/ ]' e. n. X5 N2 V20.1 随机数发生器简介3 V  ]: p: D% k2 ~" e& N' `9 x
STM32MP157自带了硬件随机数发生器(RNG),其中RNG1给A7内核使用,RNG2给M4内核使用。RNG处理器是一个以连续模拟噪声为基础的随机数发生器,在主机读数时提供一个32位的随机数。: F, E# }$ }3 S
20.1.1 RNG框图
% q* n6 P! U1 L8 a4 |( o下面先来学习RNG框图,通过学习RNG框图会有一个很好的整体掌握,同时对之后的编程也会有一个清晰的思路。STM32MP157的随机数发生器框图如下图所示:
5 m0 @: z* B2 t1 M
  ~* X, b; k2 @ 948b166ef8df447eae44efcb1e13f983.png
6 Y* l* j/ x7 `- Y8 Z, C5 o) J) ?/ H8 g6 ]/ b
图20.1.1. 1随机数发生器(RNG)框图% F) f$ f& a" H* |  q
随机数发生器有2个时钟域:AHB时钟域和RNG时钟域。AHB 时钟用于为 AHB 存储寄存器和调节组件提供时钟信号,RNG 时钟用于噪声源采样。如果 RNG_CR 寄存器中的 CED 位设置为“0”了,即启用时钟错误检测,那么 RNG 时钟频率 必须大于 AHB 时钟频率的32 分之一,否则时钟检查器会指示时钟错误,RNG 将停止生成随机数。在配置时钟时,注意此范围。
- z) @$ @) e; V- h; P  \0 [RNG时钟域时钟为rng_clk,rng_clk由RCC_RNG2CKSELR寄存器的RNG2SRC[1:0]位选择具体的时钟源,具体选择关系为:
: h: a" U+ M- {+ S, @0x0: csi_ker_ck
* y$ k* x1 v) ]3 _0x1: pll4_r_ck
5 C+ `* c/ }' D0 P& h; ]1 I; O0x2: lse_ck clock$ ~# z) j3 v; M+ d
0x3: lsi_ck
1 f9 c- y9 n, `7 R( D默认情况下STM32CubeMX会选择0x0: csi_ker_ck(4 MHz)作为rng_clk的时钟源,最大可通过PLL4配置为48MHz:6 \4 L2 f6 O9 {# \& N) U  n

% b) T* x% H4 D& E* r9 j: K) [ 698a8aa0268d4a76abfadcfbc0c54ff6.png
* |2 T4 v% G: ~' g; K- e: p* F- l" r' V3 o6 p6 g
图20.1.1. 2 RNG2默认采用CSI作为时钟源) n( b/ S4 U* Y9 F) ]' v) J0 R
AHB时钟域的时钟来自AHB3(最大为209MHz),用于访问相关寄存器等,通过RCC_MC_AHB3ENSETR的RNG2EN位(bit6)使能。可见,4MHz小于209/32,如果开启时钟错误检测,注意配置RNG2的时钟范围。/ K: w9 A( D9 e3 P" |
9 R1 X/ p/ S) J& N: [
e7bcecb9be8d4075a8d6741c2be36332.png
6 u. t, m! x" E5 J5 J7 D0 X& i( Z( ~
9 N- w& l9 T# Z% K5 m, q图20.1.1. 3 RNG时钟
. I. }2 z: c5 \1 q$ sRCC_RNG2CKSELR和RCC_MC_AHB3ENSETR这两个寄存器我们就不做介绍了,大家参考手册。从RNG框图整体上知道,RNG有两个输入和一个输出。具体如下表:2 A% R# i8 i+ p

' Z$ l* `! t* B  l 96c86692b27941bebc458eee62773e42.png
  a9 q. K4 C8 C  }
) h- ~1 Z9 t9 c) p6 L1 A6 A表20.1.1. 1 RNG内部输入/输出信号
/ m% P9 m, Z( u+ M$ M5 USTM32MP157的随机数发生器(RNG)采用模拟电路实现,由内部两个模拟噪声源产生种子,经过采样和归一化处理,再经过线性移位寄存器和判断逻辑,最终输出到RNG_DR,生成32 位随机数。) v: }) z: g& \( ~8 R# X
每个模拟噪声源由3个环形振荡器组成,振荡器产生的输出经过异或运算产生种子,经过采样归一化处理后,输出到RNG内部的线性移位寄存器。采样频率由rng_clk时钟提供,因此,随机数质量与 HCLK 频率无关。当将大量种子引入线性移位寄存器后,经过判断逻辑,最终输出到数据寄存器 (RNG_DR)。2 L, y% v; a7 K
同时,系统会监视模拟种子和专用时钟 rng_clk,当种子上出现异常序列,或rng_clk时钟频率过低时,可以由RNG_SR寄存器的对应位读取到,如果设置了中断,则在检测到错误时,还可以产生中断。+ z! L! m& s3 Y! K
20.1.2 RNG寄存器
& Z& |* [. t+ w/ j% D1.RNG控制寄存器(RNG_CR)
. [- E+ l" ]+ L: G/ O/ XRNG控制寄存器描述如下图所示:) p. F( L; r! U) F. ?

% M5 \% x3 Z& n- Q0 U7 L d730dffd53bf421caf8f752b159e98e4.png   O5 t& ?* a4 K2 l! t9 _1 N
+ Y2 n6 N2 \( P6 A
图20.1.2. 1 RNG_CR寄存器" c, z$ f+ S; c
该寄存器我们只关心RNGEN位,该位用于使能随机数发生器,所以必须设置为1。* F: w* Q. F/ s3 N; t& C
2. RNG状态寄存器(RNG_SR)
4 L1 ]5 r% c, t. B, `RNG状态寄存器描述如下图所示:+ }% l9 X4 L+ o, r" ?- f

" ~" z# [; R: h* _8 ` ce24f1c9f4954d3ab0b26abd65003e4b.png
: q1 v6 o3 W8 m  [; ^7 \. t5 e; g; O0 X9 d+ S5 W7 l9 V3 O
图20.1.2. 2 RNG_SR寄存器
! [* f! q1 ?2 q+ ]( R6 |8 v/ L该寄存器我们仅关心最低位(DRDY位),该位用于表示RNG_DR寄存器包含的随机数数据是否有效,如果该位为1,则说明RNG_DR的数据是有效的,可以读取出来了。读RNG_DR后,该位自动清零。
8 O/ \; i9 b0 d# U- w8 q5 n( H8 B  `6 N3. RNG数据寄存器(RNG_DR)
& H$ f3 @. C% S# c  |: {; y" vRNG数据寄存器描述如下图所示:
+ R. X2 @* K; d& `9 G
; L6 ?9 r) K- c 04dd465c96984062a7f83cc419e21de7.png
! N; Y6 ^( a9 a3 o) J0 \
( F; k  Y( g$ R: G6 n: P图20.1.2. 3 RNG_DR寄存器4 l9 M; [0 a& [
RNG_DR寄存器是只读寄存器,我们可以读取该寄存器获得32位随机数值。此寄存器在最多216个AHB时钟周期后,又可以提供新的随机数值。
9 P) d" r: P. C, h1 Y1 Q
# u) E$ }6 A  L: v  ]20.1.3 RNG的HAL库驱动* @8 ~) b* s. ]* I
RNG在HAL库中的驱动代码在stm32mp1xx_hal_rng.c文件(及其头文件)中。
! F; E- K( G  Y) s9 B6 X4 P  H8 j8 `1.HAL_RNG_Init函数
1 _( Q8 ]. T. j+ J+ F  URNG的初始化函数,其声明如下:
* P2 l" w/ @! a3 r5 H: k; E( ~
  1. HAL_StatusTypeDef HAL_RNG_Init(RNG_HandleTypeDef *hrng);
    4 d, F- M; x. z) s4 i4 M: k, Z1 ~3 I7 p
  2. ●函数描述:: r$ u6 N9 o0 _: t
  3.         用于初始化RNG。( j  `( _: l9 M' X2 A7 I
  4. ●函数形参:6 h8 q/ j" K' x0 d
  5.         形参1是RNG_HandleTypeDef结构体类型指针变量,其定义如下:' r' Q% A2 i. Y; K$ K
  6. typedef struct
    3 Y! M0 \. {- a9 ~( j- ?2 v
  7. {
    $ ^' o  U( ?' T0 X* c. G5 E& i
  8.   RNG_TypeDef                   *Instance;    /* RNG基地址 */$ a) v% n; z- a2 d
  9.   RNG_InitTypeDef               Init;         /* RNG初始化配置结构体 */; f1 c2 d, b8 K" {  V/ v! z
  10.   HAL_LockTypeDef               Lock;         /* RNG锁设置 */) D/ `- R6 ]+ I: Z" D1 D/ M' ~
  11.   __IO HAL_RNG_StateTypeDef   State;        /* RNG设备访问状态 */- I# @2 S3 @! V! F7 y
  12.   __IO  uint32_t                ErrorCode;    /* RNG错误代码 */
    " s6 \  ?, L$ t$ R) D
  13.   uint32_t                      RandomNumber; /* RNG最后生成的随机数 */
    ; F! h4 r9 ~7 `3 W- _' ?
  14. } RNG_HandleTypeDef;
    2 v  h, c2 A8 I6 _( }# i0 h
  15.         1)Instance:指向RNG寄存器基地址。
    , |' s2 O& [3 O" E- E
  16.         2)Init:是的RNG初始化结构体,其结构体类型RTC_InitTypeDef定义如下:9 @5 T+ f0 F7 I3 y: ?- z
  17. typedef struct8 {& A& }5 g' x, @" `
  18. {, b9 l; m3 s/ x& c7 O
  19.   uint32_t            ClockErrorDetection; /* CED时钟错误检测 */
    2 P' m! V1 W9 l5 Y+ N, H+ W
  20. } RNG_InitTypeDef;
复制代码

2 M. d8 ?/ c, b- B, D3)Lock:用于配置锁状态。- r* O4 m9 T5 z0 K; X- i
4)State:RNG设备访问状态。
+ `1 K8 G7 t) T- U# w* @5)ErrorCode :RNG错误代码* x1 o8 q) A: M4 r
6)RandomNumber :该变量存储RNG最后生成的随机数. |0 o& |; d& L0 ~  c

' m; ~* q% f4 f' R●函数返回值:
3 s. L! A' g$ E5 HHAL_StatusTypeDef枚举类型的值。8 c" |0 E, k8 N* {0 m
2. HAL_RNG_GenerateRandomNumber函数+ D  L1 g4 Z9 v! w
HAL_RNG_GenerateRandomNumber是RNG生成随机数函数。其声明如下:
0 x' ~4 f/ J4 B* Z! o" [+ }4 zHAL_StatusTypeDef HAL_RNG_GenerateRandomNumber(RNG_HandleTypeDef *hrng,/ [( m9 H1 x1 ?/ n/ }( `2 ~
uint32_t *random32bit);
5 c: M/ b1 K3 U" L- Q●函数描述:
3 B! T; P+ c- C, |' s1 F( T该函数用于RNG生成随机数。0 K% j/ o2 U# H& J" |# x
●函数形参:3 K7 n1 X8 M- C# x4 _4 g6 i
形参1是RNG_HandleTypeDef结构体类型指针变量,即RNG的句柄。( X  P  D' {# L
形参2是uint32_t类型指针变量,随机32位指针,生成随机变量。! a7 n4 Y& h2 r2 b$ l
●函数返回值:- H7 L* n3 ?4 |! f
HAL_StatusTypeDef枚举类型的值。9 d9 L, J  `9 ]. U, }( k

$ a# G% U9 X& ?2 u! U/ a20.2 硬件设计
2 H+ Y( J, ^. f1 c! Q0 G0 x1.例程功能7 t  l4 \* @2 L
本实验使用STM32MP157自带的硬件随机数生成器(RNG),获取随机数,并通过串口打印出来。按KEY0可以获取一次随机数。同时程序自动获取0~9范围内的随机数,显示在屏幕上。LED0闪烁用于提示程序正在运行。
; r. t; ^; w2 H) Y; T2.硬件资源
6 u, ], g$ U# m. ], A1)LED灯:LED0* c5 m! o' H' [; P7 ]9 N
2)独立按键 KEY0+ F' P: H  H* D
3)串口42 f. n* f; G3 z& o7 C8 @' ?
4)RNG(硬件随机数生成器)
2 \. M. S: O$ J* C2 tLED0 KEY0 UART4_TX UART4_RX9 G0 _$ ~! S3 q4 V, t: M
PI0 PG3 PG11 PB2/ F0 ?4 H4 Y( b$ `/ T4 A( K
表20.2. 1 硬件资源
: ?5 L) Q3 \4 X  G9 t0 e3.原理图$ D- {& E7 q# S, \; x# T
RNG属于STM32MP157内部资源,通过软件设置好就可以了。
4 |# n$ y# B, {: }# X( G" r8 N
1 X8 C5 S1 u/ [- G# m9 W( \. ]) V20.3 软件设计
8 C5 w% A: {) P% _* \3 g: N本实验配置好的实验工程已经放到了开发板光盘中,路径为:开发板光盘A-基础资料\1、程序源码\11、M4 CubeIDE裸机驱动例程\CubeIDE_project\ 13 RNG。
7 v/ w) [8 A4 p0 k+ q' ^. ]+ y( i20.3.1 程序流程图
- P5 S0 G7 c8 M' J下面看看本实验的程序流程图:& A8 b; G: b+ ]7 ], E5 H+ ^( S

6 Z. g4 u6 E9 K, Y$ I. j 3f99ad887c3b4ee6917cf73ad6f407d4.png $ L: s( m  A! c9 {/ {4 V
/ ?2 B. e) y8 r, _# o
图20.3.1. 1硬件随机数实验程序流程图1 p0 h  v- u: R
9 T. x" |* a; H; V$ ^/ v
20.3.2 软件配置; w+ Y% X6 i; j4 t+ W
1.新建和配置工程
7 g( L! j3 Z, @5 h0 u& G本节实验可以在前面的串口通信实验的基础上实现,因为用到串口UART4,也可以重新新建一个新的工程。这里新建工程RNG,然后配置串口UART4和按键KEY0以及LED0,具体的配置步骤我们前面的实验章节都有介绍过,如果不记得配置步骤,大家可以回顾前面相关的实验章节。本节实验中,LED和按键只用到LED0和KEY0,其它LED和按键没有用到,如果直接使用前面BSP文件夹里的led.c、led.h、ket.h和key.c文件的话,可以直接将其他LED和按键也一起配置了。
( c8 e3 N1 ~7 D) T6 H" K. N! S1 d(1)GPIO配置% ]5 c$ P7 G: N  j
LED0和KEY0配置如下:
: u! G5 I' l; ~. v
8 N& ]5 C. k+ p9 e 6026e638dc554e4c91e2b8cbf73b5984.png
: M3 |2 X. Y  e* `6 y4 I# K, |4 x+ C$ @5 I( N0 ]2 D0 y& C6 b+ C
图20.3.2. 1 LE0和KEY0配置: s' D( T, b3 l  I$ l' {% G2 V
UART4配置如下:
/ z3 g: h$ c- m  z; W0 C; J2 [7 q: J
4 X0 h0 F  s% p5 m/ L. }$ ?+ | 36ba603f8cb54816aca9fdbdf933934a.png
. E- h- M3 e; }3 r. T1 r8 X" G3 U% m
图20.3.2. 2 UART4配置% j8 Z2 A3 y3 Z8 f% X* Q9 B
(2)NVIC配置:4 l( D# l3 e* L# j
UART4参数使用默认配置:2 s+ b% Y$ v9 ?
  ~' B  X3 j7 O3 E9 u. y2 z/ ]
b45bbd9b64fe4fd7bc948b3f36a46d80.png
" N  |/ y% }, ?& s4 P# s( H; V
; Y# U. l. _" Y  ^6 _2 B图20.3.2. 3 UART4参数配置8 V7 ?' I: |8 [; Y. A& F
我们使用串口中断,先开启串口全局中断,  P; [  `7 y9 s2 N6 P
  L! R1 m2 J5 J* Z
aff30c544ad14d4c9f14cfed35b2ee6b.png 0 |1 J( }; \' p9 W- `; \# m
; Y/ m- q8 M. p- Y3 ?# V) e" J
图20.3.2. 4 开启UART4全局中断% M* P; p, h& S4 c& J
串口中断优先级配置如下:
- }; \, K5 N% J; C. {" e4 ~% u
$ r7 k6 l2 g# g db52ac267c8f49ebb3e187bc94548cae.png 6 B; h: I5 D9 f. E

, b: H* S) v) t3 X: u! Z# U- F图20.3.2. 5 配置UART4中断优先级& J0 _7 d1 z4 k0 W. |" r- `
下面,我们直接配置RNG2:7 t4 ^% ^; `, X/ w, T% ]$ p
(3)配置RNG2
$ G% E6 G5 r- z& Z  c# m6 @$ R如果不知道RNG在哪里,可以直接搜索RNG2:8 I9 h5 T' e  s( a- _
  b" x1 C0 O9 s- }% y3 G# L5 e
e05425cfce294f51905b95680b4fe1ba.png
: a0 \) z+ i% D! o' W5 F" a) C% v6 K" x& R$ T- U1 I$ r1 l) Q
图20.3.2. 6 查找RNG2& R' O, I6 u% P5 U+ @! [
在SecurityRNG2下找到RNG2的配置,按照如下图配置,先勾选Cortex-M4,再选择Activated,即激活随机数发生器。其它配置保持默认,实际上RNG没有其它参数需要配置的。这里,我们不开启时钟错误检测:
" r# x$ \% N; g  c$ a3 u% C3 V! F8 `! h/ V1 p/ R8 r
8dd3bd6af05e4d27a6937c253dc616d1.png
* o( I6 E6 T6 }1 r9 u8 F  [. q
% l+ i& a1 E, i: ]图20.3.2. 7 配置RNG2
( ?5 X. g/ `% p. i0 C( }5 Q& y(4)配置时钟  }6 Y* {8 Z$ {! G
RRNG2时钟默认采用CSI的时钟,其它时钟也可以保持默认配置。这里就保持和前面一样的配置,配置PCLK1最大为104.5MHz:
/ @5 g" m& c4 d  m) h7 G0 C2 E" ?! V/ o
9f8297fe596f4fd78beb8d7e754ed18d.png
: ~/ X. W2 X, `
) y, a6 {( ]/ P. R/ U$ q图20.3.2. 8 配置时钟
$ E7 O, \. {! O9 J% x9 c(5)配置生成独立的.c和.h文件" K; t6 d/ u( u1 d

7 C) B! C7 i1 [, N' ^. y: q 55ab73bf94e04d18957f0d18b8bb892a.png
, M9 M( A- h* N
5 U( b( n; E$ E; ]4 r" q( D图20.3.2. 9配置生成独立的文件
+ c+ S! \! t+ E+ S9 X9 k1 R  F2. 生成工程- M" }9 a( j, o: q4 l
以上的配置检查无误后,按下键盘的“Ctrl+S”组合键保存配置并生成工程。将前面按键实验用到的BSP文件夹拷贝到本工程的Src目录下,只留下按键和LED相关的代码:7 ?: x6 n& E7 @: e# Z( L
* ^- C* s; g0 x/ _" V
88b0fa359fe243bd9466ab8773b12d19.png ; S9 W% M% `) c( C  `
; d8 j/ P) R! x0 H" K
图20.3.2. 10生成工程, Y" O' u9 @* @; `% Q
3. 添加用户代码. @9 g. T" X5 t! d5 m' D
上一步操作中,我们已经将BSP文件夹拷贝到了工程中,因为本节实验只用到LED0和KEY0相关的代码,所以将其它LED1和按键的代码注释掉。当然,也可以在STM32CubeMX上将LED1和其它按键也一起配置了,这样就不需要注释这些代码了,或者也可以自己重新手动编写这部分代码。
' [; [1 t7 _5 b- O3 M! R(1)key.h、key.c、led.c和led.h的代码比较简单,这里就不列出来了,大家可以直接参考本工程中的代码。
8 W, S) Q& t" {& e  a9 u: f& K(2)串口相关的代码可直接参考前面串口通信实验章节部分,这里就不再列出来了。
( {2 c+ F7 R! F: a" K# ~+ t(3)RNG2初始化代码已经在rng.c文件中生成了,代码比较简单,如下:
) g* z2 U% C2 Z7 t8 m9 o% O) @8 h, P
  1. #include "rng.h"
    3 q% y( z7 a& F$ I/ ?2 X+ n. E. E
  2. 4 A, }0 l! e4 y; S" L, a1 p- U
  3. RNG_HandleTypeDef hrng2; /* RNG2句柄 */& t# E4 t! v& F" f% d& i3 q
  4. 2 d( M' l, w. t0 U& o' D
  5. /*** [3 Y0 W% ~1 q' p: @3 S: D
  6. * @brief       RNG底层驱动,初始化RNG2
      E" J0 O" Q4 {  R0 J( x5 j: x, y" V
  7. * @note        此函数会被HAL_RNG_Init()调用
    4 y0 h  j$ p0 a+ u: [( F5 m
  8. * @param       hrng:RNG句柄
    ( g) c! A7 f; S* }
  9. * @retval      无9 w/ S. p6 Z' O$ L; Z
  10. */
    : t3 s, U/ m7 U, ^. f6 n
  11. void MX_RNG2_Init(void)4 P$ X7 k% y; Y' ~- c  W) C
  12. {7 D3 V6 R0 e" Z/ ^; F& T
  13.   hrng2.Instance = RNG2; /* RNG2 *// t! W# d+ x8 o
  14.   hrng2.Init.ClockErrorDetection = RNG_CED_DISABLE; /* 关闭时钟错误检查 */
    * |( F, a5 s% Z
  15.   if (HAL_RNG_Init(&hrng2) != HAL_OK) /* 初始化RNG2 */1 s& q, R; y  m: T
  16.   {
    4 z1 ]9 j. A" `4 Z9 h7 Z( {$ k
  17.     Error_Handler();+ ?# r. S, G' P  h) c4 o, P: e$ ^
  18.   }
    3 g( b/ r6 [3 V& m

  19. & k8 u4 _- P/ q6 ^# ]2 M7 {: `! |
  20. }; N/ h. O* t0 t" |
  21. /**
    ! @6 P, \" k8 U- h" n
  22. * @brief       RNG底层驱动,时钟源设置和使能
    ! U9 s, N% @: R9 s3 p7 v/ g
  23. * @note        此函数会被HAL_RNG_Init()调用7 _7 K' t4 ^' U; Z2 n
  24. * @param       hrng:RNG2句柄  O( @! {# W! d2 ~3 W* f' i
  25. * @retval      无
    2 M3 P2 Z3 U* L: H  W
  26. */
    4 u8 S9 W( J! r5 l
  27. void HAL_RNG_MspInit(RNG_HandleTypeDef* rngHandle)
    3 @& ]3 F6 \, i+ g4 w! [
  28. {
    - a  u% t/ n6 y8 B
  29.   RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};0 z, E5 F. q5 O3 ]2 C  m( \
  30.   if(rngHandle->Instance==RNG2)) ~8 R5 `. E8 A( d& l  V7 ^
  31.   {
    ( ~/ ?' c; h) @! U  W( x7 t
  32.   if(IS_ENGINEERING_BOOT_MODE())
    / Q9 J3 \0 j; E6 S$ E. p
  33.   {
    2 L: e4 Q* x: M+ x( Y+ X
  34.       /* 外设外RNG2 */
    7 d0 {" U* j/ M# K* E# ~9 d7 V
  35.     PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RNG2;
    & }( y0 `3 ?3 m  i( ]  |! C9 P
  36.     /* 时钟源设置为CSI */
    8 h  }1 X; P  ]
  37.     PeriphClkInit.Rng2ClockSelection = RCC_RNG2CLKSOURCE_CSI;
    4 ]6 P$ Q! K" m2 e! q7 S
  38.     /* 初始化RCC扩展外设时钟,也就是RNG2时钟 */3 y0 C2 ]( H6 ?; G! i( b4 j) ~- M# V
  39.     if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)1 e0 ^3 t6 |2 _9 w6 T+ F2 S
  40.     {5 ]( ?- S% ~$ W* D8 h% ~
  41.       Error_Handler();
    9 d# U3 b* w5 |" _9 r; J
  42.     }
    , m- ^* ^; \: p1 w" ?+ v
  43.   }
    ' O4 K9 i4 r( Z* ]5 D
  44.     __HAL_RCC_RNG2_CLK_ENABLE(); /* 使能RNG2时钟 */# w! @: D- T8 b% z
  45.   }- e7 F/ l2 {( Y; b4 j
  46. }5 p: U$ W' `8 J/ D4 I7 u. E
  47. /**
    # {8 [) S9 L" |7 [, C0 ^4 f
  48. * @brief       RNG底层驱动反初始化函数
    ' `4 i, K5 u7 T
  49. * @note        如果需要,可以调用此函数3 `; f  w- Z  @5 Y7 c% b
  50. * @param       hrng:RNG句柄# d! A0 \% T" H) a$ }
  51. * @retval      无: I8 i' m# C0 z  [" H- \  @
  52. */$ D7 P* l, U5 \7 T
  53. void HAL_RNG_MspDeInit(RNG_HandleTypeDef* rngHandle)
    ! e  P9 I4 j! @$ P  P
  54. {/ }4 I4 k( i0 j/ g+ Y' x
  55.   if(rngHandle->Instance==RNG2)1 H; K3 C  |' J( }" d
  56.   {
    6 x  A. f, Z. L" W& w! N- r
  57.     __HAL_RCC_RNG2_CLK_DISABLE();/* 关闭RNG2时钟,即关闭RNG2 */  u) f, @' ~; x6 c+ k8 U6 ~
  58.   }
    % M" s; [0 L. n6 I2 {* O
  59. }
    4 z) ^( Z4 q  `
  60.         (4)手动添加获取随机数的代码3 i+ ^3 u5 k8 C
  61.         在rng.c文件中添加如下代码:" h6 |$ h0 B$ C7 ^
  62. /* USER CODE BEGIN 1 *// S$ I9 i1 t( d
  63. /**; o1 R( _4 ?7 }
  64. * @brief       得到随机数7 z3 }- i" L2 v! J
  65. * @param       无
    " o5 r: Q* J* j2 Q3 T! j/ g: R% @
  66. * @retval      获取到的随机数(32bit)
    9 l& e5 E$ ]; u* }
  67. */. x3 B  v2 ~1 i
  68. uint32_t rng_get_random_num(void)5 q, K3 @/ S' i& m* q9 ?" H. G
  69. {* n/ j4 z: x5 ^/ Y  E  g6 j8 p9 o/ S
  70.     uint32_t randomnum;% c: i; E* s  o3 e
  71.     HAL_RNG_GenerateRandomNumber(&hrng2, &randomnum);: |: ^& d7 X3 z9 o9 q
  72.     return randomnum;- l( U$ [9 f2 t1 d
  73. }$ c# e& @% w* v8 l# F

  74. " p, d2 {( X' m  x& R. V' s+ h
  75. /**5 \( J% m3 R! k* ?
  76. * @brief       得到某个范围内的随机数
    & S7 ]  T5 g1 v  J3 v6 k
  77. * @param       min,max: 最小,最大值.
    - T& B4 C! @- F: G5 F7 a
  78. * @retval      得到的随机数(rval),满足:min<=rval<=max
    3 [7 ^$ L/ B- `6 ?1 M; {
  79. */9 B; K0 c, K( ?; r( Q
  80. int rng_get_random_range(int min, int max)0 h9 {# Q% G! A( L% j% s! \
  81. {5 y8 i! X) ?- C" r9 l* |1 n' q
  82.     uint32_t randomnum;# L+ w3 B3 p9 Q  j' s; [& }
  83.     HAL_RNG_GenerateRandomNumber(&hrng2, &randomnum);  d# z% p, C. v, s, ^) \8 M
  84.     return randomnum%(max-min+1) + min;4 j& X  q) d% b$ @
  85. }% C5 E/ C5 H) X- h
  86. /* USER CODE END 1 */
复制代码
7 L" @9 ~, h  h' p8 c
以上代码比较简单,主要是通过HAL库中的HAL_RNG_GenerateRandomNumber函数获取随机数。rng_get_random_num函数主要是获取随机数,rng_get_random_range主要是返回某个范围内的随机数。. S+ N# R3 P4 f7 p+ M, Z3 V
(5)修改main.c文件
7 y: X" p% A6 e1 ]% U3 u; v, e1 S4 K3 p  G
  1. #include "main.h"
    9 ]0 P4 U: q+ Y' @
  2. #include "rng.h"
    $ Y( n3 ]$ O# u( e. `) y
  3. #include "usart.h"
    ; D' r8 i2 y# v% A6 e. l. @
  4. #include "gpio.h"
    6 @& O* Q8 ?; j7 h8 _
  5. ) x7 R7 d9 S. T9 V9 Z3 X6 }3 t
  6. /* USER CODE BEGIN Includes */
    " {2 P5 P! b& {  S. R
  7. #include "./BSP/Include/led.h"! ?; J  d' p5 }" a* a, H
  8. #include "./BSP/Include/key.h"
    * b' m& M" ~  V3 C8 m
  9. /* USER CODE END Includes */+ H2 m# Z1 L1 h
  10. % P/ c+ f" q( e+ {4 u7 G
  11. void SystemClock_Config(void);
    & I# }" b6 D: ~1 O
  12. / D( i* {( x9 O. y% x- L8 _0 L
  13. int main(void)0 C  U, ^  X8 ?8 b" b/ O
  14. {- k$ b4 D: P+ M( a
  15.   HAL_Init();
    # ]- l: }2 Z$ U0 N% h$ ]: Y
  16.   if(IS_ENGINEERING_BOOT_MODE())9 e" E1 x: i7 v" }# P
  17.   {
    9 r1 s& n3 \$ {  H- l$ R2 A
  18.     SystemClock_Config();' \. r" e8 X2 i7 i9 f% ]5 v
  19.   }
      S9 `8 M. ]4 a
  20.   MX_GPIO_Init();
    ! H) T3 w/ l  {. I- {
  21.   MX_RNG2_Init();
    / l6 ?0 W( n. h3 S( H5 x/ ~
  22.   MX_UART4_Init();( Z1 r5 ^4 o3 w) C6 }  S: T8 Y
  23.   /* USER CODE BEGIN 2 */+ R) m! j2 e  x( ~
  24.   /* printf("请输入字符,并按下回车键结束\r\n"); */" c: ?; B  [6 x
  25.       HAL_UART_Receive_IT(&huart4,&RxBuffer,1);/* 以中断方式接收函数 */( ~; K: q4 ?+ |( T2 ^
  26.   /* USER CODE END 2 */' t/ j3 w8 E9 l' k$ L
  27.   while (1)5 m: i. Z* ^, ]7 ?
  28.   {
    4 m; t6 g- q+ V" i# {& b5 V7 Q
  29.     /* USER CODE BEGIN 3 */+ [- v+ P0 a4 F/ ~
  30.       uint32_t random;% j' z3 ^, G$ R' L# \% n. H: L
  31.       uint8_t t = 0, key;
    $ L+ Z4 J% V* S4 _- Y
  32.       key = key_scan(0);! r8 b6 p; ~) R% l6 Y
  33.       if (key == KEY0_PRES)
    ! C' M4 }+ n4 U% S# e
  34.           {
    0 e, ?4 @9 {1 p$ J. ~
  35.              random = rng_get_random_num();
      ]2 r$ U  G7 T: E2 a/ q1 c! }
  36.              printf("Random Num:%lu\r\n", random);' ?2 W$ k2 }- j* |. J
  37.            }; [# _* [9 x3 |4 p- L/ w1 O
  38.        if ((t % 20) == 0)
    , L! M- ]" W# q; m" l
  39.            {6 x+ j, P# o2 ?( ]  p7 u7 ~
  40.              t = 0;' }( }* ?9 S* _% M4 {  k- G# S9 j
  41.              LED0_TOGGLE();                    /* 每200ms,翻转一次LED0 */
    " G& X) R+ |( J: v1 D
  42.              random = rng_get_random_range(0, 9);/* 取[0,9]区间的随机数 */( {! [8 Y, ]/ y$ P7 N$ A: P0 S
  43.              printf("Random Num[0-9]:%lu\r\n", random);
    5 u1 E& j8 t3 F1 l. L
  44.             }
    . ?' ?& B; u' {
  45.               HAL_Delay(10);
    9 k% @) c. ?) p3 V- W
  46.               t++;
    * U( o; Z" D  Y4 b" w/ }; W1 d
  47.   }
    7 h4 v/ s; x- [& ^2 d0 j( a+ C
  48.   /* USER CODE END 3 */
    % U/ B/ \! y3 D' P
  49. }
复制代码
7 ^3 ^' f- k0 o4 P
以上代码中,每隔200ms会自动打印一次[0,9]区间的随机数,同时LED0会翻转一次。如果有按键按下,那么串口就会打印获取到的随机数。
# x, O# k' `! p) `4 D! K, Q7 M& y
20.4 编译和测试
; S3 @3 @/ S/ z' J4 m. w6 O4 {编译无报错,测试结果如下:
, U# w" k# D% ]" s& c) Z! C4 F) P
96b8c0d3c0f34914bc71d09b3936bfb2.png
# b4 U4 s! i& r6 w1 x) t& q* y1 }) J4 f
图20.4. 1测试结果) q$ j% J( L2 {
————————————————* ]/ Z5 H. \/ w* x
版权声明:正点原子+ c: V0 d! ~. n# a  H" ^1 L
( U0 }9 S) B+ _+ S0 j

! G* U) p1 L: [/ o$ }
赞 收藏 评论0 发布时间:2022-9-28 18:51

举报

0个回答

所属标签

相似技术帖

官网相关资源

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