一、RNG简介
二、RNG框图介绍
三、RNG相关寄存器介绍
四、RNG相关HAL库驱动介绍
五、RNG基本驱动步骤
六、编程实战
七、总结
一、RNG简介

随机数发生器(RNG)在计算机科学和密码学中具有广泛的应用场景,包括但不限于以下几个方面:
-
验证码:在网络安全和用户验证中,随机数用于生成验证码,增加系统的安全性,防止机器人攻击和恶意访问。
-
密码学:随机数在密码学中扮演着重要角色,用于生成密钥、初始化向量(IV)和盐等,增加加密算法的安全性。
-
概率学和统计学:随机数被用于模拟概率分布和随机变量,进行蒙特卡罗模拟、蒙特卡罗积分等,用于解决统计学和概率学中的问题。
-
游戏:在游戏开发中,随机数被广泛用于生成游戏中的随机事件、随机地图、随机怪物属性等,增加游戏的趣味性和挑战性。
随机数的重要特性是无法预测的、无规律性的、独立分布的。真随机数由物理过程生成,具有完全随机的性质,而伪随机数则是通过确定性算法计算出来的,虽然看起来像是随机的,但是在一定条件下可能会被预测到。在安全性要求较高的场景中,通常会使用真随机数发生器。
二、RNG框图介绍

RNG(Random Number Generator)采用模拟电路实现,其基本原理如下:
-
模拟电路结构:RNG通常由几个环形振荡器组成。这些振荡器的输出经过异或运算,产生种子(seed),作为随机数生成的初始值。
-
LFSR(线性反馈移位寄存器):LFSR类似于一个“生产车间”,接收大量的种子输入。种子通过LFSR处理后,其内容传送到RNG数据寄存器(RNG_DR),用于随机数的生成。
-
时钟检查器和故障检测器:类似于“质检”,时钟检查器和故障检测器负责检测种子是否出现异常序列以及fpll48clk是否过低。这些异常情况会在RNG_SR寄存器的相关位显示,并可以触发中断。
-
中断功能:RNG通常设置了中断功能,当种子出现异常序列或fpll48clk过低时,会产生中断信号,以便系统进行相应的处理或响应。
总体而言,RNG通过模拟电路实现,利用环形振荡器、LFSR和时钟检查器等组件,生成随机数种子,并在检测到异常情况时产生中断,确保随机数生成的安全性和可靠性。
三、RNG相关寄存器介绍

这是RNG模块的关键寄存器及其作用:
-
RNG_CR(RNG控制寄存器):
- 用途:控制随机数发生器的启用和中断的使能。
- 作用:通过设置该寄存器的位来启用或禁用随机数发生器,并控制中断功能的使能。
-
RNG_SR(RNG状态寄存器):
- 用途:显示RNG当前的一些状态信息。
- 作用:该寄存器的特定位用于显示RNG模块的状态,例如随机数生成完成、时钟故障等。
-
RNG_DR(RNG数据寄存器):
- 用途:存储生成的32位随机数值。
- 作用:随机数生成器生成的随机数会被存储在该寄存器中,供后续程序使用。



四、RNG相关HAL库驱动介绍

这是与RNG模块相关的驱动函数及其功能描述以及关联的寄存器:
-
HAL_RNG_Init(…):
- 关联寄存器:RNG_CR
- 功能描述:用于初始化RNG模块,配置RNG控制寄存器,启用或禁用随机数发生器以及中断。
-
HAL_RNG_MspInit(…):
- 初始化回调
- 功能描述:在初始化过程中调用,用于初始化RNG模块的外设、时钟和选择时钟源等。
-
HAL_RCCEx_PeriphCLKConfig(…):
- 关联寄存器:RCC_BDCR
- 功能描述:设置RNG模块的时钟源,通常设置为PLL。
-
HAL_RNG_GenerateRandomNumber(…):
- 关联寄存器:RNG_DR
- 功能描述:用于生成随机数,会检查DRDY位以确定是否有随机数可用,并读取随机数。
-
__HAL_RCC_RNG_CLK_ENABLE(…):
- 关联寄存器:AHB2ENR
- 功能描述:使能RNG模块的时钟,确保RNG模块能够正常工作。
-
__HAL_RNG_GET_FLAG(…):
- 关联寄存器:RNG_SR
- 功能描述:用于获取RNG模块相关的标记,例如随机数生成完成标志位等。
五、RNG基本驱动步骤

RNG基本驱动步骤:
-
使能RNG时钟:
- 使用
__HAL_RCC_RNG_CLK_ENABLE()函数来启用RNG模块的时钟。
- 使用
-
初始化随机数发生器:
- 使用
HAL_RNG_Init()函数初始化RNG模块,配置RNG控制寄存器等。 - 在初始化过程中,需要调用
HAL_RNG_MspInit()函数来初始化RNG模块的外设、时钟以及选择时钟源等设置,可能需要使用HAL_RCCEx_PeriphCLKConfig()函数来配置RNG模块的时钟源。
- 使用
-
读取随机数值:
- 使用
HAL_RNG_GenerateRandomNumber()函数来生成随机数。 - 在生成随机数之前,通常会判断 DRDY 位,以确保随机数已经就绪可以读取。
- 使用
六、编程实战

按键输入
rng.c
#include "./BSP/RNG/rng.h"
#include "./SYSTEM/delay/delay.h"
RNG_HandleTypeDef g_rng_handle; /* RNG控制句柄 */
/**
* @brief 初始化RNG模块
* @retval 返回值:0成功,1失败
*/
uint8_t rng_init(void)
{
uint16_t retry = 0; /* 重试计数器 */
g_rng_handle.Instance = RNG; /* RNG实例 */
HAL_RNG_Init(&g_rng_handle); /* 初始化RNG模块 */
/* 等待RNG准备就绪 */
while ((__HAL_RNG_GET_FLAG(&g_rng_handle, RNG_FLAG_DRDY) == RESET) && (retry < 10000))
{
retry++;
delay_us(10); /* 延时等待 */
}
/* 检查RNG是否正常工作 */
if (retry >= 10000)
{
return 1; /* 随机数产生器工作不正常 */
}
return 0; /* 初始化成功 */
}
/**
* @brief 初始化RNG模块的外设、时钟并选择时钟源
* @param hrng: RNG句柄
*/
void HAL_RNG_MspInit(RNG_HandleTypeDef *hrng)
{
RCC_PeriphCLKInitTypeDef rcc_periphclk_init_struct; /* 外设时钟初始化结构体 */
/* RNG时钟使能 */
__HAL_RCC_RNG_CLK_ENABLE();
/* 配置RNG时钟源为PLL */
rcc_periphclk_init_struct.PeriphClockSelection = RCC_PERIPHCLK_RNG;
rcc_periphclk_init_struct.RngClockSelection = RCC_RNGCLKSOURCE_PLL;
HAL_RCCEx_PeriphCLKConfig(&rcc_periphclk_init_struct);
}
/**
* @brief 获取随机数
* @retval 返回32位随机数
*/
uint32_t rng_get_random_num(void)
{
uint32_t random_num = 0; /* 随机数变量 */
HAL_RNG_GenerateRandomNumber(&g_rng_handle, &random_num); /* 生成随机数 */
return random_num; /* 返回随机数 */
}
/**
* @brief 获取指定范围内的随机数
* @param min: 最小值
* @param max: 最大值
* @retval 返回在[min, max]范围内的随机数
*/
uint32_t rng_get_random_range(int min, int max)
{
uint32_t random_num = 0; /* 随机数变量 */
HAL_RNG_GenerateRandomNumber(&g_rng_handle, &random_num); /* 生成随机数 */
return random_num % (max - min + 1) + min; /* 返回指定范围内的随机数 */
}
rng.h
#ifndef __RNG_H
#define __RNG_H
#include "./SYSTEM/sys/sys.h"
uint8_t rng_init(void); // 初始化RNG模块的外设、时钟并选择时钟源
uint32_t rng_get_random_num(void); // 获取随机数
uint32_t rng_get_random_range(int min, int max); // 获取指定范围内的随机数
#endif
main.c
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/KEY/key.h"
#include "./BSP/RNG/rng.h"
int main(void)
{
uint8_t key;
uint32_t value = 0;
uint32_t value_range = 0;
sys_cache_enable(); /* 打开L1-Cache */
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(240, 2, 2, 4); /* 设置时钟, 480Mhz */
delay_init(480); /* 延时初始化 */
usart_init(115200); /* 初始化串口 */
led_init(); /* 初始化LED */
key_init(); /* 初始化按键 */
LED0(0); /* 先点亮LED0 */
rng_init(); /* RNG初始化 */
while (1)
{
key = key_scan(0); /* 得到键值 */
if (key)
{
switch (key)
{
case WKUP_PRES: /* 控制LED0(RED)翻转 */
value = rng_get_random_num();
printf("value:%d \r\n", value);
LED0_TOGGLE(); /* LED0状态取反 */
break;
case KEY1_PRES: /* 控制LED1(GREEN)翻转 */
value_range = rng_get_random_range(0, 9);
printf("value_range:%d \r\n", value_range);
LED1_TOGGLE(); /* LED1状态取反 */
break;
case KEY0_PRES: /* 控制LED2(BLUE)翻转 */
LED2_TOGGLE(); /* LED2状态取反 */
break;
}
}
else
{
delay_ms(10);
}
}
}


源码
rng.c
#include "./BSP/RNG/rng.h" // 引入RNG头文件
#include "./SYSTEM/delay/delay.h" // 引入延时函数头文件
RNG_HandleTypeDef rng_handle; // 声明RNG句柄变量
/**
* @brief 初始化RNG
* @param 无
* @retval 0,成功;1,失败
*/
uint8_t rng_init(void)
{
uint16_t retry = 0;
rng_handle.Instance = RNG; // 设置RNG句柄的实例
HAL_RNG_DeInit(&rng_handle); // 重新初始化RNG
HAL_RNG_Init(&rng_handle); // 初始化RNG
// 等待RNG准备就绪
while ((__HAL_RNG_GET_FLAG(&rng_handle, RNG_FLAG_DRDY) == RESET) && (retry < 10000))
{
retry++; // 尝试次数加1
delay_us(10); // 延时10微秒
}
if (retry >= 10000)
{
return 1; // 随机数产生器工作不正常,返回1
}
return 0; // 返回0表示初始化成功
}
/**
* @brief RNG底层驱动,时钟源设置和使能
* @note 此函数会被HAL_RNG_Init()调用
* @param hrng:RNG句柄
* @retval 无
*/
void HAL_RNG_MspInit(RNG_HandleTypeDef *hrng)
{
RCC_PeriphCLKInitTypeDef RNGClkInitStruct;
// 设置RNG时钟源,选择PLL,时钟为480MHz
RNGClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RNG; // 设置RNG时钟源为PLL
RNGClkInitStruct.RngClockSelection = RCC_RNGCLKSOURCE_PLL; // RNG时钟源选择PLL
HAL_RCCEx_PeriphCLKConfig(&RNGClkInitStruct); // 配置RNG时钟源
__HAL_RCC_RNG_CLK_ENABLE(); // 使能RNG时钟
}
/**
* @brief 得到随机数
* @param 无
* @retval 获取到的随机数(32bit)
*/
uint32_t rng_get_random_num(void)
{
uint32_t randomnum;
HAL_RNG_GenerateRandomNumber(&rng_handle, &randomnum); // 生成随机数
return randomnum; // 返回随机数
}
/**
* @brief 得到某个范围内的随机数
* @param min,max: 最小,最大值.
* @retval 得到的随机数(rval),满足:min<=rval<=max
*/
int rng_get_random_range(int min, int max)
{
uint32_t randomnum;
HAL_RNG_GenerateRandomNumber(&rng_handle, &randomnum); // 生成随机数
return randomnum % (max - min + 1) + min; // 返回在[min, max]范围内的随机数
}
rng.h
#ifndef __RNG_H
#define __RNG_H
#include "./SYSTEM/sys/sys.h"
uint8_t rng_init(void); /* RNG初始化 */
uint32_t rng_get_random_num(void); /* 得到随机数 */
int rng_get_random_range(int min,int max); /* 得到属于某个范围内的随机数 */
#endif
main.c
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./USMART/usmart.h"
#include "./BSP/MPU/mpu.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./BSP/RNG/rng.h"
int main(void)
{
uint32_t random; // 存储随机数的变量
uint8_t t = 0, key; // t用于定时计数,key存储按键状态
sys_cache_enable(); // 打开L1-Cache
HAL_Init(); // 初始化HAL库
sys_stm32_clock_init(240, 2, 2, 4); // 设置时钟, 480Mhz
delay_init(480); // 延时初始化
usart_init(115200); // 串口初始化为115200
usmart_dev.init(240); // 初始化USMART
mpu_memory_protection(); // 保护相关存储区域
led_init(); // 初始化LED
lcd_init(); // 初始化LCD
key_init(); // 初始化按键
// 在LCD上显示欢迎信息
lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);
lcd_show_string(30, 70, 200, 16, 16, "RNG TEST", RED);
lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
// 初始化随机数发生器
while (rng_init())
{
lcd_show_string(30, 110, 200, 16, 16, " RNG Error! ", RED);
delay_ms(200);
lcd_show_string(30, 110, 200, 16, 16, "RNG Trying...", RED);
}
lcd_show_string(30, 110, 200, 16, 16, "RNG Ready! ", RED);
lcd_show_string(30, 130, 200, 16, 16, "KEY0:Get Random Num", RED);
lcd_show_string(30, 150, 200, 16, 16, "Random Num:", RED);
lcd_show_string(30, 180, 200, 16, 16, "Random Num[0-9]:", RED);
while (1)
{
key = key_scan(0); // 检测按键状态
// 如果按键KEY0被按下,获取一个随机数并在LCD上显示
if (key == KEY0_PRES)
{
random = rng_get_random_num();
lcd_show_num(30 + 8 * 11, 150, random, 10, 16, BLUE);
}
// 每200ms翻转一次LED0,并显示[0,9]范围内的随机数
if ((t % 20) == 0)
{
LED0_TOGGLE(); // 每200ms,翻转一次LED0
random = rng_get_random_range(0, 9); // 获取[0,9]范围内的随机数
lcd_show_num(30 + 8 * 16, 180, random, 1, 16, BLUE); // 在LCD上显示随机数
}
delay_ms(10); // 延时10ms
t++; // 定时计数器递增
}
}
七、总结


&spm=1001.2101.3001.5002&articleId=136379053&d=1&t=3&u=5182bfd953224077ba5548f666f3506a)
1543

被折叠的 条评论
为什么被折叠?



