Dynamic Array Filling

I have built a circuit on my Arduino Mega 2560, with 8 LEDS with built in resistors plugged into digital ports 39, 41, 43, 45, 47, 49, 51, and 53. They are controlled by 8 Momentary Push Buttons plugged into digital ports 38, 40, 42, 44, 46, 48, 50, and 52 and 220 Ω resistors to the ground rail on one side, and my positive rail on the other. I also have a piezo buzzer plugged into digital pin 8.

My code is as follows:

const int LED1 = 39;
const int LED2 = 41;
const int LED3 = 43;
const int LED4 = 45;
const int LED5 = 47;
const int LED6 = 49;
const int LED7 = 51;
const int LED8 = 53;
const int Button1 = 38;
const int Button2 = 40;
const int Button3 = 42;
const int Button4 = 44;
const int Button5 = 46;
const int Button6 = 48;
const int Button7 = 50;
const int Button8 = 52;
const int Speaker = 36;
int CurrentButton[]={Button1, Button2, Button3, Button4, Button5, Button6, Button7, Button8};
int CB;
int CurrentLED[]={LED1,LED2,LED3,LED4,LED5,LED6,LED7,LED8};
int CL;
int count;
int RandomStart;
long seed;
         
void setup(){
   long seed = analogRead(0) + 1024 * analogRead(1);
   randomSeed(seed);
   RandomStart=random(0,8);
   //RandomStart=5;
   pinMode(LED1, OUTPUT);
   pinMode(LED2, OUTPUT);
   pinMode(LED3, OUTPUT); 
   pinMode(LED4, OUTPUT);
   pinMode(LED5, OUTPUT);
   pinMode(LED6, OUTPUT);
   pinMode(LED7, OUTPUT);
   pinMode(LED8, OUTPUT);
   pinMode(Button1, INPUT);
   pinMode(Button2, INPUT);
   pinMode(Button3, INPUT);
   pinMode(Button4, INPUT);
   pinMode(Button5, INPUT);
   pinMode(Button6, INPUT);
   pinMode(Button7, INPUT);
   pinMode(Button8, INPUT);
   CB=CurrentButton[RandomStart];
   CL=CurrentLED[RandomStart];
   count=RandomStart;
   digitalWrite(CL, HIGH);
   tone(8,50,100);
}
         
void loop() {
  if (digitalRead(CB) == HIGH) {
    digitalWrite(CL, LOW);
    count++;
    if(count>=sizeof(CurrentButton)/sizeof(CurrentButton[0])) count = 0;
    CB = CurrentButton[count];
    CL = CurrentLED[count];
    digitalWrite(CL, HIGH);
  }
}

As of now, my code works perfectly. Each LED is associated with one button, at the start of the program one is randomly selected and illuminated. After that you can press an LED's button to turn it off, and illuminate the next one in sequence. This all works perfectly. There is just one more piece of functionality that I would like to add but have no clue how to approach.

Currently I have an array with all 8 buttons in it, and a corresponding array with all 8 LEDs in it. I would like to make it so when the program starts up my buzzer plays a tone, and a certain number of buttons are pressed, and then 10 seconds later the buzzer plays a second tone and only the buttons pressed in between the two tones are the LEDs that get cycled through.

Any and all help would be greatly appreciated.

Currently I have an array with all 8 buttons in it, and a corresponding array with all 8 LEDs in it.

That is a very convoluted way to populate the arrays. There is no reason, once you have an array of pin numbers to have individual variables with the same values.

and a certain number of buttons are pressed

A certain FIXED number or a certain VARIABLE number?

Two things that would make everything a lot easier.

First is hardware an doesn't make a big change (anymore). In the future, just place the buttons between GND and the pin and just enable the internal pull up. No need for a resistor that way.

Second and major, which you kind of tried, use arrays! This would reduce the code to <30 lines :wink:

And in that same light, you could just make an array to mask off unused switches.

Smalll example:

const byte SwitchPins[] = {2, 3, 4};
const byte NrSwitches = sizeof(SwitchPins);
const byte LedPins[NrSwitches] = {5, 6, 7};

bool mask[NrSwitches];

void setup(){
  //set pinmodes
  for(byte i = 0; i < NrSwitches; i++){
    pinMode(SwitchPins[i], INPUT_PULLUP);
    pinMode(LedPins[i], OUTPUT);
  }
  
  //wait and set mask based on input
  delay(5000);
  for(byte i = 0; i < NrSwitches; i++){
    mask[i] = !digitalRead(SwitchPins[i]); //sets presses switches to true
  }
}

void loop(){
  for(byte i = 0; i < NrSwitches; i++){
    if(!digitalRead(SwitchPins[i]) && mask[i]){ //aka button is pressed AND the mask was set during setup()
      digitalWrite(LedPins[i], HIGH);
    }
    else{
      digitalWrite(LedPins[i], LOW);
    }
    
    //or in single line:
    //digitalWrite(LedPins[i], !digitalRead(SwitchPins[i]) && mask[i]);
  }
}

Note, this assumes switches to GND!

It will be a variable number of buttons pressed, between 2 and 8.

I'm sorry but I don't understand what you mean by an "internal pull up".

How would I use arrays differently then I am currently?

Dracore:
I'm sorry but I don't understand what you mean by an "internal pull up".

Step 1: Remove the resistors to the switches
Step 2: Connect switch between pin an GND (instead of Vcc)
Step 3: Call pinMode(pin, INPUT_PULLUP)
Step 4: Expect a LOW when the button is pressed and a HIGH when it isn't.
Done :wink: No need for resistors

Dracore:
How would I use arrays differently then I am currently?

Like in my example. Just put everything directly in an array and use that to your advantage so you can index over it.

What is the advantage of doing so? What is wrong with using resistors?

Dracore:
What is the advantage of doing so? What is wrong with using resistors?

Nothing wrong, advantage is less work and less components :slight_smile:

Example code with mask (only no beep)

const byte SwitchPins[] =         {38, 40, 42, 44, 46, 48, 50, 52};
const byte NrSwitches = sizeof(SwitchPins);
const byte LedPins[NrSwitches] =  {39, 41, 43, 45, 47, 49, 51, 53};
const byte AnalogSeedPin = A0;

bool mask[NrSwitches];

byte currentPos;

void setup(){
  //set pinmodes
  for(byte i = 0; i < NrSwitches; i++){
    pinMode(SwitchPins[i], INPUT_PULLUP);
    pinMode(LedPins[i], OUTPUT);
  }
  
  //wait and set mask based on input
  delay(5000);
  for(byte i = 0; i < NrSwitches; i++){
    mask[i] = !digitalRead(SwitchPins[i]); //sets presses switches to true
  }
  
  randomSeed(analogRead(AnalogSeedPin));
  currentPos = random(0, NrSwitches);
}

void loop(){
  checkSwitches();
  updateLeds();
}

void updateLeds90{
  for(byte i = 0; i < NrSwitches; i++){
    digitalWrite(LedPins[i], i == currentPos);
  }
}

void checkSwitches(){
  if(!digitalRead(SwitchPins[currentPos])){
    while(!mask[++currentPos]){
      if(currentPos >= NrSwitches){
        currentPos = 0;
      }
    }
  }
}

Untested but you should get an idea :slight_smile:

Mm, yeah, problem is I overshoot the mask array..... No time to fix it now..

" I would like to make it so when the program starts up my buzzer plays a tone, and a certain number of buttons are pressed, and then 10 seconds later the buzzer plays a second tone and only the buttons pressed in between the two tones are the LEDs that get cycled through."

wow! I visualized this program, and it will work if there is enough memory! Assuming a data logger or store, and some scripting to alter the html inline codes, probably keystroke to memorize the buttons pressed, and no interference from me.... it just might work!

beep
keystroke n
input n
delay 5000//wait 5 seconds for input
if n NOEXIST
then //(do something)
else
keystroke as signifigator
For each LED in keystroke Next
LED HIGH
delay 1000/wait a second
LED ++
Loop not EOF

just a guess... not a pro

septillion:
Nothing wrong, advantage is less work and less components :slight_smile:

Example code with mask (only no beep)

const byte SwitchPins[] =         {38, 40, 42, 44, 46, 48, 50, 52};

const byte NrSwitches = sizeof(SwitchPins);
const byte LedPins[NrSwitches] =  {39, 41, 43, 45, 47, 49, 51, 53};
const byte AnalogSeedPin = A0;

bool mask[NrSwitches];

byte currentPos;

void setup(){
 //set pinmodes
 for(byte i = 0; i < NrSwitches; i++){
   pinMode(SwitchPins[i], INPUT_PULLUP);
   pinMode(LedPins[i], OUTPUT);
 }
 
 //wait and set mask based on input
 delay(5000);
 for(byte i = 0; i < NrSwitches; i++){
   mask[i] = !digitalRead(SwitchPins[i]); //sets presses switches to true
 }
 
 randomSeed(analogRead(AnalogSeedPin));
 currentPos = random(0, NrSwitches);
}

void loop(){
 checkSwitches();
 updateLeds();
}

void updateLeds90{
 for(byte i = 0; i < NrSwitches; i++){
   digitalWrite(LedPins[i], i == currentPos);
 }
}

void checkSwitches(){
 if(!digitalRead(SwitchPins[currentPos])){
   while(!mask[++currentPos]){
     if(currentPos >= NrSwitches){
       currentPos = 0;
     }
   }
 }
}




Untested but you should get an idea :)

Mm, yeah, problem is I overshoot the mask array..... No time to fix it now..

So I have changed my circuit, removing the resistors as you suggested and switching simply to pin to ground. I tried your code correcting this

septillion:

void updateLeds90{

to

void updateLeds(){

But I cannot really tell what its doing. After the 5 seconds has elapsed it randomly picks an LED (not necessarily one of the ones pressed in the set up) and then that LED's button does turn it off but no next LED is illuminated.

I simply don't understand your code enough to troubleshoot it and figure out the error.

Dracore:
correcting this to

void updateLeds(){

Oeps :stuck_out_tongue:

Dracore:
not necessarily one of the ones pressed in the set up

Ah, yeah, I forgot to filter for the random bit.

Dracore:
I simply don't understand your code enough to troubleshoot it and figure out the error.

The code is not all that hard IF you understand how to look over arrays. Which bit confuses you?

I made some changes. Yes, it's quite a bit longer but that's because of the comments and debug. Via Serial Monitor you're now able to see what it's doing.

const bool Debug = true;

const byte SwitchPins[] =         {38, 40, 42, 44, 46, 48, 50, 52};
const byte NrSwitches = sizeof(SwitchPins);
const byte LedPins[NrSwitches] =  {39, 41, 43, 45, 47, 49, 51, 53};
const byte AnalogSeedPin = A0;

bool mask[NrSwitches];

byte currentPos;

void setup(){
  //Setup Serial if we want to debug
  if(Debug){
    Serial.begin(115200);
  }
  
  //set pinmodes
  for(byte i = 0; i < NrSwitches; i++){
    pinMode(SwitchPins[i], INPUT_PULLUP);
    pinMode(LedPins[i], OUTPUT);
  }
  
  //debug to serial
  if(Debug){
    Serial.println(F("Press switches to use"));
  }
  
  //wait and set mask based on input
  delay(5000);
  for(byte i = 0; i < NrSwitches; i++){
    mask[i] = !digitalRead(SwitchPins[i]); //sets presses switches to true
  }
  
  //debug to serial
  if(Debug){
    Serial.print(F("Switches selected: "));
    for(byte i = 0; i < NrSwitches; i++){
      if(mask[i]){
        Serial.print(i);
        Serial.print(" ");
      }
    }
    Serial.println();
  }
  
  //Wait a little so you can release the switches
  delay(1000);
  
  randomSeed(analogRead(AnalogSeedPin));
  do{
    currentPos = random(0, NrSwitches);
  }
  //random again if we selected an inactive led
  while(!mask[currentPos]);
  
  //debug
  if(Debug){
    Serial.print(F("First led: "));
    Serial.println(currentPos);
  }
}

void loop(){
  checkSwitches();
  updateLeds();
}

void updateLeds(){
  for(byte i = 0; i < NrSwitches; i++){
    digitalWrite(LedPins[i], i == currentPos);
  }
}

void checkSwitches(){
  if(!digitalRead(SwitchPins[currentPos])){
    //if the correct switch is pressed, go to next
    do{
      currentPos++;
      //loop back if we're at the last
      if(currentPos > NrSwitches){
        currentPos = 0;
      }
    }
    //go to next again if we're now at an inactive led (mask = false)
    while(!mask[currentPos]);
    
    if(Debug){
      Serial.print(F("next led: "));
      Serial.println(currentPos);
    }
  }
}