OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 34|回复: 0

《STM32H7R7开发指南 V1.1 》第三十章 随机数发生器实验

[复制链接]

1316

主题

1332

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
5627
金钱
5627
注册时间
2019-5-8
在线时间
1502 小时
发表于 8 小时前 | 显示全部楼层 |阅读模式
本帖最后由 正点原子运营 于 2026-4-24 09:50 编辑

第三十章 随机数发生器实验

1)实验平台:正点原子STM32H7R7开发板

2)章节摘自【正点原子】STM32H7R7开发指南 V1.1

3)购买链接: https://detail.tmall.com/item.htm?id=820823382459

4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/stm32/zdyz_stm32h7rx.html

5)正点原子官方B站:https://space.bilibili.com/394620890

6)正点原子STM32开发板技术交流群:756580169


2.jpg

3.png

本章,我们将介绍STM32H7R7的硬件随机数发生器。我们使用KEY0按键来获取硬件随机数,并且将获取到的随机数值显示在LCD上面。同时,使用LED0指示程序运行状态。
本章分为如下几个小节:
30.1 随机数发生器简介
30.2 硬件设计
30.3 程序设计
30.4 下载验证


30.1 随机数发生器简介
STM32H7R7自带了硬件随机数发生器(RNG),RNG处理器是一个以连续模拟噪声为基础的随机数发生器,在主机读数时提供一个32位的随机数。

30.1.1 RNG框图
下面先来学习RNG框图,通过学习RNG框图会有一个很好的整体掌握,同时对之后的编程也会有一个清晰的思路。STM32H7R7的随机数发生器框图如图30.1.1.1所示:

第三十章 随机数发生器实验341.png
图30.1.1.1 随机数发生器(RNG)框图

随机数发生器有2个时钟域:AHB时钟域和RNG时钟域。AHB时钟域的时钟来自AHB2,用于访问相关寄存器等,通过AHB2ENR的RNGEN位(bit6)使能。
RNG时钟域时钟为rng_clk,rng_clk由D2CCIP2R寄存器的RNGSEL[1:0]位选择具体的时钟源,具体选择关系为:0,hsi8_ck;1,pll1_q_ck;2,lse_ck;3,lsi_ck。我们一般选择pll1_q_ck作为rng_clk的时钟源(实验中调用sys_stm32_clock_init函数时设置了pll1_q_ck为300MHZ),因此设置RNGSEL[1:0]=1即可。AHB2ENR和D2CCIP2R这两个寄存器我们就不做介绍了,大家参考手册。
从RNG框图整体上知道,RNG有两个输入和一个输出。具体如下表:


1.png
表30.1.1.1 RNG内部输入/输出信号

STM32H7R7的随机数发生器(RNG)采用模拟电路实现,由内部两个模拟噪声源产生种子,经过采样和归一化处理,再经过线性移位寄存器和判断逻辑,最终输出到RNG_DR,生成32 位随机数。
每个模拟噪声源由3个环形振荡器组成,振荡器产生的输出经过异或运算产生种子,经过采样归一化处理后,输出到RNG内部的线性移位寄存器。采样频率由rng_clk时钟提供,因此,随机数质量与 HCLK 频率无关。当将大量种子引入线性移位寄存器后,经过判断逻辑,最终输出到数据寄存器 (RNG_DR)。
同时,系统会监视模拟种子和专用时钟 rng_clk,当种子上出现异常序列,或rng_clk时钟频率过低时,可以由RNG_SR寄存器的对应位读取到,如果设置了中断,则在检测到错误时,还可以产生中断。


30.1.2 RNG寄存器
RNG控制寄存器(RNG_CR)
RNG控制寄存器描述如图30.1.2.1所示:


第三十章 随机数发生器实验1332.png
图30.1.2.1 RNG_CR寄存器

该寄存器我们只关心RNGEN位,该位用于使能随机数发生器,所以必须设置为1。
RNG状态寄存器(RNG_SR)
RNG状态寄存器描述如图30.1.2.2所示:


第三十章 随机数发生器实验1434.png
图30.1.2.2 RNG_SR寄存器

该寄存器我们仅关心最低位(DRDY位),该位用于表示RNG_DR寄存器包含的随机数数据是否有效,如果该位为1,则说明RNG_DR的数据是有效的,可以读取出来了。读RNG_DR后,该位自动清零。
RNG数据寄存器(RNG_DR)
RNG数据寄存器描述如图30.1.2.3所示:


第三十章 随机数发生器实验1594.png
图30.1.2.3 RNG_DR寄存器

RNG_DR寄存器是只读寄存器,我们可以读取该寄存器获得32位随机数值。此寄存器在最多216个AHB时钟周期后,又可以提供新的随机数值。

30.2 硬件设计

1. 例程功能
本实验使用STM32H7R7自带的硬件随机数生成器(RNG),获取随机数,并显示在LCD屏幕上。按KEY0可以获取一次随机数。同时程序自动获取0~9范围内的随机数,显示在屏幕上。LED0闪烁用于提示程序正在运行。

2. 硬件资源
1)LED灯
       LED: LED0 – PD14
2)独立按键  KEY0 – PE9
3)串口1(PB14/PB15连接在板载USB转串口芯片CH340上面)
2)正点原子2.8/3.5/4.3/7/10寸TFTLCD模块(包括MCU屏和RGB屏,都支持)
3)RNG(硬件随机数生成器)

3. 原理图
RNG属于STM32H7R7内部资源,通过软件设置好就可以了。本实验通过配合按键获取随机数和通过LCD显示。


30.3 程序设计

30.3.1 RNG的HAL库驱动
RNG在HAL库中的驱动代码在stm32h7rsxx_hal_rng.c文件(及其头文件)中。
1. HAL_RNG_Init函数
RNG的初始化函数,其声明如下:
  1. HAL_StatusTypeDef HAL_RNG_Init(RNG_HandleTypeDef *hrng);
复制代码
函数描述:
用于初始化RNG。
函数形参:
形参1是RNG_HandleTypeDef结构体类型指针变量,其定义如下:

  1. typedef struct
  2. {
  3.   RNG_TypeDef                                 *Instance;            /* RNG基地址 */
  4.   RNG_InitTypeDef                       Init;                 /* RNG初始化配置结构体 */
  5.   HAL_LockTypeDef                       Lock;                 /* RNG锁设置 */
  6.   __IO HAL_RNG_StateTypeDef               State;                /* RNG设备访问状态 */
  7.   __IO  uint32_t                        ErrorCode;            /* RNG错误代码 */
  8.   uint32_t                              RandomNumber;         /* RNG最后生成的随机数 */
  9. } RNG_HandleTypeDef;
复制代码
1)Instance:指向RNG寄存器基地址。
2)Init:是的RNG初始化结构体,其结构体类型RTC_InitTypeDef定义如下:

  1. typedef struct
  2. {
  3.   uint32_t            ClockErrorDetection;                 /* CED时钟错误检测 */
  4. } RNG_InitTypeDef;
复制代码
3)Lock:用于配置锁状态。
4)State:RNG设备访问状态。
5)ErrorCode :RNG错误代码
6)RandomNumber :该变量存储RNG最后生成的随机数
函数返回值:
HAL_StatusTypeDef枚举类型的值。

2. HAL_RNG_GenerateRandomNumber函数
HAL_RNG_GenerateRandomNumber是RNG生成随机数函数。其声明如下:

  1. HAL_StatusTypeDef HAL_RNG_GenerateRandomNumber(RNG_HandleTypeDef *hrng,
  2. uint32_t *random32bit);
复制代码
函数描述:
该函数用于RNG生成随机数。
函数形参:
形参1是RNG_HandleTypeDef结构体类型指针变量,即RNG的句柄。
形参2是uint32_t类型指针变量,随机32位指针,生成随机变量。
函数返回值:
HAL_StatusTypeDef枚举类型的值。  

RNG配置步骤
1)使能随机数发生器时钟
调用__HAL_RCC_RNG_CLK_ENABLE函数使能随机数发生器时钟,实际是通过设置AHB2ENR寄存器的相关位。
2)初始化(使能)随机数发生器
通过调用HAL_RNG_Init函数初始化随机数发生器,然后自行调用RNG的MSP回调函数,并使能随机数发生器。
当我们使用HAL_RNG_Init之后,在该函数内部,会调用RNG的MSP回调函数。回调函数中一般编写与MCU相关的外设时钟初始化以及NVIC配置。
3)判断DRDY位,读取随机数值
经过前面两个步骤,我们就可以读取随机数值了,不过每次读取之前,必须先判断RNG_SR寄存器的DRDY位,如果该位为1,则可以读取RNG_DR得到随机数值,如果不为1,则需要等待。 在HAL库中,通过调用HAL_RNG_GenerateRandomNumber函数判断DRDY位并读取随机数值。
通过以上3个步骤的设置,我们就可以使用STM32H7R7的随机数发生器(RNG)了。


30.3.2 程序解析
1. RNG驱动代码
这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。RNG驱动源码包括两个文件:rng.c和rng.h。
rng.h头文件只有函数的声明,下面我们直接介绍rng.c的程序,先看RNG的初始化函数,其定义如下:

  1. /**
  2. * @brief   初始化随机数发生器
  3. * [url=home.php?mod=space&uid=271674]@param[/url]   无
  4. * @retval  初始化结果
  5. * @arg     0: 初始化成功
  6. * @arg     1: 初始化失败
  7. */
  8. uint8_t rng_init(void)
  9. {
  10.     g_rng_handle.Instance = RNG;
  11.    
  12.     if (HAL_RNG_DeInit(&g_rng_handle) != HAL_OK)
  13.     {
  14.         return 1;
  15.     }
  16.    
  17.     if (HAL_RNG_Init(&g_rng_handle) != HAL_OK)
  18.     {
  19.         return 1;
  20.     }
  21.    
  22.     return 0;
  23. }
复制代码
rng_init函数中调用HAL_RNG_Init函数初始化RNG,然后等待RNG初始化完成,同时判断初始化过程是否超时。
我们用HAL_RTC_MspInit回调函数来编写RNG时钟配置等代码,其定义如下:

  1. /**
  2. * @brief   HAL库RNG初始化MSP函数
  3. * @param   无
  4. * @retval  无
  5. */
  6. void HAL_RNG_MspInit(RNG_HandleTypeDef *hrng)
  7. {
  8.     if (hrng->Instance == RNG)
  9.     {        
  10.         /* 使能时钟 */
  11.         __HAL_RCC_RNG_CLK_ENABLE();
  12.     }
  13. }
复制代码
最后两个是我们获取随机数函数,它们的定义如下:
  1. /**
  2. * @brief   获取随机数
  3. * @param   无
  4. * @retval  随机数
  5. */
  6. uint32_t rng_get_random(void)
  7. {
  8.     uint32_t random;
  9.    
  10.     if (HAL_RNG_GenerateRandomNumber(&g_rng_handle, &random) != HAL_OK)
  11.     {
  12.         return 0;
  13.     }
  14.    
  15.     return random;
  16. }

  17. /**
  18. * @brief   获取指定范围的随机数
  19. * @param   min: 指定范围的最小值
  20. * @param   max: 指定范围的最大值
  21. * @retval  随机数
  22. */
  23. int32_t rng_get_random_range(int32_t min, int32_t max)
  24. {
  25.     uint32_t random;
  26.    
  27.     if (HAL_RNG_GenerateRandomNumber(&g_rng_handle, &random) != HAL_OK)
  28.     {
  29.         return 0;
  30.     }
  31.    
  32.     return ((int32_t)random % (max - min + 1) + min);
  33. }
复制代码
其中rng_get_random用于读取随机数值,而rng_get_random_range用于读取一个特定范围内的随机数,实际上它们都是通过调用的函数HAL_RNG_GenerateRandomNumber来实现的。

2. main.c代码
在main.c里面编写如下代码:

  1. int main(void)
  2. {
  3.     uint8_t t = 0;
  4. uint8_t key;
  5. uint32_t random;
  6. int32_t random_range;

  7.     sys_mpu_config();                   /* 配置MPU */
  8.     sys_cache_enable();                 /* 使能Cache */
  9.     HAL_Init();                         /* 初始化HAL库 */
  10.     sys_stm32_clock_init(300, 6, 2);    /* 配置时钟,600MHz */
  11.     delay_init(600);                    /* 初始化延时 */
  12.     usart_init(115200);                 /* 初始化串口 */
  13.     led_init();                         /* 初始化LED */
  14.     key_init();                         /* 初始化按键 */
  15.     hyperram_init();                    /* 初始化HyperRAM */
  16.     lcd_init();                         /* 初始化LCD */
  17.     rng_init();                         /* 初始化随机数发生器 */

  18.     lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);
  19.     lcd_show_string(30, 70, 200, 16, 16, "RNG TEST", RED);
  20.     lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);

  21.     lcd_show_string(30, 130, 200, 16, 16, "KEY0:Get Random Num", RED);
  22.     lcd_show_string(30, 150, 200, 16, 16, "Random Num:", RED);
  23.     lcd_show_string(30, 180, 200, 16, 16, "Random Num[0-9]:", RED);

  24.     while (1)
  25.     {
  26.         key = key_scan(0);
  27.         if (key == KEY0_PRES)
  28.         {
  29.             random = rng_get_random();
  30.             lcd_show_num(30 + 8 * 11, 150, random, 10, 16, BLUE);
  31.         }
  32.         if (++t == 20)
  33.         {
  34.                         t = 0;
  35.             LED0_TOGGLE();                       /* 每200ms,翻转一次LED0 */
  36.             random_range = rng_get_random_range(0, 9); /* 取[0,9]区间的随机数 */
  37.             lcd_show_num(30 + 8 * 16, 170, random_range, 1, 16, BLUE);
  38.         }
  39.         delay_ms(10);
  40.     }
  41. }
复制代码
该部分代码也比较简单,在所有外设初始化成功后,进入死循环,等待按键按下,如果KEY0按下,则调用rng_get_random函数,读取随机数值,并将读到的随机数显示在LCD上面。每隔200ms获取一次区间[0,9]的随机数,并实时显示在液晶上。同时LED0,周期性闪烁,400ms闪烁一次。  

30.4 下载验证
将程序下载到开发板后,可以看到LED0不停的闪烁,提示程序已经在运行了。然后我们按下KEY0,就可以在屏幕上看到获取到的随机数。同时,就算不按KEY0,程序也会自动的获取0~9区间的随机数显示在LCD上面。实验结果如图30.4.1所示:

第三十章 随机数发生器实验7122.png
图30.4.1 获取随机数成功
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /1 下一条

正点原子公众号

如发现本坛存在违规或侵权内容, 请点击这里发送邮件举报 (或致电020-38271790)。请提供侵权说明和联系方式。我们将及时审核依法处理,感谢配合。

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2026-4-24 18:14

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表