53. 硬件随机数

一、随机数发生器简介

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

随机数发生器框图

  STM32F407 的随机数发生器(RNG)采用模拟电路实现。此电路产生馈入线性反馈移位寄存器(RNG_LFSR)的种子,用于生成 32 位随机数。

  该模拟电路由几个环形振荡器组成,振荡器的输出进行异或运算以产生种子。RNG_LFSR 由专用时钟(PLL48CLK)按恒定频率提供时钟信息,因此随机数质量与 HCLK 频率无关。当将大量种子引入 RNG_LFSR 后,RNG_LFSR 的内容会传入数据寄存器(RNG_DR)。

  同时,系统会监视模拟种子和专用时钟 rng_clk,当种子上出现异常序列,或 rng_clk 时钟频率过低时,可以由 RNG_SR 寄存器的对应位读取到,如果设置了中断,则在检测到错误时,还可以产生中断。

二、RNG寄存器

2.1、RNG控制寄存器

RNG控制寄存器

  该寄存器我们需要关注 RNGEN 位,该位用于使能随机数发生器,所以必须设置为 1。

2.2、RNG状态寄存器

RNG状态寄存器

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

2.3、RNG数据寄存器

RNG数据寄存器

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

三、RNG配置步骤

3.1、使能随机数发生器时钟

#define __HAL_RCC_RNG_CLK_ENABLE()    do { \
                                        __IO uint32_t tmpreg = 0x00U; \
                                        SET_BIT(RCC->AHB2ENR, RCC_AHB2ENR_RNGEN);\
                                        /* Delay after an RCC peripheral clock enabling */ \
                                        tmpreg = READ_BIT(RCC->AHB2ENR, RCC_AHB2ENR_RNGEN);\
                                        UNUSED(tmpreg); \
                                      } while(0U)

3.2、初始化随机数发生器

HAL_StatusTypeDef HAL_RNG_Init(RNG_HandleTypeDef *hrng)

  形参 hrngRNG_HandleTypeDef 结构体类型指针变量,其定义如下:

typedef struct
{
    RNG_TypeDef *Instance;                      // RNG基地址
    HAL_LockTypeDef Lock;                       // RNG锁设置
    __IO HAL_RNG_StateTypeDef State;            // RNG设备访问状态
    __IO  uint32_t ErrorCode;                   // RNG错误代码
    uint32_t RandomNumber;                      // RNG最后生成的随机数
} RNG_HandleTypeDef;

  Instance指向 RNG 寄存器基地址

#define RNG                 ((RNG_TypeDef *) RNG_BASE)

  该函数的返回值是 HAL_StatusTypeDef 枚举类型的值,有 4 个,分别是 HAL_OK 表示 成功HAL_ERROR 表示 错误HAL_BUSY 表示 忙碌HAL_TIMEOUT 表示 超时

typedef enum 
{
    HAL_OK = 0x00U,             // 成功
    HAL_ERROR = 0x01U,          // 错误
    HAL_BUSY = 0x02U,           // 忙碌
    HAL_TIMEOUT = 0x03U         // 超时
} HAL_StatusTypeDef;

3.3、生成随机数

  HAL_RNG_GenerateRandomNumber() 是 RNG 生成随机数函数。

HAL_StatusTypeDef HAL_RNG_GenerateRandomNumber(RNG_HandleTypeDef *hrng, uint32_t *random32bit)

  形参 hrngRNG_HandleTypeDef 结构体类型指针变量,即 RNG 的句柄。

  形参 random32bituint32_t 类型指针变量,随机 32 位指针,生成随机变量。

  该函数的返回值是 HAL_StatusTypeDef 枚举类型的值,有 4 个,分别是 HAL_OK 表示 成功HAL_ERROR 表示 错误HAL_BUSY 表示 忙碌HAL_TIMEOUT 表示 超时

四、程序源码

  RNG 初始化函数:

RNG_HandleTypeDef g_rng_handle;

/**
 * @brief RNG初始化函数
 * 
 * @return uint8_t 0: 初始化成功; 1: 初始化失败
 */
uint8_t RNG_Init(void)
{
    uint16_t time = 0;

    g_rng_handle.Instance = RNG;
    HAL_RNG_Init(&g_rng_handle);

    // 等待RNG初始化完成
    while ((!__HAL_RNG_GET_FLAG(&g_rng_handle, RNG_FLAG_DRDY) == RESET) && (time < 1000))
    {
        time++;
        HAL_Delay(1);
    }
  
    if (time >= 1000)
    {
        return 1;
    }
  
    return 0;
}

  RNG 底层初始化函数:

/**
 * @brief RNG底层初始化函数
 * 
 * @param hrng 
 */
void HAL_RNG_MspInit(RNG_HandleTypeDef *hrng)
{
    if (hrng->Instance == RNG)
    {
        __HAL_RCC_RNG_CLK_ENABLE();
    }
}

  生成一个随机数函数

/**
 * @brief 生成一个随机数函数
 * 
 * @return uint32_t 32位的随机数值
 */
int RNG_GetRandomNumber(void)
{
    uint32_t random_number = 0;
    HAL_RNG_GenerateRandomNumber(&g_rng_handle, &random_number);

    return random_number;
}

  获取某一个范围内的随机数函数:

/**
 * @brief 获取某一个范围内的随机数函数
 * 
 * @param min 最小值
 * @param max 最大值
 * @return uint32_t 32位的随机数值
 */
int RNG_GetRandomNumberInRange(int min, int max)
{
    uint32_t random_number = 0;
    HAL_RNG_GenerateRandomNumber(&g_rng_handle, &random_number);

    return random_number % (max - min + 1) + min;
}

  main() 函数:

int main(void)
{
    uint32_t number = 0;

    HAL_Init();
    System_Clock_Init(8, 336, 2, 7);
    Delay_Init(168);

    UART_Init(&g_usart1_handle, USART1, 115200);
    RNG_Init();

    while (1)
    {
        number = RNG_GetRandomNumber();
        printf("number: %d\r\n", number);
        number = RNG_GetRandomNumberInRange(0, 100);
        printf("number: %d\r\n\r\n", number);
        HAL_Delay(1000);
    }
  
    return 0;
}
posted @ 2024-02-02 21:54  星光映梦  阅读(450)  评论(0编辑  收藏  举报