Sebastian Jarosz
Sebastian Jarosz

Reputation: 83

AVR Atmega128 random number generator from range

I'm building project for studies on ATmega128 with my friend and we have a problem with random number generator (from 0 to 5), because the function always show the same result. We can't add time.h, because AVR Studio didn't accept this.

Code below:

uint8_t randomNumber(uint8_t r){
r = rand()%5;
return r;
}

other try

uint8_t randomNumber(uint8_t min, uint8_t max){
uint8_t = result;
result = min + rand() % (max+1 - min);
return result;
}

Any ideas? Thanks, Sebastian

Upvotes: 1

Views: 5327

Answers (1)

bathMarm0t
bathMarm0t

Reputation: 423

Wow this question sent me down the rabbit hole.

  1. Pseudorandom numbers are relatively easy to generate.
  2. Truly random numbers are VERY hard to generate.
  3. The quality of your random number (whether biases appear in it) depends completely on your seed value.
  4. 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:

  1. 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)).
  2. Time user inputs (humans are by default not precise).
  3. 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;
}

Upvotes: 4

Related Questions