AVR Atmega128 范围内的随机数发生器
AVR Atmega128 random number generator from range
我正在与我的朋友一起构建 ATmega128 研究项目,我们遇到了随机数生成器(从 0 到 5)的问题,因为该函数总是显示相同的结果。我们不能添加 time.h,因为 AVR Studio 不接受这个。
代码如下:
uint8_t randomNumber(uint8_t r){
r = rand()%5;
return r;
}
其他尝试
uint8_t randomNumber(uint8_t min, uint8_t max){
uint8_t = result;
result = min + rand() % (max+1 - min);
return result;
}
有什么想法吗?
谢谢,
塞巴斯蒂安
哇,这个问题让我掉进了兔子洞。
- 伪随机数比较容易生成。
- 真正的随机数很难生成。
- 您的随机数的质量(是否出现偏差)完全取决于您的种子值。
- 随机数生成器的种子值必须是(等等)随机的,否则人们可以猜出你使用的是哪个数字,从而破坏你的生成器的随机性。
从哪里获得随机种子值?
互联网提出的方案:
- 来自环境的自然噪声(读取一个 adc,或者...https://www.fourmilab.ch/hotbits/(我知道这对于 arduino 项目不实用,但有趣 none 更少))。
- 时间用户输入(人类默认不精确)。
- 晶体之间的时间差异。 [https://en.wikipedia.org/wiki/Clock_drift]
轻微免责声明:
1/3 已被证明在商业环境中是不安全的,并且很容易看出 #2 是如何通过使用计算机而不是人类来进行游戏的。
所以最快的方法可能是使用浮动ADC。在你认为这是个好主意之前:https://skemman.is/bitstream/1946/10689/1/ardrand.pdf
记住:较大的种子池会增加随机性(也就是使用 32 位随机种子值比使用布尔随机种子值更好)。
128 上的 ADC 有 1024 个值,实际上,浮点值趋向于远小于这个值(我读过你应该像 32 一样对待它)。
为了提高获得随机数的机会,多次从 adc 读数中取出最低位(也就是读取 adc 16 次以获得 16 位 "random" 数字)。
假设您设置了 adc 等
未经测试的伪代码
/* srand example */
#include <stdio.h> /* printf, NULL */
#include <stdlib.h> /* srand, rand */
#include <avr/io.h>
//pseudo code. you must implement init_adc() and read_adc()
int main ()
{
//Init and seed.
uint16_t u_rand_val = 0;
uint16_t u_seed_rand_val = 0;
init_adc();
//Note we're assuming the channel that you are reading from is FLOATING or hooked up to something very noisy.
//Gather bits from the adc, pushing them into your pseudorandom seed.
for(uint8_t i=0; i<16; i++){
u_seed_rand_val = u_seed_rand_val<<1 | (read_adc()&0b1);
}
srand (u_seed_rand_val);
while(1){
//Do whatever you were going to do.
//Note that calls to rand() use the seed set up by srand above.
u_rand_val = rand()%5;
print("Cur val:%u", u_rand_val);
}
return 0;
}
我正在与我的朋友一起构建 ATmega128 研究项目,我们遇到了随机数生成器(从 0 到 5)的问题,因为该函数总是显示相同的结果。我们不能添加 time.h,因为 AVR Studio 不接受这个。
代码如下:
uint8_t randomNumber(uint8_t r){
r = rand()%5;
return r;
}
其他尝试
uint8_t randomNumber(uint8_t min, uint8_t max){
uint8_t = result;
result = min + rand() % (max+1 - min);
return result;
}
有什么想法吗? 谢谢, 塞巴斯蒂安
哇,这个问题让我掉进了兔子洞。
- 伪随机数比较容易生成。
- 真正的随机数很难生成。
- 您的随机数的质量(是否出现偏差)完全取决于您的种子值。
- 随机数生成器的种子值必须是(等等)随机的,否则人们可以猜出你使用的是哪个数字,从而破坏你的生成器的随机性。
从哪里获得随机种子值?
互联网提出的方案:
- 来自环境的自然噪声(读取一个 adc,或者...https://www.fourmilab.ch/hotbits/(我知道这对于 arduino 项目不实用,但有趣 none 更少))。
- 时间用户输入(人类默认不精确)。
- 晶体之间的时间差异。 [https://en.wikipedia.org/wiki/Clock_drift]
轻微免责声明: 1/3 已被证明在商业环境中是不安全的,并且很容易看出 #2 是如何通过使用计算机而不是人类来进行游戏的。
所以最快的方法可能是使用浮动ADC。在你认为这是个好主意之前:https://skemman.is/bitstream/1946/10689/1/ardrand.pdf
记住:较大的种子池会增加随机性(也就是使用 32 位随机种子值比使用布尔随机种子值更好)。
128 上的 ADC 有 1024 个值,实际上,浮点值趋向于远小于这个值(我读过你应该像 32 一样对待它)。
为了提高获得随机数的机会,多次从 adc 读数中取出最低位(也就是读取 adc 16 次以获得 16 位 "random" 数字)。
假设您设置了 adc 等
未经测试的伪代码
/* srand example */
#include <stdio.h> /* printf, NULL */
#include <stdlib.h> /* srand, rand */
#include <avr/io.h>
//pseudo code. you must implement init_adc() and read_adc()
int main ()
{
//Init and seed.
uint16_t u_rand_val = 0;
uint16_t u_seed_rand_val = 0;
init_adc();
//Note we're assuming the channel that you are reading from is FLOATING or hooked up to something very noisy.
//Gather bits from the adc, pushing them into your pseudorandom seed.
for(uint8_t i=0; i<16; i++){
u_seed_rand_val = u_seed_rand_val<<1 | (read_adc()&0b1);
}
srand (u_seed_rand_val);
while(1){
//Do whatever you were going to do.
//Note that calls to rand() use the seed set up by srand above.
u_rand_val = rand()%5;
print("Cur val:%u", u_rand_val);
}
return 0;
}