Recording switch press sequences problem

Hello,
I'm trying to make a controller that records a switch press sequence on four switches and plays them back when triggered. I have went through several examples and tutorials trying to make this work and thought I had it down but when I upload and try and run the sketch it doesn't seem to work (I bet we are all very familiar with that :astonished:) I have been attempting to debug it for hours and cant seem to nail down how to fix the problem, though I think I know about where it is.
Project background:
There are 4 switches which are recorded, one for trigger, and one for record connected on pins 2-7. The switches are momentary NO tactile push-buttons. The LED's that indicate when a output is high are on 8-11, the record indicator light is on 12 and play indicator is on 13. When the record switch is pressed and released the arduino (duemilanove 328) records the sequence of the 4 programming switches storing the times they are pressed as well in a 2d array. When the trigger is pressed it plays back the switch sequence. All of the switches are on pullup resistors and wait for a LOW signal.
I have included the whole sketch below and have tried to comment it such that it is easy to follow.

// I/O pin varible config
int but1 = 2;
int but2 = 3;
int but3 = 4;
int but4 = 5;
int trig1= 6;  
int rec  = 7;
int out1 = 8;
int out2 = 9;
int out3 = 10;
int out4 = 11;
int pla_lite = 12;
int rec_lite = 13;
bool show_pres = false;
unsigned long  show_seq[100][3];
int rButState;
int tButState;
int but1State;
int but2State;
int but3State;
int but4State;

void setup(){
  //pinMode config
  pinMode(rec,INPUT);
  pinMode(but1,INPUT);
  pinMode(but2,INPUT);
  pinMode(but3,INPUT);
  pinMode(but4,INPUT);
  pinMode(trig1,INPUT);
  pinMode(out1,OUTPUT);
  pinMode(out2,OUTPUT);
  pinMode(out3,OUTPUT);
  pinMode(out4,OUTPUT);
  pinMode(rec_lite,OUTPUT);
  pinMode(pla_lite,OUTPUT);
  //read initial button states
  rButState = digitalRead(rec);
  tButState = digitalRead(trig1);
  but1State = digitalRead(but1);
  but2State = digitalRead(but2);
  but3State = digitalRead(but3);
  but4State = digitalRead(but4);

}

void loop(){
  int rval;                                                         //
  int rval2;
  int tval;
  int tval2;
  digitalWrite(out1, LOW);                                          //Make sure outputs are low
  digitalWrite(out2, LOW);
  digitalWrite(out3, LOW);
  digitalWrite(out4, LOW);                      
  tval = digitalRead(trig1);                                        //Read Trigger State
  delay(10);                                                        //Debounce
  tval2 = digitalRead(trig1);                                       //
  if (tval == tval2 && tval == LOW && tval != tButState && show_pres == true){     //Trigger show if one is recorded
    playShow();
    tButState = tval;
  }
  rval = digitalRead(rec);                                          //Read REC button state
  delay(10);                                                        //Debounce
  rval2 = digitalRead(rec);                                         //
  if (rval == rval2 && rval == LOW && rval != rButState){           //Record show
    recordShow();
    rButState = rval;
  }

}

void recordShow(){                                                  //Record show function
  int b1val;                                                        //---------------------
  int b1val2;                                                       //
  int b2val;                                                        //
  int b2val2;                                                       //
  int b3val;                                                        //Comparison values of buttons
  int b3val2;                                                       //for debounce
  int b4val;                                                        //
  int b4val2;                                                       //
  int rval;                                                         //
  int rval2;                                                        //---------------------
  unsigned long start_time = millis();                              //Log time recording starts
  bool isrec = true;
  memset(show_seq, 0, sizeof(show_seq[0][0])*300*3);                //Clear show
  int counter = 0;
  digitalWrite(rec_lite,HIGH);                                      //Turn on REC light
  while (isrec == true){                                            //Keep looping until record is pressed again
    b1val = digitalRead(but1);
    delay(10);
    b1val2 = digitalRead(but1);
    if (b1val == b1val2 && b1val == LOW && b1val != but1State){   //Is button 1 pressed?
      digitalWrite(out1, HIGH);                                   //Echo button press on output
      show_seq[counter][1] = out1;                                //Register the button pressed in 1st column
      if (counter == 0){
        show_seq[counter][2] = millis() - start_time;             //Register time until button is pressed from start if first button press
      }
      else{
        show_seq[counter][2] = millis() - show_seq[counter-1][3]; //Register time since last button press
      }
      while (digitalRead(but1)==0){
        delay(10);
      }                                                           //Wait until button is released
      show_seq[counter][3] = millis() -  show_seq[counter][2];    //Register time button is held
      digitalWrite(out1, LOW);
      counter++;
      but1State = b1val;
    }
  }
  b2val = digitalRead(but2);
  delay(10);
  b2val2 = digitalRead(but2);
  if (b2val == b2val2 && b2val == LOW && b2val != but2State){
    digitalWrite(out2, HIGH);
    show_seq[counter][1] = out2;
    if (counter == 0){
      show_seq[counter][2] = millis() - start_time; 
    }
    else{
      show_seq[counter][2] = millis() - show_seq[counter-1][3];
    }
    while (digitalRead(but1)==0){
      delay(10);
    }
    show_seq[counter][3] = millis() -  show_seq[counter][2];
    digitalWrite(out2, LOW);
    counter++;
    but2State = b2val;
  }
  show_pres = true;

  b3val = digitalRead(but3);
  delay(10);
  b3val2 = digitalRead(but3);
  if (b3val == b3val2 && b3val == LOW && b3val != but3State){
    digitalWrite(out3, HIGH);
    show_seq[counter][1] = out3;
    if (counter == 0){
      show_seq[counter][2] = millis() - start_time; 
    }
    else{
      show_seq[counter][2] = millis() - show_seq[counter-1][3];
    }
    while (digitalRead(but1)==0){
      delay(10);
    }
    show_seq[counter][3] = millis() -  show_seq[counter][2];
    digitalWrite(out3, LOW);
    counter++;
    but3State = b3val;
  }

  b4val = digitalRead(but4);
  delay(10);
  b4val2 = digitalRead(but4);
  if (b4val == b4val2 && b4val == LOW && b4val != but4State){
    digitalWrite(out4, HIGH);
    show_seq[counter][1] = out4;
    if (counter == 0){
      show_seq[counter][2] = millis() - start_time; 
    }
    else{
      show_seq[counter][2] = millis() - show_seq[counter-1][3];
    }
    while (digitalRead(but1)==0){
      delay(10);
    }
    show_seq[counter][3] = millis() -  show_seq[counter][2];
    digitalWrite(out4, LOW);
    counter++;
    but4State = b4val;
  }

  rval = digitalRead(rec);
  delay(10);
  rval2 = digitalRead(rec);
  if (rval == rval2 && rval == LOW && rval != rButState){                    //Trigger show if one is recorded
    isrec = false;
    rButState = rval;
  }

  digitalWrite(rec_lite,LOW);  
}

void playShow(){                                                    //Play the show function
  int counter = 0;
  digitalWrite(pla_lite,HIGH);                                      //Turn on play light
  while (show_seq[counter][1] > 0){                                 //Play show as long as there is a button value present
    delay(show_seq[counter][2]);
    digitalWrite(show_seq[counter][1], HIGH);
    delay(show_seq[counter][3]);
    digitalWrite(show_seq[counter][1], LOW);
    counter++;
  }
  digitalWrite(pla_lite,LOW);                                       //Turn off play light
}

I am not the best programmer so the code may not be very efficient and it might not follow proper code etiquette, but the problem seems to be in the playShow and recordShow functions and I may have not debounced properly because commenting the body's of the two if statements in the main loop and adding a command to send "test" to the serial monitor instead works. I modeled the debounce after the adafruit tutorial. I'm sure the mistake is elementary and noobish but appreciate any help anyone could give. I'm kinda at a brick wall on how to fix this.

unsigned long  show_seq[300][3];

300 * 3 * 4= ?

Which processor are you using?

the 328

So, of your 2048 bytes of RAM, you've reserved 3600 for this one array.

Ok, I changed that to a 100 element array. I'm an idiot, variables are stored in the RAM not flash, duh :blush:. But it still doesn't work.

Your code is very hard to follow, but when you get to writing stuff like the b4val = digitalRead(but4); and

int but1 = 2;
int but2 = 3;
int but3 = 4;
int but4 = 5;

int out1 = 8;
int out2 = 9;
int out3 = 10;
int out4 = 11;

repeatedly nearly always suggests that you should be using arrays for similar constructs.
Shorter code makes it easier to read, and gives the bugs fewer dark corners to hide in.

For the switches, you are not enabling the internal pull-up resistors, which suggests that you (should) have external pull-up or pull-down resistors. Do you?

      while (digitalRead(but1)==0){
        delay(10);
      }                                                           //Wait until button is released

Why would you want to wait for up to 10 milliseconds after the button is released to notice it?

I may have not debounced properly

There is a nice library that handles de-bouncing buttons. Why not use that library?

Ok, I cleaned it up with for loops. However it is still stuck in the record function only iterating the while loop once. Also once you press the buttons that turn on the outputs they only light up once. I think its where I'm trying to implement the debounce. I've been trying to sort this out all day and have had no luck. I hope its easier to follow now. Here's the code:

int button[] = {
  2,3,4,5};
int trig1= 6;  
int rec  = 7;
int LEDoutput[] = {
  8,9,10,11};
int pla_lite = 12;
int rec_lite = 13;
bool show_pres = false;
unsigned long  show_seq[100][3];
int rButState;
int tButState;
int buttonState[4];


void setup(){
  //pinMode config
  pinMode(rec,INPUT);
  pinMode(trig1,INPUT);
  
  for (int i = 0; i < 5; i++){
    pinMode(button[i],INPUT);
  }
  
  for (int i = 0; i < 5; i++){
    pinMode(LEDoutput[i],OUTPUT);
  }
  
  pinMode(rec_lite,OUTPUT);
  pinMode(pla_lite,OUTPUT);
  //read initial button states
  rButState = digitalRead(rec);
  tButState = digitalRead(trig1);
  
  for (int i = 0; i < 5; i++){
    buttonState[i] = digitalRead(button[i]);
  }

}

void loop(){
  int rval;                                                         //
  int rval2;
  int tval;
  int tval2;
  
  for (int i = 0; i < 5; i++){                                      //Make sure outputs are low
    digitalWrite(LEDoutput[i], LOW);
  }

  tval = digitalRead(trig1);                                        //Read Trigger State
  delay(10);                                                        //Debounce
  tval2 = digitalRead(trig1);                                       //

  if (tval == tval2 && tval == LOW && tval != tButState && show_pres == true){     //Trigger show if one is recorded
    playShow();
    tButState = tval;
  }

  rval = digitalRead(rec);                                          //Read REC button state
  delay(10);                                                        //Debounce
  rval2 = digitalRead(rec);                                         //

  if (rval == rval2 && rval == LOW && rval != rButState){           //Record show
    recordShow();
    rButState = rval;
  }

}

void recordShow(){                                                  //Record show function
  int buttonVal[4];                                              
  int buttonVal2[4];
  int rval;                                                         
  int rval2;                                                        
  unsigned long start_time = millis();                              //Log time recording starts
  bool isrec = true;
  memset(show_seq, 0, sizeof(show_seq[0][0])*100*3);                //Clear show
  int counter = 0;
  rButState = digitalRead(rec);
  digitalWrite(rec_lite,HIGH);                                      //Turn on REC light
  
  while (isrec == true){                                            //Keep looping until record is pressed again
    for (int i = 0; i <5; i++){

      buttonVal[i] = digitalRead(button[i]);                        //Debounce
      delay(10);
      buttonVal2[i] = digitalRead(button[i]);

      if (buttonVal[i] == buttonVal2[i] && buttonVal[i] == LOW && buttonVal[i] != buttonState[i]){   //Is button  pressed?
        digitalWrite(LEDoutput[i], HIGH);                            //Echo button press on output
        show_seq[counter][1] = LEDoutput[i];                         //Register the button pressed in 1st column

        if (counter == 0){
          show_seq[counter][2] = millis() - start_time;              //Register time until button is pressed from start if first button press
        }

        else{
          show_seq[counter][2] = millis() - show_seq[counter-1][3];  //Register time since last button press
        }

        while (digitalRead(button[i])==0){                          //Wait until button is released
          delay(10);
        }                                                           
        show_seq[counter][3] = millis() -  show_seq[counter][2];    //Register time button is held
        digitalWrite(LEDoutput[i], LOW);
        counter++;
        buttonState[i] = buttonVal[i];
      }
      rval = digitalRead(rec);
      delay(10);
      rval2 = digitalRead(rec);
      
      if (rval == rval2 && rval == LOW && rval != rButState){       //Exit out of record
        isrec = false;
        rButState = rval;
      }
    }



  }

  digitalWrite(rec_lite,LOW);  
}

void playShow(){                                                    //Play the show function
  int counter = 0;
  digitalWrite(pla_lite,HIGH);                                      //Turn on play light
  
  while (show_seq[counter][1] > 0){                                 //Play show as long as there is a button value present
    delay(show_seq[counter][2]);
    digitalWrite(show_seq[counter][1], HIGH);
    delay(show_seq[counter][3]);
    digitalWrite(show_seq[counter][1], LOW);
    counter++;
  }
  digitalWrite(pla_lite,LOW);                                       //Turn off play light
}

Sorry paul, I had that post written since earlier but didn't notice I hadn't submitted it and I didn't see your reply. Yes I have external pull-up resistors. And I'll check out the debounce library, maybe that will help me solve the problem. As far as the wait for 10ms its just an arbitrary small value I picked, its basically just to kinda pause the code there until the button is released for the purpose of recording the timing of the press.

ok, I checked out the Bounce library but am now really confused on how to use this with the array structure I've built for the buttons. I don't know how to do this with the objects the example said to create. Sorry if this seems real newbie but I'm not used to using objects and libraries.

Sorry if this seems real newbie but I'm not used to using objects and libraries.

I'll agree, perhaps, with the comment about libraries, but not to the part about objects. You use objects, like switches, all the time. The behavior associated with the object is all over the place, though.

The Button library, though, collects all the code in one place, and associates it with the object. You no longer have to ask the Arduino is the switch is pressed and was not pressed, after waiting a period of time.

Just create an instance of Bounce, associated with some pin and some interval (how long the switch might bounce).

Then, in loop, call update() and read() for each Bounce object you want to know the current state of.

Bounce sw1(button[0], 10);

void setup()
{
   pinMode(button[0], INPUT);
}

void loop()
{
   sw1.update();

   // some code

   int sw1state = sw1.read();
   if(sw1state == LOW)
   {
      // switch is pressed and done bouncing
   }
}

Ok, I got it working alot better. It records the button presses and will play them back, however it seems to mess the timing of the presses up upon playback. I have reviewed the code several times and cannot find out why its doing this. I believe it has something to do with the math to determine the length of the button presses and delay time between them because the play back gets slower the longer you wait from resetting the board as well as the delays getting longer the further into the "show" you get.
Here's the code for a button press and logging the times (each button is a copy of this with the variable names adjusted for the correct button)

//=============Record Show===========
void recordShow(){                                                  
  delay(250);
  unsigned long start_time = millis();                              //Log time recording starts
  bool isrec = true;                                                //Variable to keep recording until REC is pressed again
  memset(show_seq, 0, sizeof(show_seq[0][0])*100*3);                //Clear show
  int counter = 0;                                                  //Counter for show_seq indexing
  digitalWrite(rec_lite,HIGH);                                      //Turn on REC light

  while (isrec == true){                                            //Keep looping until REC is pressed again

    //----------Button 1-------------
    button1.update ();

    int but1state = button1.read ();
    if (but1state == LOW){                                         //Is button pressed?
      digitalWrite(LEDoutput[0], HIGH);                            //Echo button press on output
      show_seq[counter][0] = LEDoutput[0];                         //Register the button pressed in 1st column

      if (counter == 0){
        show_seq[counter][1] = millis() - start_time;              //Register time until button is pressed from start if first button press 2nd column
      }

      else{
        show_seq[counter][1] = millis() - show_seq[counter-1][2];  //Register time since last button press
      }

      while (digitalRead(button[0])==0){                           //Wait until button is released
        delay(10);
      }                                                           
      show_seq[counter][2] = millis() -  show_seq[counter][1];     //Register time button is held 3rd column
      digitalWrite(LEDoutput[0], LOW);
      counter++;
    }

And here's the code for the playback:

//============Play Show============
void playShow(){                                                    
  int counter = 0;
  digitalWrite(pla_lite,HIGH);                                      

  while (show_seq[counter][0] > 0){                                 //Play show as long as there is a button value present
    delay(show_seq[counter][1]);                                    
    digitalWrite(show_seq[counter][0], HIGH);
    delay(show_seq[counter][2]);
    digitalWrite(show_seq[counter][0], LOW);
    counter++;
  }
  digitalWrite(pla_lite,LOW);                                       //Turn off play light
}

Let me know if you want to see the entire program.

I fixed it and its running great. For those interested, here's the code:

#include <Bounce.h>
// Program: Programmable Controller

//  Date: 7-10-2011
//  Version: 1.6


// I/O pin varible config
const int button[] = {
  2,3,4,5};
const int trig1= 6;  
const int rec  = 7;
const int LEDoutput[] = {
  8,9,10,11};
const int pla_lite = 12;
const int rec_lite = 13;
bool show_pres = false;
unsigned long  show_seq[100][3];
Bounce button1 = Bounce(button[0],5);
Bounce button2 = Bounce(button[1],5);
Bounce button3 = Bounce(button[2],5);
Bounce button4 = Bounce(button[3],5);
Bounce recbutton = Bounce(rec,5);
Bounce trigbutton = Bounce(trig1,5);


//========SETUP=============
void setup(){
  //pinMode config
  pinMode(rec,INPUT);
  pinMode(trig1,INPUT);

  for (int i = 0; i < 4; i++){
    pinMode(button[i],INPUT);
  }

  for (int i = 0; i < 4; i++){
    pinMode(LEDoutput[i],OUTPUT);
  }

  pinMode(rec_lite,OUTPUT);
  pinMode(pla_lite,OUTPUT);

}


//============Main Loop===============
void loop(){
  int rval;                                                         //
  int tval;


  for (int i = 0; i < 4; i++){                                      //Make sure outputs are low
    digitalWrite(LEDoutput[i], LOW);
  }

  //------------Trigger Show Button------------
  trigbutton.update ( );

  tval = trigbutton.read();                                        //Read Trigger State

  if (tval == LOW && show_pres == true){                           //Trigger show if one is recorded
    playShow();
  }

  //------------Record Show Button------------
  recbutton.update ();

  rval = recbutton.read ();                                          //Read REC button state

  if (rval == LOW){           //Record show
    recordShow();
  }

}


//=============Record Show===========
void recordShow(){                                                  
  delay(250);
  bool isrec = true;                                                //Variable to keep recording until REC is pressed again
  memset(show_seq, 0, sizeof(show_seq[0][0])*100*3);                //Clear show
  int counter = 0;                                                  //Counter for show_seq indexing
  digitalWrite(rec_lite,HIGH);                                      //Turn on REC light
  unsigned long start_time = millis();                              //Log time recording starts
  unsigned long now = 0;
  unsigned long prev = 0;
  while (isrec == true){                                            //Keep looping until REC is pressed again

    //----------Button 1-------------
    button1.update ();

    int but1state = button1.read ();
    if (but1state == LOW){                                         //Is button pressed?
      digitalWrite(LEDoutput[0], HIGH);                            //Echo button press on output
      show_seq[counter][0] = LEDoutput[0];                         //Register the button pressed in 1st column
      now = millis();
      if (counter == 0){
        show_seq[counter][1] = millis() - start_time;              //Register time until button is pressed from start if first button press 2nd column
      }

      else{
        show_seq[counter][1] = millis() - prev;  //Register time since last button press
      }

      while (digitalRead(button[0])==0){                           //Wait until button is released
        delay(10);
      }                                                           
      show_seq[counter][2] = millis() -  now;     //Register time button is held 3rd column
      digitalWrite(LEDoutput[0], LOW);
      prev = millis();
      counter++;
    }


    //---------------Button 2----------------
    button2.update ();

    int but2state = button2.read ();
    if (but2state == LOW){  
      digitalWrite(LEDoutput[1], HIGH);                            
      show_seq[counter][0] = LEDoutput[1];                         
      now = millis();

      if (counter == 0){
        show_seq[counter][1] = millis() - start_time;              
      }

      else{
        show_seq[counter][1] = millis() - prev;  
      }

      while (digitalRead(button[1])==0){                          
        delay(10);
      }                                                           
      show_seq[counter][2] = millis() -  now;    
      digitalWrite(LEDoutput[1], LOW);
      prev = millis();
      counter++;
    }      

    //---------------Button 3----------------
    button3.update ();

    int but3state = button3.read ();
    if (but3state == LOW){   
      digitalWrite(LEDoutput[2], HIGH);                            
      show_seq[counter][0] = LEDoutput[2];                         
      now = millis();

      if (counter == 0){
        show_seq[counter][1] = millis() - start_time;              
      }

      else{
        show_seq[counter][1] = millis() - prev;  
      }

      while (digitalRead(button[2])==0){                          
        delay(10);
      }                                                           
      show_seq[counter][2] = millis() -  now;    
      digitalWrite(LEDoutput[2], LOW);
      prev = millis();
      counter++;
    }      


    //---------------Button 4----------------
    button4.update ();

    int but4state = button4.read ();
    if (but4state == LOW){   
      digitalWrite(LEDoutput[3], HIGH);                            
      show_seq[counter][0] = LEDoutput[3];                         
      now = millis();

      if (counter == 0){
        show_seq[counter][1] = millis() - start_time;              
      }

      else{
        show_seq[counter][1] = millis() - prev;  
      }

      while (digitalRead(button[3])==0){                          
        delay(10);
      }                                                           
      show_seq[counter][2] = millis() -  now;    
      digitalWrite(LEDoutput[3], LOW);
      prev = millis();
      counter++;
    }

    //----------------Exit Record Button-------------
    recbutton.update ();

    int recState = recbutton.read ();

    if (recState == LOW){                                              //Exit out of record
      isrec = false;
      delay(250);
    }
  }
  digitalWrite(rec_lite , LOW);
  show_pres = true;
}



//============Play Show============
void playShow(){                                                    
  int counter = 0;
  digitalWrite(pla_lite,HIGH);                                      

  while (show_seq[counter][0] > 0){                                 //Play show as long as there is a button value present
    delay(show_seq[counter][1]);                                    
    digitalWrite(show_seq[counter][0], HIGH);
    delay(show_seq[counter][2]);
    digitalWrite(show_seq[counter][0], LOW);
    counter++;
  }
  digitalWrite(pla_lite,LOW);                                       //Turn off play light
}

Attached is the board setup (as good as I could draw it in Fritzing)

The array that I store the sequence in is a 100x3 2D unsigned long array. This needs to be stored into non-volatile memory so the board can be turned off and it still remembers the sequence when turned back on. I don't see this sequence being rewritten over 1000 times at max so I'm not worried about exceeding the rewrite limits of either the flash or EEPROM. At 100x3 it will have to be cut down a bit to (75x3 maybe) to fit into the EEPROM but I don't think I'll have to cut it down to fit into the flash as the program itself shouldn't use more than about 8K.
For the EEPROM, I kinda understand Halley's templates here: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1234477290/3#11
But for writing to flash I am having a harder time understanding how to implement the example here: Frequently Asked Questions as it seems that you have to know the contents of the array when setting up the global constants.
Any help would be appreciated.

The array that I store the sequence in is a 100x3 2D unsigned long array.

Flash storage is read-only. The need to overwrite values in the array precludes storing it in flash memory. Therefore, you don't need to understand how to do it.

Ah, Ok. I misunderstood what was going on there. Sorry, I should have read that page I linked a bit closer.. "There are times when you may need an array of strings which will never be modified." :blush:
I'll probably be back with more dumb questions later.. Thanks Paul.