Wow this question sent me down the rabbit hole.
- Pseudorandom numbers are relatively easy to generate.
- Truly random numbers are VERY hard to generate.
- The quality of your random number (whether biases appear in it) depends completely on your seed value.
- Seed values for random number generators must be (wait for it) random, otherwise people can guess which numbers you are using, defeating the randomness of your generator.
Where to get a random seed value from?
Options proposed by the internet:
- Natural noise from the environment (read an adc, or... https://www.fourmilab.ch/hotbits/ (i know it's not practical for an arduino project, but interesting none the less)).
- Time user inputs (humans are by default not precise).
- Timing differences between crystals. [https://en.wikipedia.org/wiki/Clock_drift]
Mild disclaimer:
1/3 have been proven unsafe in commercial environments, and it's easy to see how #2 could be gamed by using a computer instead of a human.
So the quickest way is probably to use a floating ADC. Before you think this is a good idea: https://skemman.is/bitstream/1946/10689/1/ardrand.pdf
Remember: Larger pools of seeds increases the randomness (aka using a 32bit random seed value is better than using a boolean random seed value).
ADC's on the 128 have 1024 values, realistically, a floating point value will trend to far less than that (I've read you should treat it like 32).
To improve your chances of getting random numbers, take the lowest bit from the adc reading multiple times (aka read the adc 16 times to get a 16 bit "random" number).
Assuming you have your adc set up etc.
UNTESTED PSEUDO CODE
/* 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;
}