Odd random() behavior

I'm trying to use the random() function to choose a number between 1 and 10, which is then used to return a specific array in a function. The application I am using this in is an "jar of fireflies" project that flashes LEDs to mimic the behavior of fireflies. The firefly light sequences are stored as arrays of PWM values, and I simply cycle through each value in the array to display a pattern using the LEDs.

If I hard-code this function of mine to output pattern number 3 every time its called, it works just fine. But when I try to use random() to pick a random pattern between 1 and 10, the LEDs no longer flash.

I should note that I am using HLT's implementation of the Arduino core for ATTiny85s! So perhaps the random() function is not yet supported. Nonetheless, can somewhat suggest a neat way to get my program to choose a pseudo-random pattern (or a number from 1-10) without using external libraries? Thanks!

byte * pickPattern() {
//  int r = random(1,10);  // does not work
  int r = 10; // works!
  
  CHAN_1_PATTERN_SIZE = patternSizes[r-1];
  
  switch(r) {
    case 1:
      return pattern1;
      break;
    case 2:
      return pattern2;
      break;
    case 3:
      return pattern3;
      break;
    case 4:
      return pattern4;
      break;
    case 5:
      return pattern5;
      break;
    case 6:
      return pattern6;
      break;
    case 7:
      return pattern7;
      break;
    case 8:
      return pattern8;
      break;
    case 9:
      return pattern9;
      break;
    case 10:
      return pattern10;
      break;
  }
  
}

Why the switch/case?
Why not a simple array of pointers?

So perhaps the random() function is not yet supported

I believe the Alessandro Saporetti / HLT core does include random. In any case, this code...

void setup( void )
{
  Serial.begin( 9600 );
}

void loop( void )
{
  Serial.println( random( 1, 10 ) );
  delay( 100 );
}

...on this core...

http://code.google.com/p/arduino-tiny/

...produces a stream of values 1 through 9 (as documented, the high value is excluded). random works fine for me.

Assuming also that analogRead() is also not available

analogRead is available. But, even on a floating pint, the values are decidedly not random. The random function is a good choice.

Hm, the plot thickens. Well here’s my full code, maybe you can provide some insight into something that I’m doing wrong with my logic, rather than the core being at fault. All I have connected to the ATTiny85 is an LED whose anode is connected to pin 5 (pin 0 in Arduino mapping), and cathode connected to pin 7 (pin 2 in Arduino mapping).

When I don’t use random and explicitly return the same pattern every single time in my pickPattern method (choose r = 4, for example), the LED lights up just fine. But when I try to use random(1,10), nothing happens. Sometimes the LED will blink once very, very faintly, but thats about it.

// Define the driver (+) pins
#define  CHAN_1_DRIVER_PIN  0

const byte NUM_LOW_PINS = 3;
const byte NUM_PATTERNS = 10;
const byte LOW_PINS[] = {2, 3, 4};

// Separate variables for two concurrent channels
byte CHAN_1_PIN;
byte * CHAN_1_PATTERN;
byte CHAN_1_PATTERN_SIZE;
byte CHAN_1_COUNTER;
byte CHAN_1_PATTERN_COUNTER;

// Define all the firefly patterns (based on real data)
byte pattern1[] = {2, 14, 44, 95, 141, 175, 192, 186, 149, 94, 60, 35, 38, 50, 76, 83, 73, 58, 43, 30, 20, 14, 16, 25, 30, 27, 20, 11, 4, 10, 17, 19, 14, 8, 4, 4, 6, 9, 9, 4, 2, 4, 14, 37, 79, 133, 173, 185, 172, 143, 106, 70, 45, 36, 44, 60, 75, 75, 59, 37, 20, 12, 16, 22, 26, 25, 22, 18, 14, 10, 7, 5, 7, 10, 10, 9, 7, 6, 5, 4, 5, 6, 6, 6, 5, 4, 3, 2, 2, 1};
byte pattern2[] = {5, 17, 45, 89, 131, 163, 185, 192, 180, 143, 95, 64, 41, 31, 44, 55, 79, 82, 73, 61, 48, 36, 26, 18, 14, 15, 23, 30, 29, 24, 17, 9, 4, 9, 15, 19, 17, 12, 6, 3, 3, 6, 8, 9, 7, 3, 2, 4, 12, 30, 61, 105, 149, 178, 184, 172, 148, 116, 84, 57, 41, 36, 44, 58, 72, 76, 68, 51, 32, 18, 12, 14, 20, 24, 26, 24, 21, 18, 15, 11, 8, 5, 5, 8, 10, 10, 9, 8, 6, 5, 4, 4, 5, 6, 6, 6, 5, 5, 4, 3, 2, 2, 1};
byte pattern3[] = {5, 15, 32, 64, 99, 132, 160, 179, 183, 167, 131, 89, 62, 44, 32, 36, 44, 54, 74, 74, 67, 57, 47, 38, 29, 21, 16, 14, 17, 24, 29, 29, 26, 20, 14, 6, 6, 13, 18, 20, 19, 16, 11, 6, 4, 4, 6, 9, 10, 8, 5, 3, 4, 7, 18, 37, 68, 112, 156, 186, 192, 176, 148, 115, 85, 61, 45, 36, 36, 45, 58, 69, 70, 59, 43, 29, 20, 15, 13, 15, 20, 23, 24, 24, 22, 20, 17, 14, 11, 8, 6, 5, 7, 11, 11, 9, 7, 5, 3};
byte pattern4[] = {2, 29, 81, 123, 130, 104, 63, 24, 2, 1, 1, 1, 1, 1, 1, 4, 15, 26, 36, 46, 55, 66, 79, 91, 102, 109, 115, 121, 131, 142, 152, 155, 151, 141, 133, 131, 135, 144, 153, 158, 158, 154, 151, 150, 149, 148, 144, 139, 136, 138, 145, 155, 161, 160, 153, 144, 138, 139, 145, 152, 156, 154, 148, 141, 138, 140, 145, 150, 153, 153, 152, 152, 154, 154, 150, 142, 134, 129, 132, 142, 156, 168, 170, 161, 146, 131, 121, 117, 116, 116, 115, 113, 110, 109, 106, 101, 92, 80, 67, 58, 52, 49, 46, 43, 39, 33, 27, 22, 18, 14, 11, 7, 5, 3, 1, 1, 0, 1, 0};
byte pattern5[] = {1, 31, 89, 126, 119, 85, 42, 6, 1, 1, 1, 1, 1, 1, 8, 22, 37, 51, 64, 72, 80, 92, 108, 122, 127, 122, 117, 124, 143, 163, 167, 155, 139, 135, 142, 150, 150, 141, 131, 129, 133, 139, 143, 146, 149, 152, 150, 144, 138, 138, 145, 150, 147, 137, 132, 137, 153, 166, 167, 156, 148, 149, 156, 161, 156, 147, 141, 145, 152, 157, 156, 154, 156, 161, 161, 152, 140, 133, 131, 130, 124, 114, 105, 102, 103, 101, 93, 82, 74, 68, 63, 55, 46, 38, 32, 29, 25, 20, 15, 11, 8, 6, 4, 2, 1, 1, 0, 0};
byte pattern6[] = {2, 25, 70, 117, 146, 144, 111, 61, 18, 1, 1, 1, 1, 1, 1, 1, 1, 8, 18, 28, 39, 50, 60, 69, 78, 85, 92, 99, 105, 111, 118, 126, 134, 142, 149, 155, 159, 161, 160, 156, 152, 146, 139, 134, 129, 126, 125, 126, 129, 134, 140, 148, 155, 162, 168, 171, 172, 171, 168, 163, 158, 153, 149, 146, 144, 144, 146, 148, 151, 154, 157, 158, 158, 157, 154, 150, 145, 141, 137, 134, 133, 132, 134, 136, 139, 143, 147, 149, 150, 150, 147, 143, 138, 133, 128, 123, 118, 115, 113, 111, 109, 108, 105, 102, 98, 92, 86, 78, 70, 63, 55, 48, 42, 37, 33, 29, 25, 22, 19, 16, 13, 10, 7, 5, 3, 2, 1, 1, 0, 0};
byte pattern7[] = {1, 27, 72, 109, 121, 104, 61, 17, 1, 1, 1, 1, 1, 1, 1, 11, 21, 34, 48, 60, 70, 77, 86, 99, 115, 128, 135, 135, 134, 136, 141, 144, 143, 139, 138, 141, 147, 148, 142, 131, 123, 126, 138, 153, 164, 166, 161, 156, 154, 154, 153, 151, 150, 155, 163, 169, 166, 152,136, 126, 128, 139, 151, 156, 153, 146, 140, 136, 131, 123, 115, 110, 110, 112, 110, 100, 86, 73, 65, 62, 60, 58, 52, 46, 40, 35, 31, 25, 20, 15, 11, 8, 6, 4, 2, 1, 1, 0, 0};
byte pattern8[] = {1, 26, 73, 116, 131, 115, 80, 39, 8, 1, 1, 1, 1, 1, 1, 1, 6, 15, 26, 36, 47, 58, 70, 82, 91, 98, 102, 106, 111, 119, 131, 144, 154, 157, 153, 144, 137, 134, 137, 146, 154, 158, 156, 149, 141, 137, 138, 143, 151, 157, 158, 155, 151, 148, 150, 154, 158, 160, 158, 153, 148, 144, 145, 147, 150, 150, 146, 140, 133, 130, 131, 135, 140, 143, 144, 142, 141, 141, 144, 149, 153, 156, 157, 157, 157, 160, 164, 167, 167, 161, 153, 145, 142, 143, 149, 154, 155, 149, 137, 124, 115, 112, 116, 123, 128, 128, 121, 110, 99, 91, 88, 88, 89, 87, 83, 75, 66, 57, 50, 44, 38, 34, 29, 25, 20, 17, 13, 9, 7, 4, 3, 1, 1, 0, 1, 0};
byte pattern9[] = {2, 36, 94, 130, 121, 79, 27, 1, 1, 1, 1, 1, 1, 5, 16, 30, 45, 59, 71, 82, 94, 107, 119, 130, 137, 142, 147, 151, 154, 153, 149, 144, 141, 141, 143, 143, 140, 134, 131, 135, 145, 160, 171, 172, 163, 150, 141, 140, 145, 151, 152, 147, 138, 134, 136, 147, 159, 165, 162, 152, 140, 132, 129, 131, 132, 131, 127, 123, 119, 116, 112, 105, 96, 86, 77, 69, 62, 54, 45, 38, 31, 27, 23, 19, 14, 10, 6, 4, 2, 1, 1, 0, 0};
byte pattern10[] = {2, 42, 99, 121, 96, 42, 3, 1, 1, 1, 1, 1, 12, 25, 41, 60, 77, 86, 91, 100, 118, 136, 144, 143, 141, 146, 153, 155, 153, 152, 155, 154, 148, 141, 142, 152, 159, 154, 142, 136, 141, 152, 153, 143, 132, 126, 124, 120, 111, 101, 92, 83, 72, 59, 49, 43, 38, 30, 21, 15, 11, 8, 5, 3, 1, 1, 0, 0};

// Set up an array for all the patterns
byte patternSizes[] = { 90, 103, 99, 119, 108, 130, 98, 136, 93, 68 }; 
byte patternOrder[] = {1, 4, 2, 6, 10, 4, 8, 1, 3, 7, 5, 10, 3, 4, 4, 8, 1, 4, 7, 3, 8, 2, 9, 8, 10, 2, 4, 6, 7, 3, 3, 9};
byte patternOrderSize = 32;

void setup() {
  // Set up all the pin directions
  pinMode(CHAN_1_DRIVER_PIN, OUTPUT);
  
  for(int i=0; i<3; i++)
    pinMode(LOW_PINS[i], OUTPUT);

  // Initialize both driver pins to LOW, so no power reaches LEDs
  digitalWrite(CHAN_1_DRIVER_PIN, LOW);
  
  // Initialize all grounding pins to HIGH, so that when the
  // driver pins do go HIGH, not all LEDs turn on.
  for(int i=0; i<3; i++)
    digitalWrite(LOW_PINS[i], HIGH);
    
  CHAN_1_PIN = LOW_PINS[0];
  CHAN_1_PATTERN_COUNTER = 0;
  CHAN_1_PATTERN = pickPattern();

}

void loop() {

 // Drive LED cathode LOW (provide path to ground)  
 digitalWrite(CHAN_1_PIN, LOW);
 
 // Output frame of pattern
 analogWrite(CHAN_1_DRIVER_PIN, CHAN_1_PATTERN[CHAN_1_PATTERN_COUNTER]);
 
 // Increment pattern counter, or reset counter and pick a new pattern
 if(CHAN_1_PATTERN_COUNTER < CHAN_1_PATTERN_SIZE) {
   CHAN_1_PATTERN_COUNTER++;
 } else {
   CHAN_1_PATTERN_COUNTER = 0;
   CHAN_1_PATTERN = pickPattern();
 }
 
 delay(10);
  
}

/******************************************
 Pick a random pattern
 - Method to pick a random firefly 
   pattern by generating a random number
   between 1 and 10.
*******************************************/
byte * pickPattern() {
  int r = random(1,10);  // does not work
//  int r = 10; // works!
  
  CHAN_1_PATTERN_SIZE = patternSizes[r-1];
  
  switch(r) {
    case 1:
      return pattern1;
      break;
    case 2:
      return pattern2;
      break;
    case 3:
      return pattern3;
      break;
    case 4:
      return pattern4;
      break;
    case 5:
      return pattern5;
      break;
    case 6:
      return pattern6;
      break;
    case 7:
      return pattern7;
      break;
    case 8:
      return pattern8;
      break;
    case 9:
      return pattern9;
      break;
    case 10:
      return pattern10;
      break;
    default:
      return pattern2;
      break;
  }
  
}

h4t:
maybe you can provide some insight into something that I’m doing wrong with my logic

The logic may or may not be a problem. What is definitely a problem…

Memory available… 512 Bytes Internal SRAM

Largest memory consumers…

pattern1 90
pattern2 103
pattern3 99
pattern4 119
pattern5 108
pattern6 130
pattern7 99
pattern8 136
pattern9 93
pattern10 68
patternSizes 10
patternOrder 32
Total 1087

Your Sketch uses considerably more memory than what is available. You will need to move most or all of the arrays into PROGMEM.

All I have connected to the ATTiny85 is an LED whose anode is connected to pin 5 (pin 0 in Arduino mapping), and cathode connected to pin 7 (pin 2 in Arduino mapping).

No current limiting resistor?

When I don’t use random and explicitly return the same pattern every single time in my pickPattern method (choose r = 4, for example), the LED lights up just fine.

Luck.

Sure about that? When I compile my program using the "ATTiny85 w/ Arduino as ISP" board option (HLT's core) I have plenty of space:

Binary sketch size: 2614 bytes (of a 8192 byte maximum)

Also, doesn't the Atmel datasheet state that the ATTiny85 has 8k of memory?

And yes, I do have a current limiting resistor (just a 100ohm for testing, I have other resistors and LEDs for the finished product, once the code is debugged).

h4t:
Sure about that?

Quite. A better description than I could write...

Great, I wish this had been explained in the docs for the core :frowning: I tried once a while ago to understand how to use PROGMEM, but it was too hard for me. Now it looks like I don't have a choice, lol. Time to get reading, I guess!

By the way, how did you get that breakdown of bytes you posted? It'd be cool to know that kind of info on the fly when developing.

Over at AVRfreaks a few years ago there was a simulation of firefly behaviour, including the self-synchronising bit.
Worth having a dig for.

h4t:
Great, I wish this had been explained in the docs for the core :frowning:

If your comment was meant to be constructive criticism then you'll need to clarify what you mean by "this".

I tried once a while ago to understand how to use PROGMEM, but it was too hard for me. Now it looks like I don't have a choice, lol. Time to get reading, I guess!

Start here...
http://arduiniana.org/libraries/flash/

By the way, how did you get that breakdown of bytes you posted?

The command-line tool "avr-size" can be used to determine the static memory usage. I prefer to use my eyeballs and Excel to get a total. This forces me to look at the source code giving me a rough idea of the dynamic memory usage.

It'd be cool to know that kind of info on the fly when developing.

It would. I believe the feature (static memory usage reporting) has been requested. I suggest you add your voice to the request...
http://code.google.com/p/arduino/

'this' meaning how the compiled sketch size reported in the Arduino IDE does not show the whole picture: without realizing the differences in memory types, average users will tend to look at the compiled sketch size reported and assume thats all there is to it. It would be awesome if, instead, the IDE spit out something more like this:

Flash: 2614 bytes (of a 8192 byte maximum)
SRAM: 1025 (of a 512 byte maximum)
EEPROM: 0 (of a 512 byte maximum)

[color=red]ERROR: SRAM is full! You may experience unexpected sketch behavior. Try moving large variables and constants into Flash memory, see: http://www.arduino.cc/en/Tutorial/Memory[/color]

I'll get to work figuring out PROGMEM, and if it still eludes me, I will jump right into that Flash library you posted.

By the way, am I correct in thinking that SRAM for a microcontroller is much like RAM on a PC, and that using the PROGMEM modifier is essentially similar to using hard drive space as extra memory (swap space, I think they call it)?

Thanks for the help!

There is a limit on the amount of SRAM available, which the compiler could know about. The problem with reporting the amount of SRAM is that some of it is used by static objects (literal strings, static arrays, etc.) and some of it is used by dynamic objects (stack, heap, malloc, etc.). The compiler knows nothing about how much you will use malloc(), or how many functions deep you will end up at any one time, which affects stack usage.

The compiler has no idea how much EEPROM you might be using. That is entirely up to you to maintain control of.

h4t:
‘this’ meaning how the compiled sketch size reported in the Arduino IDE does not show the whole picture … the IDE spit out something more like this:

As I said earlier, please add your voice where it will count; on the “issue list”.

By the way, am I correct in thinking that SRAM for a microcontroller is much like RAM on a PC, and that using the PROGMEM modifier is essentially similar to using hard drive space as extra memory (swap space, I think they call it)?

A fairly good analogy.