Setting up an Array with Functions and randomly accessing one of them.

Before I get totally crazy here I decided to ask for help.

I have build up 8LEDs with one 74HC164 and they work fine. I know how to access the different LEDS and how to shift them the way I desire.

I have created several functions for the different modes (like blink the leds left from right and right to left and so on)
Including to that I have installed a button into that circuit to access one function when pressing the button, and it works too.

What I want now is, putting all that different LED functions into an array and when pressing the button I want one of that functions to be called randomly.

I think I know what arrays are and how it works actually. But I simply dont know how to set up the code correctly.

const int buttonPin = 2;     // the number of the pushbutton pin

const int clockPin = 9;
const int dataPin = 8;

// variables will change:
int buttonState = 0;         // variable for reading the pushbutton status
int ButtonLoop = 0;
char* myLEDarray[] = {"snakeLeftRight", "walkLeftRight"};

void setup() {
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);    
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
}

void randomMode() {
  random(myLEDarray[2]);
}

void loop() {
  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);

  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (buttonState == HIGH) {
    randomMode ();
  }
  else allOFF ();
}

void allOFF() {
  shiftOut (dataPin, clockPin, MSBFIRST, B00000000);
}

void snakeLeftRight() {
  for (int i=0; i<3; i++)
  {
    shiftOut(dataPin, clockPin, MSBFIRST, B00000001);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B00000011);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B00000111);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B00001111);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B00011111);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B00111111);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B01111111);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B11111111);
    delay(50);

    shiftOut(dataPin, clockPin, MSBFIRST, B10000000);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B11000000);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B11100000);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B11110000);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B11111000);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B11111100);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B11111110);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B11111111);
    delay(50);
  }
}

void walkLeftRight() {
  for (int i=0; i<8; i++)
  {
    shiftOut(dataPin, clockPin, MSBFIRST, B00000001 << i);
    delay(50);
  }
  for (int i=0; i<8; i++)
  {
    shiftOut(dataPin, clockPin, MSBFIRST, B10000000 >> i);
    delay(50);
  }
}

This thread should help http://forum.arduino.cc/index.php/topic,204418.0.html

not sure if I really get anything out of that thread... at least it came to my mind that Arrays cannot simply call functions or I cannot call anything from an aray directly as a function.. so I have to build something up that places like a dummy function and then sets the function name out of an array and puts it into that dummy function as a string or something.. well

You can certainly create an array of function pointers and call them with a random index.

void randomblink1() {};
void randomblink2() {};
void randomblink3() {};
void (*funcptrs)()[3] = {randomblink1, randomblink2, randomblink3};

loop
{
funcptrs[get_random_0_to_2()]()
}

I'm not sure your definition will work:

void (*funcptrs)()[3] = {randomblink1, randomblink2, randomblink3};

Using Purdum's Right-Left Rule, your definition says: "funcptrs is a pointer to function of three arrays returning void". I'm not even sure that would compile. Try:

void (*funcptrs[3])() = {randomblink1, randomblink2, randomblink3};

Now using the Right-Left Rule, it says: "funcptrs is an array of three pointers to function returning void:". I think that's what he wants.

Thanks, I find function pointer declarations confusing. I take a stab and then let the compiler tell me how close I am. "Stepwise refinement by error message."

thx for your help guys... I just realize that I still lack a huge amount of how to manage C code... its all kind of nonsense to me. So this will be some hard work to get the basics at first.

even though years ago I coded in actionscrip and php ... its like I have never even worked with code at all ... the same logical principles but alwys different code aragments.

Function pointers are an advanced C topic. They are rarely needed. I used them for a slight speed increase in an expression parser I was writing.

You can also use a switch case like this:

switch (random_num_0_to_2)
{
    case 0:
    randomblink1();
    break;

    case 1:
    randomblink2();
    break;

   case 2:
    default:
    randomblink3();
    break;
}

Which, IMHO, is much easier to understand.

I am just totally stuck…
I somehow tried to put the different suggestion into the code but I simply dont get it to work.

How would I put it into this code here? (the huge part at the end is only to control the shift register with the different blinking modes)

this code now executes all the different blinking modes in a row, when I press the button…

const int clockPin = 9;  //setting the clock to talk to the 74HC164 shifter to pin 9 on arduino
const int dataPin = 8;   // setting the pin for serial communication with the 74HC164 shifter
const int buttonPin = 2; // setting the pin of the button

int buttonState = 0;   // button state low


//setting the different pins as Out or Input
void setup() {
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  pinMode(buttonPin, INPUT);
}


// Loop checking the button high low and executing command on high else all leds off
void loop() {
  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);

  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (buttonState == HIGH) {
    loopSnakeLeftRight ();
    walkLeftRight ();
    traindrive();
    leftrightcollusionSingle();
    leftrightcollusionsnake();
    fastblink();
    snakecentral();
    strobeblink();
    leftrightblink();
  }
  else allOFF ();
}

// All LEDS off function
void allOFF() {
  shiftOut (dataPin, clockPin, MSBFIRST, B00000000);
}



//  now all the different blinking modes for the shift register are bellow

void loopSnakeLeftRight() {
  for (int i=0; i<3; i++)
  {
    shiftOut(dataPin, clockPin, MSBFIRST, B00000001);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B00000011);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B00000111);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B00001111);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B00011111);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B00111111);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B01111111);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B11111111);
    delay(50);

    shiftOut(dataPin, clockPin, MSBFIRST, B10000000);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B11000000);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B11100000);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B11110000);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B11111000);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B11111100);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B11111110);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B11111111);
    delay(50);
  }
}

void walkLeftRight() {
  for (int i=0; i<8; i++)
  {
    shiftOut(dataPin, clockPin, MSBFIRST, B00000001 << i);
    delay(50);
  }
  for (int i=0; i<8; i++)
  {
    shiftOut(dataPin, clockPin, MSBFIRST, B10000000 >> i);
    delay(50);
  }
}

void traindrive() {
  for (int i=0; i<3; i++)
  {
    shiftOut(dataPin, clockPin, MSBFIRST, B00000000);
    delay(100); 
    shiftOut(dataPin, clockPin, MSBFIRST, B00000001);
    delay(100);
    shiftOut(dataPin, clockPin, MSBFIRST, B00000010);
    delay(100);
    shiftOut(dataPin, clockPin, MSBFIRST, B00000101);
    delay(100);
    shiftOut(dataPin, clockPin, MSBFIRST, B00001010);
    delay(100);
    shiftOut(dataPin, clockPin, MSBFIRST, B00010101);
    delay(100);
    shiftOut(dataPin, clockPin, MSBFIRST, B00101010);
    delay(100);
    shiftOut(dataPin, clockPin, MSBFIRST, B01010101);
    delay(100);
    shiftOut(dataPin, clockPin, MSBFIRST, B10101010);
    delay(100);
    shiftOut(dataPin, clockPin, MSBFIRST, B01010101);
    delay(100);
    shiftOut(dataPin, clockPin, MSBFIRST, B10101010);
    delay(100);
    shiftOut(dataPin, clockPin, MSBFIRST, B01010101);
    delay(100);
    shiftOut(dataPin, clockPin, MSBFIRST, B10101010);
    delay(100);
    shiftOut(dataPin, clockPin, MSBFIRST, B01010101);
    delay(100);
    shiftOut(dataPin, clockPin, MSBFIRST, B10101010);
    delay(100);
    shiftOut(dataPin, clockPin, MSBFIRST, B01010101);
    delay(100);

    shiftOut(dataPin, clockPin, MSBFIRST, B10101010);
    delay(100);
    shiftOut(dataPin, clockPin, MSBFIRST, B01010100);
    delay(100);
    shiftOut(dataPin, clockPin, MSBFIRST, B10101000);
    delay(100);
    shiftOut(dataPin, clockPin, MSBFIRST, B01010000);
    delay(100);
    shiftOut(dataPin, clockPin, MSBFIRST, B10100000);
    delay(100);
    shiftOut(dataPin, clockPin, MSBFIRST, B01000000);
    delay(100);
    shiftOut(dataPin, clockPin, MSBFIRST, B10000000);
    delay(100); 
    shiftOut(dataPin, clockPin, MSBFIRST, B00000000);
    delay(100); 

    shiftOut(dataPin, clockPin, MSBFIRST, B00000000);
    delay(50); 
    shiftOut(dataPin, clockPin, MSBFIRST, B10000000);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B01000000);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B10100000);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B01010000);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B10101000);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B01010100);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B10101010);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B01010101);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B10101010);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B01010101);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B10101010);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B01010101);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B10101010);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B01010101);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B10101010);
    delay(50);

    shiftOut(dataPin, clockPin, MSBFIRST, B01010101);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B00101010);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B00010101);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B00001010);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B00000101);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B00000010);
    delay(50);
    shiftOut(dataPin, clockPin, MSBFIRST, B00000001);
    delay(50); 
    shiftOut(dataPin, clockPin, MSBFIRST, B00000000);
    delay(50); 
  }
}

I mean I dont even know how to put it into the code there…

void loop() {
  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);

  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (buttonState == HIGH) {
    randomled();
  }
  else allOFF ();
}

// All LEDS off function
void allOFF() {
  shiftOut (dataPin, clockPin, MSBFIRST, B00000000);
}

switch randomled (random_num_0_to_2)
{
  
  case 0;
  loopSnakeLeftRight ();
  break;
  
  case 1:
  walkLeftRight ();
  break;
  
  case 2;
  traindrive();
  break;
}

To use the function pointers, first write three functions named randomblink1, randomblink2, and randomblink3. Then use the data definition I supplied in the earlier post. Perhaps this sample will help explain it:

                      // The three function definitions...
void randomblink1()
{
  Serial.println("We're in randomblink1()");
}
void randomblink2()
{
  Serial.println("We're in randomblink2()");
}
void randomblink3()
{
  Serial.println("We're in randomblink3()");
}
                     // An array of pointers to those functions
void (*funcptrs[3])() = {randomblink1, randomblink2, randomblink3};


void setup() {     
  Serial.begin(115200);
  randomSeed(analogRead(A0));    // Seed the random number generator.
}

void loop() {
  void (*whichone)();   // Define a dummy function so you can call the three functions. Using the Right-Left Rule, this
                         // says "whichone is a pointer to function returning void"
  
  long rand = random(0, 3);  // Only return values 0-2
  
  whichone = funcptrs[rand];   // This assigns a random function pointer as the lvalue of whichone()
  whichone();                     // Invoke the function
  
  delay(1000);               // wait for a second
}

In an unabashed plug, my book Beginning C for Arduino has two chapters on pointers. and explains the Right-Left Rule which you might find useful.

Thanks for your exact explanation.... I will try it out! EDIT: in this case it worked with the Switch, but I really want to understand the function pointers and will try to solve it with the function pointers next.

At least I am happy that it works now at all.... :fearful:

I wonder but I got it to work with the Switch case...

with this code it actually really randomly selects one of the cases, I was very suprized that it worked. But I wonder why I need to hold the button for about 2 seconds before it even executes this command, weird.

// Loop checking the button high low and executing command on high else all leds off
void loop() {
  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);

  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (buttonState == HIGH) {
    int random_num_0_to_8 = random ();
    
   switch (random_num_0_to_8) {
  case '0':
    loopSnakeLeftRight ();
    break;
  case '1':
    walkLeftRight ();
    break;
  case '2':
    traindrive();
    break;
  case '3':
    leftrightcollusionSingle();
    break;
  case '4':
    leftrightcollusionsnake();
    break;
  case '5':
    fastblink();
    break;
  case '6':
    snakecentral();
    break;
  case '7':
    strobeblink();
    break;
  case '8':
    leftrightblink();
    break;    
    
  
}

“Stepwise refinement by error message.”

I never knew that there was a formal name to my style of coding. 8)

Aw, come on...try the function pointers. They're worth learning.

I'm not sure what this call does:

    int random_num_0_to_8 = random ();

But it seems unlikely that it returns a number from 0 to 8. This might work better:

    int random_num_0_to_8 = random (0,8);

you are right... I wondered why it delayed sometimes a long time before it changed from one blink mode to another... and it was simply because he was chosing randomly a number that was higher than 0 to 8... like 2000. And of course 2000 was not leading to any function inside the switch, so it threw out a number till it hit something in between 0 and 8. So I just put random (9) and it doesnt delay anymore.

even figured out how to avoid chosing the same number twice in a row... (proud)

would like to figure out how to code probabilities... for example... one specific function has to be selcted more often than another...

but that is a whole another story..

btw.. THANKS to everyone in this thread helping me.. I really moved forward of understanding coding this little fella..