如何有效地在微控制器中生成随机数?是否有任何通用指南或特定的快速方法?
8 回答
一个通常生成伪随机数而不是实际随机数,尽管两者都可能以不同的速率。
有两个一般类别,具体取决于序列是否将用于加密目的。主要区别在于序列中一个数字的知识是否允许预测下一个数字。通用RNG不担心算法知识是否允许观察者复制序列,它们运行得更快。
一个典型的通用 RNG 算法是Mersenne Twister。各种算法有许多公共实现。看这里一个。
如果 MT 需要太多内存,一个中途的后备是线性同余生成器。(MT 直到 1997 年才发明。)这个生成器有一些问题,但它几乎不需要内存,几乎不需要代码,而且速度非常快。实现无处不在,在 Knuth 的半数字算法中有详细介绍。
要播种任何 RNG,您将需要熵源,请参阅http://en.wikipedia.org/wiki/Entropy_(computing)(注意:SO 对该链接中的 () 感到困惑。)这通常是由 CPU 可以观察到的定时事件派生,例如击键、(我猜这对你不起作用)中断和数据包到达。如果实时时钟保持自己的状态,则它通常是可接受的来源,因为很少以任何顺序对重新启动进行计时。
您可以将种子存储到 EEPROM,当设备启动时,您可以增加种子并再次存储。所以,每次重启你都会有不同的随机数。
如果您可以访问 ADC,则可以从中读取最低有效位,并将其用作伪随机数生成器的种子,就像其他人发布的那样。显然,您需要从 ADC 读取多个位,因此需要多次读取,这可能需要一段时间。但是您只需要这样做一次,例如在启动时,然后使用更快的 PRNG 生成新的随机数。
许多嵌入式器件都内置了内置ADC,例如Atmel 的ATMega 系列。
如果硬件有一个供用户使用的按钮,一个简单的技巧是计算按钮被按下的时间。使用足够快的短计数器,您会得到一个“随机”数字。
Pseudo random number generators that are the fastest and least demanding w.r.t. the instruction set (only shift and xor, no multiplication or division) are smaller variants of the Mersenne twister idea (called Generalized Linear Feedback Shift register). Mersenne twister itself needs too much memory for microcontrollers.
The problem with these generators is that they may generate long sequences near zero if you are unlucky. With a reasonable size of the state space and initialization from another PNRG this is however unlikely.
They are also not secure for cryptography or gambling, an intelligent adversary can predict future states after observing the output. This is because they are linear.
I once designed such a generator for a small nonstandard processor with a state space of about 50 24-bit words. I tested variants with the Diehard test suite until I found a good one. The application was generating random variations for a hardware test.
读取计时器并使用一系列位对其进行异或/南定/等会给用户一个半随机的,因为事件之间的时间可能足够分开,用户将无法真正分辨出与计时器。
如果您可以使引脚悬空,则可以帮助使用线性反馈移位寄存器生成随机数。我不确定这是要走的路,但请看看我的代码:
// This code was written for 8051 (AT89S52)
unsigned char lfsr = 231; //8 bit shift register, with the seed of 231 or '11100111b'
unsigned char input_bit, i;
void main (void)
{
//Setup
P0_0 = 0; // Leave Pin 0 Port 0 floating
uart_init(); //Initializing uart/serial communication with pc
while (1)
{
for (i = 0; i < 255; i++)
{
if (P0_0 == 1) // If Pin 0.0 is HIGH
{
input_bit = ((lfsr >> 0) ^ (lfsr >> 2) ^ (lfsr >> 3) ^ (lfsr >> 4)) & 1;
lfsr = (lfsr >> 1) | (input_bit << 7);
}
}
printf_tiny("%u\n", lfsr); //Send the random number to PC
soft_delay(65535); //Simple delay function
} //end while (1) loop
}
编辑:我发现我的答案可能很糟糕。关于为什么不应该使用浮动数字引脚的更多详细信息:https ://electronics.stackexchange.com/questions/50476/random-number-generators-using-a-gpio-pin