Simple pattern output via an array

Hi all,

I'm new to the forums and it's good to be here!

So I've wired up 3 single colour LEDs and 3 push buttons.
At the moment my goal is to make the LEDs flash in a particular pattern, constantly. Later I hope to ask a participant to push the buttons in time with the LEDs but my first hurdle appears to be making the pattern work.

The pattern is very regular and loops ad infinitum. I found a tutorial about using arrays to make patterns (it was the KITT tutorial from Knight Rider) which makes the LEDs light up back and forth in a row. The pattern I have is more abstract than that and I found a tutorial that seemed to make it easy to do this, and ended up writing the code below.

const int ledPin1 = 10; //define the led pins
const int ledPin2 = 11;
const int ledPin3 = 12;
const int switchPin1 = 1; //define the button pins
const int switchPin2 = 2;
const int switchPin3 = 3;
int timer = 100; //set the speed for the pattern to be displayed
int ledPins[] = {10, 11, 12}; //define the led pins
int pinCount = 3; //define the number of leds

void setup()
{
int pinArray[8, 3] = //set the array as 8 rows and 3 columns
  {
    {1, 0, 0}, //define the pattern in which the leds should light up
    {0, 1, 0},
    {0, 0, 1},
    {0, 1, 0},
    {1, 0, 0},
    {0, 1, 0},
    {0, 0, 1},
    {0, 1, 0}
  }
  pinMode(ledPin1, OUTPUT);  //define the pin modes
  pinMode(ledPin2, OUTPUT);
  pinMode(ledPin3, OUTPUT);
  pinMode(switchPin1, INPUT);
  pinMode(switchPin2, INPUT);
  pinMode(switchPin3, INPUT);
}

void loop()
{
  for(row = 0; row <= 7; row ++)  //tell the program to cycle through the rows of the array
  {
    digitalWrite(10, array[row, 0]);
    digitalWrite(11, array[row, 1]);
    digitalWrite(12, array[row, 2]);
    delay(100);
  }
}

I realise there might be more code than is necessary in it, and the pattern in the array is just a test. The error I keep getting out is this:

JGL_Code.cpp: In function 'void setup()':
JGL_Code:12: error: expected ]' before ',' token JGL_Code:12: error: expected unqualified-id before numeric constant JGL_Code:40: error: expected }' at end of input

directed at the line ' int pinArray[8, 3] ='

I'm sorry that the code is such a mess. I'm new to programming and at the moment I'm feeling my way through the tutorials. If anyone can help me out with this I'd be really grateful.

Happy to answer any questions...

Cheers!

First issue is your array syntax: multidimensional arrays in c use int myArray[8][3], not myArray[8,3] as in basic. This applies equally when you access the array elements in your loop()

Declaring the array inside setup makes it visible only in setup, move it above so that it'll be accessible in loop() too. Add a semicolon after the declaration.

in loop, row is not defined. Also, you're referring to your array as array here, but (once you've moved it out of setup) you'll need to refer to it as pinArray.

That should get you to the point where it complies at least :wink:

Thanks Bill,

I finally managed to get this working (actually managed it myself so I'm quite chuffed) but you were spot on with what the problems were that I was having.

Is it possible to reference an array at a certain point in order to satisfy an if statement?
For instance:

I have got a button for each of my 3 LEDs. I am trying to write code such that when an LED is lit, and the button associated with it is pressed within a set time of it lighting (say 500ms), one point is added to a running score. The way I envisage this happening is by using an if statement to say, if button1 = LOW (because it is pushed) && LED1 = HIGH then add a point to the score. Because the array will be outputting a signal for LED1 to be HIGH then am I able to use this as a trigger, or do I have to be more specific?

Be careful with the & and && and also = and ==.
What you describe sound feasible, something along these lines.

if ((button1 == LOW) && (array[LED1] == HIGH)){
score = score+1;
}

The extra ( )s will help keep your code & logic straight.

Thanks for the info CrossRoads.

My struggle continues... here is the latest:

const int ledPin1 = 10;
const int ledPin2 = 11;
const int ledPin3 = 12;
const int switchPin1 = 1;
const int switchPin2 = 2;
const int switchPin3 = 3;
int row = 0;
int score = 0;
int array[8][3] =
  {
    {1, 0, 1},
    {0, 1, 0},
    {1, 0, 1},
    {0, 1, 0},
    {1, 0, 1},
    {0, 1, 0},
    {1, 0, 1},
    {0, 1, 0},
  };


void setup()
{
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  pinMode(ledPin3, OUTPUT);
  pinMode(switchPin1, INPUT);
  pinMode(switchPin2, INPUT);
  pinMode(switchPin3, INPUT);
}

void loop()
{   
  for(row = 0; row <= 7; row ++)
  {
    digitalWrite(10, array[row] [0]);
    digitalWrite(11, array[row] [1]);
    digitalWrite(12, array[row] [2]);
    delay(500);   
  }
  int val1 = 0;
  int val2 = 0;
  int val3 = 0;
  do
  {
    val1 = digitalRead(switchPin1); val2 = digitalRead(switchPin2); val3 = digitalRead(switchPin3);
  }
  while (val1 == HIGH && val2 == HIGH && val3 == HIGH);
  if((val1 == LOW)&&(array[0]==HIGH));
  {
    score++;
  }
  else if((val2 == LOW)&&(array[1]==HIGH));
  {
    score++;
  }
  else if((val3 == LOW)&&(array[2]==HIGH));
  {
    score++;
  }
}

And the latest error messages...

JGL_Code.cpp: In function 'void loop()':
JGL_Code:48: error: ISO C++ forbids comparison between pointer and integer
JGL_Code:52: error: 'else' without a previous 'if'
JGL_Code:52: error: ISO C++ forbids comparison between pointer and integer
JGL_Code:56: error: 'else' without a previous 'if'
JGL_Code:56: error: ISO C++ forbids comparison between pointer and integer

I'm not sure how it will be possible to get around the direct comparison between the array and the button push. I wondered if I could output the array value as a HIGH/LOW value for comparison, but I wasn't sure how to go about that. Do I need an intermediary conversion step that reads the value at a particular point in an array and then outputs it as a different kind of value? I think I know what I want/need to do but I'm not sure how to code it.

I'll be very grateful for any help on this... cheers!

This:

  if((val1 == LOW)&&(array[0]==HIGH));

Has a couple of problems. The semicolon should not be there. The compiler reads it as if(Condition), do nothing. Then it runs the block underneath regardless. Then when it later sees an else, it is bewildered.

Your array has two dimensions. Here you only supplied one, and as you see, the compiler does not like that.

Thanks bill, you were spot on.

The code now compiles, although I'm still working through the logic as it's not doing what I want it to at present. Think I might have to replace the delay() command with a millis() one so that I can register the button pushes while the flashing is happening. One odd thing is that I rigged up the SerialMonitor to display the accumulated score that the player has got. At the moment the pattern is only running through once, and once it reaches the 8th flash it runs into the if statements and stops until any of the buttons is pushed, then the loop starts again and the SM displays '4' as the score. Once the loop comes back around and another button is pushed it adds a further '4' onto the score (and displays '8'). This happens ad infinitum, regardless of whether the player has pushed the buttons at the correct time or not...

const int ledPin1 = 10; //assign all the components to their relevant pins
const int ledPin2 = 11;
const int ledPin3 = 12;
const int switchPin1 = 1;
const int switchPin2 = 2;
const int switchPin3 = 3;
void(* resetFunc) (void) = 0; //set up reset function
int row = 0; //set aside memory for the row of the array to progress with time
int score = 0; //set aside memory for the score to be added to
int array[8][3] =    // set up the array which dictates the pattern in which the LEDs will flash
  {
    {1, 0, 1},
    {0, 1, 0},
    {1, 0, 1},
    {0, 1, 0},
    {1, 0, 1},
    {0, 1, 0},
    {1, 0, 1},
    {0, 1, 0},
  };


void setup()
{
  Serial.begin(9600); //set up the Serial Monitor
  pinMode(ledPin1, OUTPUT); // designate inputs and outputs
  pinMode(ledPin2, OUTPUT);
  pinMode(ledPin3, OUTPUT);
  pinMode(switchPin1, INPUT);
  pinMode(switchPin2, INPUT);
  pinMode(switchPin3, INPUT);
}

void loop()
{   
  for(row = 0; row <= 7; row ++)  //begin counting through the array from row 1 to row 8 to flash the LEDs
  {
    digitalWrite(10, array[row] [0]); //write column 0 to the LED on pin 10
    digitalWrite(11, array[row] [1]); //write column 1 to the LED on pin 11
    digitalWrite(12, array[row] [2]); //write column 2 to the LED on pin 12
    delay(1000);   //slow the flashes down - I would like to be able to do this without delay() so that 
  }                    //the button pushes can be registered
  int val1 = 0;  //set aside memory for the button pushes to be stored after digitalRead
  int val2 = 0;
  int val3 = 0;
  do
  {
    val1 = digitalRead(switchPin1); val2 = digitalRead(switchPin2); val3 = digitalRead(switchPin3);
  }
  while (val1 == HIGH && val2 == HIGH && val3 == HIGH); //if all the buttons are unpressed proceed
  for(row = 0; row <= 7; row++) //while cycling through the rows of the array
  {
    if((val1 == LOW)&&(array[row][0]==HIGH)) //when button (1) is pressed at the same time as LED (10) is
    {                                                          //switched on in the sequence, add a point to the score
      score++;
    }
    else if((val2 == LOW)&&(array[row][1]==HIGH)) //when button (1) is pressed at the same time as LED
    {                                                                //(11) switched on in sequence add a point to the score
      score++;
    }
    else if((val3 == LOW)&&(array[row][2]==HIGH)) //when button (1) is pressed at the same time as LED
    {                                                                //(12) switched on in sequence add a point to the score
      score++;
    }
    else
    {
      digitalWrite(ledPin1, HIGH);
      digitalWrite(ledPin2, HIGH);
      digitalWrite(ledPin3, HIGH);
      delay(3000);
    }
  }
  Serial.print(score); //show accumulated score of the player
}

How will the switches get read again once you get into the the while loop?

  {
    val1 = digitalRead(switchPin1); val2 = digitalRead(switchPin2); val3 = digitalRead(switchPin3);
  }
  while (val1 == HIGH && val2 == HIGH && val3 == HIGH); //if all the buttons are unpressed proceed

seems like the {val1 = digitalRead ...} section needs to follow the while:

while (val1 == 1 ...){read the switches again ...}

Your For loop & array could really just be from 0 to 1 as your data array is only 010 or 101 & just repeat four times. Simplify.

How will the switches get read again once you get into the the while loop?

Every time through.

do
  {
    val1 = digitalRead(switchPin1); val2 = digitalRead(switchPin2); val3 = digitalRead(switchPin3);
  }
  while (val1 == HIGH && val2 == HIGH && val3 == HIGH);

Then the while (val1 == ...) does nothing at all? It just goe to the next statement no matter what?

Does this
http://arduino.cc/en/Reference/DoWhile
help?

Yes - missed that.
Was thinking more like

while (val1 == 1 ...)
{read the swithces;}

Seems like same thing but written backwards.

Not the same thing at all; "do..while" will execute the body of the loop at least once, whereas a "while" loop may not execute the body at all.

As you surmised, you need to use millis. Currently, your code cycles the leds through all the patterns, then reads the buttons. Then you check each pattern to see if the led corresponding to the button press was lit. At this point, it's too late, the cycle of patterns is over. The pinArray data has a 1 set in four positions in each column, so whichever button is pressed, there will be four matches, hence the score increments in fours.

You need to display a pattern on the leds, then check the buttons for that pattern only & then set the score. Millis will let you do this. The blink without delay tutorial will give you the idea.

Ok, latest update.

Firstly, to answer the point about the repeating pattern - At the moment that pattern is a placeholder for a more advanced pattern that I'm going to put in later, but I take your point.

I had a look at the BlinkWithoutDelay tut and entered in the millis() code, so that it now looks like this...

const int ledPin1 = 10;
const int ledPin2 = 11;
const int ledPin3 = 12;
const int switchPin1 = 1;
const int switchPin2 = 2;
const int switchPin3 = 3;
long previousMillis = 0; //set aside memory space for the previous time before loop
long interval = 1000; //set the determinant interval at 1000, the same flash rate as with the delay
int row = 0;
int score = 0;
int array[8][3] =
  {
    {1, 0, 1},
    {0, 1, 0},
    {1, 0, 1},
    {0, 1, 0},
    {1, 0, 1},
    {0, 1, 0},
    {1, 0, 1},
    {0, 1, 0},
  };


void setup()
{
  Serial.begin(9600);
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  pinMode(ledPin3, OUTPUT);
  pinMode(switchPin1, INPUT);
  pinMode(switchPin2, INPUT);
  pinMode(switchPin3, INPUT);
}

void loop()
{ 
    long currentMillis = millis(); //count how many ms have passed since loop began and assign the value
    if(currentMillis - previousMillis > interval) //figure out if enough time has passed to continue the loop
    {
      previousMillis = currentMillis; //assign the ms passed until looping as the new previousMillis value
    for(row = 0; row <= 7; row ++) //proceed onto the patterning code for the flashing LEDs
    {
      digitalWrite(10, array[row] [0]);
      digitalWrite(11, array[row] [1]);
      digitalWrite(12, array[row] [2]);
    }
    int val1 = 0;
    int val2 = 0;
    int val3 = 0;
    do
    {
      val1 = digitalRead(switchPin1); val2 = digitalRead(switchPin2); val3 = digitalRead(switchPin3);
    }
    while (val1 == HIGH && val2 == HIGH && val3 == HIGH);
    for(row = 0; row <= 7; row++)
    {
      if((val1 == LOW)&&(array[row][0]==HIGH))
      {
        score++;
      }
      else if((val2 == LOW)&&(array[row][1]==HIGH))
      {
        score++;
      }
      else if((val3 == LOW)&&(array[row][2]==HIGH))
      {
        score++;
      }
      Serial.print(score);
     }
    }
  }

I feel like it should be working with the millis stuff added in, but it seems to just be freezing up now, on the 2nd line of the array pattern. The LED on pin 11 is brightly illuminated with the LEDs on pins 10 and 12 flashing dimly and regularly, presumably at 1000ms intervals.

The switches seem to have no effect. I'm wondering if the do...while command is contradicting the qualifying sections of my code. I think this because in order for the code to proceed it's saying that all the buttons must be registered as HIGH. However, in order for the player to proceed they must push the buttons LOW at the same time as the LEDs are on. The two can't happen at the same time and so I'm thinking that might be a big flaw in the logic.

At the moment I am so very, very confused. Apologies for constantly posting this but it feels like it's nearly there.

Get rid of your two for loops that iterate through all your rows - you're still doing all the patterns without reading the buttons. Literally, just delete those two lines. When millis tells you it's time to change patterns, increment row. Don't forget to set it back to zero once it hits seven. An if statement can do this, or if you want to, there's always the modulus operator (%), which is less code, but looks a little more obscure.

Wow, that's cool. The scoring system is now totally working (thank you for the tips about the for loops) and that's brilliant :).

The LEDs are now static (as they obviously aren't progressing through the array now that the for loops are gone) so I'll work on trying to get the millis() to advance through the pattern as you've suggested.

Thanks!

Ok, latest update!

I've been playing with the modulo statement and, while I've gotten somewhere, it's still not flashing.
I've managed to make the flashing proceed 1 step at a time, but I'm having to push buttons to make the LEDs progress through the array pattern. I focused on the 'row' and incrementing it using modulo.

At present the code looks like this:

const int ledPin1 = 10;
const int ledPin2 = 11;
const int ledPin3 = 12;
const int switchPin1 = 2;
const int switchPin2 = 3;
const int switchPin3 = 4;
long previousMillis = 0;
long interval = 1000;
int row = 0; //I'm using this to try and increment the array rows
int score = 0;
int array[8][3] =
  {
    {1, 0, 1},
    {0, 1, 0},
    {1, 0, 1},
    {0, 1, 0},
    {1, 0, 1},
    {0, 1, 0},
    {1, 0, 1},
    {0, 1, 0},
  };


void setup()
{
  Serial.begin(9600);
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  pinMode(ledPin3, OUTPUT);
  pinMode(switchPin1, INPUT);
  pinMode(switchPin2, INPUT);
  pinMode(switchPin3, INPUT);
}

void loop()
{ 
    int previousRow = row + 1; //I created this to use as a difference for the progression
    long currentMillis = millis();
    if(currentMillis - previousMillis > interval)
    {
      previousMillis = currentMillis;
      row = (previousRow + 8) & 7; //this line raises the value of 'row' by 1 each new loop
      if(row == 8) //these 3 lines are to make sure that when row hits 8 it is reset to line 0
      {
        row = 0;
      }
    {
      digitalWrite(10, array[row] [0]);
      digitalWrite(11, array[row] [1]);
      digitalWrite(12, array[row] [2]);
    }
    int val1 = 0;
    int val2 = 0;
    int val3 = 0;
    do
    {
      val1 = digitalRead(switchPin1); val2 = digitalRead(switchPin2); val3 = digitalRead(switchPin3);
    }
    while (val1 == HIGH && val2 == HIGH && val3 == HIGH);
    {
      if((val1 == LOW)&&(array[row][0]==HIGH))
      {
        score++;
      }
      else if((val2 == LOW)&&(array[row][1]==HIGH))
      {
        score++;
      }
      else if((val3 == LOW)&&(array[row][2]==HIGH))
      {
        score++;
      }
      Serial.print(score);
     }
    }
  }

At the moment the code is loading up with row2 as the first lit LED. When I press any of the buttons (not just the one relating to LED 2) the pattern progresses to the next line and then after a pause of 1000ms it progresses onto the next line, and then the progression halts for some reason until the next button press. I'm not sure why this is. This freeze is the last hurdle...

Try making long assignments
unsigned long

move this stuff
int val1 = 0;
int val2 = 0;
int val3 = 0;
up before setup. You don't need to set them low right before reading them. They will be High or Low from the read.

this one too
unsigned long currentMillis = 0;

then start loop with

currentMillis = millis();

I have also had occurrence where doing all this as 1 step would not work:
if(currentMillis - previousMillis > interval)

and I had to resort to
elapsedMillis = currentMillis - previousMillis;
if (elapsedMillis >=interval) {
next steps ...
}
I don't know why.

Wow, really feel like I'm earning this Newbie tag big-time.

CrossRoads, all those modifications you recommended worked out really nicely. The LEDs now cycle through the pattern (although for some reason the interval between flashes varies a little each time - I guess this makes sense as it's polling at different times each time rather than having a set time like with the delay() function) which is great, so thanks.

I got rid of the while() loop as I realised that that was the thing stopping the looping as it would only proceed through the code once a button was pressed. The LEDs now flash as they're meant to, and they output a score to the SM which is great. One final problem I'm having is that when I press the buttons the flash rate of the LEDs slows down a fair bit. Does anyone know why this might be?

The (nearly) finalised code:

const int ledPin1 = 10;
const int ledPin2 = 11;
const int ledPin3 = 12;
const int switchPin1 = 2;
const int switchPin2 = 3;
const int switchPin3 = 4;
unsigned long previousMillis = 0;
unsigned long interval = 1000; //pattern progression delay
unsigned long currentMillis = 0;
unsigned long elapsedMillis = 0;
int row = 0;
int score = 0;
int val1 = 0;
int val2 = 0;
int val3 = 0;
int array[8][3] =
  {
    {1, 0, 1},
    {0, 1, 0},
    {1, 0, 1},
    {0, 1, 0},
    {1, 0, 1},
    {0, 1, 0},
    {1, 0, 1},
    {0, 1, 0},
  };


void setup()
{
  Serial.begin(9600);
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  pinMode(ledPin3, OUTPUT);
  pinMode(switchPin1, INPUT);
  pinMode(switchPin2, INPUT);
  pinMode(switchPin3, INPUT);
}

void loop()
{ 
    currentMillis = millis();
    int previousRow = row + 1;
    row = (previousRow + 8) & 7; //the code used to cycle through the pattern in the array
      if(row == 8)
      {
        row = 0;
      }
    elapsedMillis = currentMillis - previousMillis;
    if(elapsedMillis >= interval)
    {
      previousMillis = currentMillis;
    {
      digitalWrite(10, array[row] [0]);
      digitalWrite(11, array[row] [1]);
      digitalWrite(12, array[row] [2]);
    }
      val1 = digitalRead(switchPin1); val2 = digitalRead(switchPin2); val3 = digitalRead(switchPin3);
    {
      if((val1 == LOW)&&(array[row][0]==HIGH) && (val3 == LOW) && (array[row][2]==HIGH)) //if buttons 1&3 are pushed down and LEDs 1&3 is lit, add a point to the score
      {
        score++;
        Serial.print(score); //print the score to the SM
      }
      else if((val2 == LOW)&&(array[row][1]==HIGH)) //if button 2 is pushed down and LED 2 is lit, add a point to the score
      {
        score++;
        Serial.print(score); //print the score to the SM
      }
      
     }
    }
}

I'm thinking I'm going to debounce the push buttons to make everything run a little smoother. I hope that this will also stop the repeated scores from showing up on the SM. At the moment when the button is pushed during an LED being lit, the system slows down and up to 3 points can be added successively to the tally. Debouncing should stop this...