Reading a sequential text file from an SD card for LED sequence

Hello everyone. I have written a program that uses a simple hardware interface with one button, which when pressed by the user, initiates a sequence of flashing LEDs over a short time and only after an elapsed period of pause. The user then cannot press the button to create another sequence within the specified pause time, which I have set to 10 seconds. There are also two separate LEDs to show whether the pause has elapsed, i.e. if the system is "armed."

I created my LED sequence with a function in my program that uses delays and HIGH/LOW to create the LED flashes. I would instead like to read text files from an SD card, and have my program sequenctially pick from these files to generate the sequence of lights.

Here's my program:

#include <Bounce.h>

int MAST = 2; //mast
int YAPORT = 3; //yardarm port side
int YASTBD = 4; //yardarm starboard side
int BOW = 5; //bow

int REDled = 8;
int GREENled = 7;
int ARMED = 0;

//Sequence
int SEQUENCEbutton = 10;
unsigned long SequenceLastFired;

//sequence reset time, during which sequence button will not work after pressed (should be eventually set to 15 minutes)
int SequenceResetTime = 10000;

//button debouncing
Bounce SEQUENCEbouncer = Bounce (SEQUENCEbutton,1);

void setup () 
{
  pinMode (MAST, OUTPUT);
  pinMode (BOW, OUTPUT);
  pinMode (YAPORT, OUTPUT);
  pinMode (YASTBD, OUTPUT);
    
  pinMode (SEQUENCEbutton, INPUT);
  
  digitalWrite (MAST, LOW);
  digitalWrite (BOW, LOW);
  digitalWrite (YAPORT, LOW);
  digitalWrite (YASTBD, LOW);
  
  Serial.begin (9600);
  
}

void loop ()
{
   
  if (ARMED == 0)
  {
   digitalWrite (REDled, HIGH); 
   digitalWrite (GREENled, LOW);
   }
  
  if (ARMED == 1)
  {
    digitalWrite (REDled, LOW);
    digitalWrite (GREENled, HIGH);
  }
  
 if ((millis() - SequenceLastFired) > SequenceResetTime)
 {
    ARMED = 1;
 }
 else
 {
  ARMED = 0; 
 }
  
    //check for button presses
  SEQUENCEbouncer.update();
  int SEQUENCEbuttonState = SEQUENCEbouncer.read();
  if (SEQUENCEbuttonState == HIGH && (millis() - SequenceLastFired > SequenceResetTime))
  {
  SEQUENCEfire();
  }
    
    
    Serial.println (ARMED);
       
}

//=======================SEQUENCE CODE===============================
void SEQUENCEfire ()
{
  ARMED = 0;
  digitalWrite (REDled, HIGH);
  digitalWrite (GREENled, LOW);
  
  //FOGHORN CODE HERE?
  
  delay (1000);
  digitalWrite (MAST, HIGH);
  delay (100);
  digitalWrite (MAST, LOW);
  delay (800);
  digitalWrite (BOW, HIGH);
  delay (100);
  digitalWrite (BOW, LOW);
  delay (300);
  digitalWrite (MAST, HIGH);
  digitalWrite (BOW, HIGH);
  delay (100);
  digitalWrite (MAST, LOW);
  digitalWrite (BOW, LOW);
  delay (450);
  digitalWrite (MAST, HIGH);
  delay (100);
  digitalWrite (MAST, LOW);
  delay (1200);
  digitalWrite (BOW, HIGH);
  delay (100);
  digitalWrite (BOW, LOW);
  delay (950);
  digitalWrite (MAST, HIGH);
  digitalWrite (BOW, HIGH);
  delay (100);
  digitalWrite (MAST, LOW);
  digitalWrite (BOW, LOW);
  delay (250);
  digitalWrite (MAST, HIGH);
  digitalWrite (BOW, HIGH);
  delay (100);
  digitalWrite (MAST, LOW);
  digitalWrite (BOW, LOW);
  delay (250);
  digitalWrite (MAST, HIGH);
  digitalWrite (BOW, HIGH);
  delay (100);
  digitalWrite (MAST, LOW);
  digitalWrite (BOW, LOW);
  delay (250);
  digitalWrite (MAST, HIGH);
  digitalWrite (BOW, HIGH);
  delay (100);
  digitalWrite (MAST, LOW);
  digitalWrite (BOW, LOW);
  delay (250);
   
  SequenceLastFired = millis();
  


}

The above program functions as desired. I will post the new program in a second post in this thread due to size limitations (hope this is OK).

I have given writing a new program to read the text files from the SD card a go in place of my delay-based sequencing, yet I am not achieving the desired results. One of the files on the SD card looks like this:

100,00000000
500,01000001
700,00000000
1000,10000010
1200,00011000
1400,01000001
1600,00011000
1800,00000000
2000,10000010
2200,00100100
2500,01000001
2700,00000000
3000,00000000
3500,01000001
3700,00000000
4000,10000010
4200,00011000
4500,01000001
4700,00011000
4900,10000010
5100,00100100
5300,01000001
5500,00000000
8000,00000000

And here is my new program.

#include <Bounce.h>
#include <SdFat.h>
#include <SdFatUtil.h>

int outputPins[4] = {2,3,4,5};
long millisSinceStart = 0;
int currentEventPtr = 0;

//arming indicator LEDs
int REDled = 8;
int GREENled = 7;
int ARMED = 0;

struct Event {
 long eventTimestamp;
 byte address;
} ;

//SD card setup
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;
int offset = 2;
int fileCount = 7; // count + 1
char name[] = "03.txt";
uint8_t fileCounter = 3;

// store error strings in flash to save RAM
#define error(s) error_P(PSTR(s))
void error_P(const char* str) 
{
  PgmPrint("error: ");
  if (card.errorCode()) 
  {
    PgmPrint("SD error: ");
   }
  while(1);
}

//Sequence
int SEQUENCEbutton = 6;
unsigned long SequenceLastFired;
int sequenceSize;
Event sequence[150];

//sequence reset time, during which sequence button will not work after pressed (should be eventually set to 15 minutes)
int SequenceResetTime = 10000;

//button debouncing
Bounce SEQUENCEbouncer = Bounce (SEQUENCEbutton,1);

void setup () 
{
  pinMode (SEQUENCEbutton, INPUT);
  
  for (int i = 0; i < 4; i++) 
  {
     pinMode(outputPins[i] + offset, OUTPUT); 
  }
    
  if (!card.init(SPI_HALF_SPEED)) error("card.init failed");
  if (!volume.init(&card)) error("volume.init failed");
  if (!root.openRoot(&volume)) error("openRoot failed");
  
  for (int i = 0; i < 4; i++) 
  {
     digitalWrite(i + offset, LOW); 
     delay(10);
  }
 
 Serial.begin(9600);
 
 }

void loop ()
{
   if (ARMED == 0)
  {
   digitalWrite (REDled, HIGH); 
   digitalWrite (GREENled, LOW);
   }
  
  if (ARMED == 1)
  {
    digitalWrite (REDled, LOW);
    digitalWrite (GREENled, HIGH);
  }
  
 if ((millis() - SequenceLastFired) > SequenceResetTime)
 {
    ARMED = 1;
 }
 else
 {
  ARMED = 0; 
 }
  
    //check for button presses
  SEQUENCEbouncer.update();
  int SEQUENCEbuttonState = SEQUENCEbouncer.read();
  if (SEQUENCEbuttonState == HIGH && (millis() - SequenceLastFired > SequenceResetTime))
  {
  SEQUENCEfire();
  }
    
   

//=================HOW DOES THIS CONTROL THE SEQUENCE???================================= 
  millisSinceStart = millis();
  if(millisSinceStart > (sequence[currentEventPtr].eventTimestamp)) 
  {
    checkBitOut(sequence[currentEventPtr].address);    
    currentEventPtr++;
    if(currentEventPtr >= sequenceSize)
    {
      currentEventPtr = 0;
      file.close();
      for (int i = 0; i < 4; i++) {
         digitalWrite(i+offset, LOW); 
         delay(10);
      }
     }
     
  }
 //   ============================================================================

 
    
   Serial.println (ARMED);
       
}

dir_t dir;

//=======================SEQUENCE CODE===============================
void SEQUENCEfire ()
{
 // ARMED = 0;
 // digitalWrite (REDled, HIGH);
 // digitalWrite (GREENled, LOW);
  
  //FOGHORN CODE HERE?
  
for (int i = 0; i < 4; i++) {
     digitalWrite(i + offset, LOW); 
     delay(10);
  }
  
  sequenceSize = 0;
  
  
  if (file.open(&root, name, O_READ)) {
     
  } else{
    
    fileCounter = 0;
    name[0] = fileCounter/10 + '0';
    name[1] = fileCounter%10 + '0';
    if (!file.open(&root, name, O_READ)){
      error("file.open failed");
    }else{
         
    }
  }
  
  fileCounter++; // sequential
  
  
  
  name[0] = fileCounter/10 + '0';
  name[1] = fileCounter%10 + '0';    
  
  
  int n;
  char buf[32];  
  int sequenceIndex = 0;
  int index = 0;
  char timestampString[10] = {0,0,0,0,0,0,0,0,0,0};
  boolean isByteString = false;
  byte currentByte = B00000000;
  
  // READ THROUGH EACH CHARACTER IN THE FILE
  while ((n = file.read(buf, sizeof(buf))) > 0) {
    
    // LOOP THROUGH BUFFER
    for (int i = 0; i < n; i++)
    {   
      // DELIMITER HIT - ADD PREVIOUS TO ARRAY
      if(buf[i] == ',' || buf[i] == '\n'){ 
        // TIMESTAMP        
        if(isByteString == false) 
        {                  
          index++;
          timestampString[index] = '\0'; 
          long ts = atoi(timestampString);
          sequence[sequenceIndex].eventTimestamp = ts;
          char timestampString[10] = {0,0,0,0,0,0,0,0,0,0};
          index = 7;
        }
        // BYTE      
        if(isByteString == true)
        {
          sequence[sequenceIndex].address = currentByte;
          currentByte = B00000000;
          index = 0;                
        }
        isByteString = !isByteString; // SWITCHES BACK AND FORTH BETWEEN TIMESTAMP AND BYTE              
      } 
      // END - DELIMITER CODE
      
      if(buf[i] == '\n'){
        sequenceSize++;
        sequenceIndex++;
      }

      // BUILD DATA TYPES     
      if(buf[i] != ',' && buf[i] != '\n' && buf[i] != '\r'  && buf[i] != ' '){
        
        // TIMESTAMP
        if(isByteString == false)
        {
            timestampString[index] = char(buf[i]);
            index++;
        }          
        
        // BYTE
        if(isByteString == true)
        {
          if(char(buf[i]) == '1'){
            currentByte = currentByte | (1 << index);
          }
  
          if(char(buf[i]) == '0'){
            currentByte = currentByte | (0 << index);
          }
          
          index--;        
        }
       
      } // END - BUILD DATA TYPES    
    } // END - LOOP THROUGH BUFFER   
  } // END - LOOP THROUGH FILE

  //Serial.println("Done Loading \n");
  resetMillis();  
  currentEventPtr = 0;
  SequenceLastFired = millis();
}
  

 void checkBitOut(byte myDataOut) {
  int i=0;
  int pinState; 
  for (i=7; i>=0; i--)  {
    if ( myDataOut & (1<<i) ) {
      pinState= 1;
    }
    else {	
      pinState= 0;
    }
    digitalWrite(i + offset, pinState);
  }
}

extern volatile unsigned long timer0_millis;

void resetMillis()
{
 cli();  // disable interrupts
 timer0_millis = 0;
 sei();  // enable interrupts
}

After uploading, my REDled glows red, and then after my 10s pause, the LEDs begin flashing in the sequence from the SD card for about 30 seconds, and then the program crashes and prints "error:" to the Serial port.

So, my program is reading the text file on the card, but my arming system and button press are not working, and then it crashes. The program should load, the REDled should be red for 10 seconds, then turn off while the GREENled turns on, and then the program should only read the sequence file from the SD card when the user presses the button. Then, after the sequence finishes, the button should not be active for the specified pause time.

Any help would be much appreciated, thanks.

Event sequence[150];

Each element of the array is 5 bytes. 150 of them use 750 bytes.

#include <SdFat.h>
#include <SdFatUtil.h>

Reading and writing to the SD card is done in 512 byte chunks. Those 512 bytes need to be stored somewhere.

Just these two items are using well over half of your memory, if you have a 328 based Arduino.

Constant strings take up memory, too. I suspect that you are running out of memory.

        if(isByteString == false) 
        {                  
          index++;
          timestampString[index] = '\0'; 
          long ts = atoi(timestampString);
          sequence[sequenceIndex].eventTimestamp = ts;
          char timestampString[10] = {0,0,0,0,0,0,0,0,0,0};
          index = 7;
        }

A local variable that goes out of scope almost immediately is hardly useful use of memory.

            timestampString[index] = char(buf[i]);

The char() macro is for people that don't understand casting. Casting a char to a char is hardly necessary.

  resetMillis();

Why? Calendars roll over at the end of the month. People manage. Clocks roll over at the end of the day. People manage.

A local variable that goes out of scope almost immediately is hardly useful use of memory.

What alternative would you suggest?

I'm having trouble understanding some of what my program is doing, as I did not write all of it, it came partly from a friend and partly from online resources. I would be greatful if I could better understand it so i can address some of PaulS's concerns and hopefully write e better, more memory efficient program.

For starters, my text files contain lines like this:
100,00000000
500,01000001
...etc.

The 100 is meant to be a millisecond value, the binary number is meant to refer to digital pins 0 through 7, which corresponds to which LEDs are lit when the function checkBitOut is passed the data from the text file.

I am wondering why the function checkBitOut seems to work without use of PORTD declaration in the setup?

void checkBitOut(byte myDataOut) {
  int i=0;
  int pinState;
  for (i=7; i>=0; i--)  {
     if ( myDataOut & (1<<i) ) {
      pinState= 1;
    }
    else {	
      pinState= 0;
    }

Also, in the above function, there is an "if" stament with a bitwise &. This if statement does not test a condition....which is confusing to me. 

I added some serial for debugging (and yes I know that pins 0 and 1 won't work with Serial enabled...), and I find the values of "myDataOut" in BIN are 10000000, then 01000000, then 00100000, etc. The values of (1<<i) start at 10000000, then go to 01000000, etc. So this "if" statement is using the & operator to set the pin to HIGH if "myDataOut' and "(1<<i)" are equal as i goes from 7 to 0? Or am I not understanding what is actually going on here?

What alternative would you suggest?

That would depend on why you are defining the variable.

          char timestampString[10] = {0,0,0,0,0,0,0,0,0,0};

What, exactly, is this for? You declare and initialize the array, but never reference it.

@PaulS - The variable (I think) is being defined so that when the program reads one text file, it timestamps when it was read so that it can move onto reading the next one. I did not write this bit of the code so I am not sure.

Isn't the char timestampString array referenced below where it is declared in the part of my program that reads the text files from the SD card?

I have attempted to modify my code to make use of a Finite State Machine approach to have it cycle through the states I want:
Idle at power on (lasts for 3 seconds)
Startup (lasts for 6 seconds)
Armed
Firing
Pausing
Armed

So far, so good - the program loads, the states cycle through, and I am able to get the "firing" state to read the first text file from the card:

100,00111100
500,00100000
650,00010000
1000,00011000
1250,00011000
1400,00000000
1600,00011000
1800,00000000
2000,00000000
2200,00100000
2500,00000000
2700,00000000
3000,00000000
3500,00000000
3700,00000000
4000,00000000
4200,00011000
4500,00000000
4700,00011000
4900,00011100
5150,00100100
5300,00000000
5500,00000000
8000,00000000

And light up my LEDs. Then, after it runs through the sequence, the FSM transitions into "Pausing,"' then back to "armed" after the prescribed pause time; however, when it is sent back into "firing" with another button press, it does not read the next text file.

This code was originally written to read the text files one after another after another with an random intermission in between - so I know my probelm at the moment is that I need to change the code in the function loadSequence() or add a counter variable in the firing state to match the text files, so that each time the FSM cycles into Firing, it reads the next text file on the card.

I am not well versed at all in the SD library - I didn't write the original code - can anyone help?

Here's my program:

#include <Bounce.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include <FiniteStateMachine.h>

int REDled = 8;
int GREENled = 9;


//Sequence
int SEQUENCEbutton = 6;
unsigned long SequenceLastFired;

//Variables for Timing
unsigned long StartupEnteredTime;
unsigned long ArmedEnteredTime;
unsigned long FiringEnteredTime;
unsigned long PausingEnteredTime;

unsigned long StartFiring;

State Idle = State (DSIdle); //idle state
State Startup = State (DSStartupStart,DSStartupUpd,DSStartupExit); //startup state
State Armed = State (DSArmedStart,DSArmedUpd,DSArmedExit); //Armed state
State Firing = State (DSFiringStart,DSFiringUpd,DSFiringExit); //cannons firing state
State Pausing = State (DSPausingStart,DSPausingUpd,DSPausingExit);//pause state
FSM DSStateMachine = FSM(Idle); //initialize DS State Machine, start in state: Idle


//sequence reset time, during which sequence button will not work after pressed (should be eventually set to 15 minutes)
int SequenceResetTime = 15000;

//button debouncing
Bounce SEQUENCEbouncer = Bounce (SEQUENCEbutton,3);

//SD card setup
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;


//Text files on card names and quantity
//int offset = 2;
int fileCount = 7; // count + 1

//struct for variables in text file
struct Event {
 long eventTimestamp;
 byte address;
} ;

//LED or Cannon Pins
int outputPins[4] = {2,3,4,5};
int sequenceSize;
long millisSinceStart = 0;
int currentEventPtr = 0;

char name[] = "03.txt";
uint8_t fileCounter = 3;

Event sequence[150];

// store error strings in flash to save RAM
#define error(s) error_P(PSTR(s)) 
void error_P(const char* str) {
  PgmPrint("mystery error: ");
  if (card.errorCode()) 
  {
    PgmPrint("SD error: ");
   }
  while(1);
}

//====================SETUP CODE TO RUN ONCE=====================

void setup () {
 
  pinMode (SEQUENCEbutton, INPUT);
  for (int i = 2; i < 6; i++) 
  {
     pinMode(outputPins[i], OUTPUT); 
  }

  if (!card.init(SPI_HALF_SPEED)) error("card.init failed");
  if (!volume.init(&card)) error("volume.init failed");
  if (!root.openRoot(&volume)) error("openRoot failed");
  
 for (int i = 2; i < 6; i++)  {
     digitalWrite(i, LOW); 
     delay(10);
  }
 Serial.begin(9600);
 //REMOVED loadSequence(); 
 }

//===================MAIN PROGRAM LOOP CODE=====================
void loop (){
  
      if (millis() > 3000 && DSStateMachine.isInState(Idle)){
        {
        DSStateMachine.transitionTo(Startup);
        }
      
   }       
DSStateMachine.update();   
}

dir_t dir;

//State machines
//Idle------------------------------/
void DSIdle (){
  Serial.println("In State = Idle");
  for (int i = 2; i < 6; i++)  
  {
     digitalWrite(i, LOW); 
  }
  digitalWrite(GREENled, LOW);
  digitalWrite(REDled, HIGH);
}

//Startup----------------------------/
void DSStartupStart (){
  Serial.println("In State = Startup");
  for (int i = 2; i < 6; i++)  
  {
     digitalWrite(i, LOW); 
  }
  digitalWrite(GREENled, LOW);
  digitalWrite(REDled, HIGH);
  StartupEnteredTime = millis();
  Serial.println(StartupEnteredTime);
}
  
void DSStartupUpd (){
    
  if (millis() - StartupEnteredTime > 6000)
    {
    DSStateMachine.transitionTo(Armed);
    }  
}

void DSStartupExit ()
{
}

//Armed------------------------------/
 void DSArmedStart (){
   for (int i = 2; i < 6; i++)  
  {
     digitalWrite(i, LOW); 
  }
  Serial.println("In State = Armed");
  digitalWrite(GREENled, HIGH);
  digitalWrite(REDled, LOW);
  ArmedEnteredTime = millis();

 }
 
 void DSArmedUpd (){
  
 SEQUENCEbouncer.update();
 int SEQUENCEbuttonState = SEQUENCEbouncer.read();  

 if (SEQUENCEbuttonState == HIGH)
 {
 DSStateMachine.transitionTo(Firing);
 }
}

void DSArmedExit ()
{
}

//FIRING---------------------------/
void DSFiringStart()
{  
  Serial.println("In State = Firing");
  loadSequence();
}

void DSFiringUpd()
{
  StartFiring = millis();
  Serial.println(StartFiring);
  delay(1000);
  Serial.println("timestamp");
  Serial.println(sequence[currentEventPtr].eventTimestamp);
  
  if(StartFiring > (sequence[currentEventPtr].eventTimestamp))
  {
      loadBinaryCannonSequences(sequence[currentEventPtr].address);    
      currentEventPtr++;
      if(currentEventPtr >= sequenceSize)
      {
        currentEventPtr = 0;
        file.close();
        for (int i = 2; i < 6; i++) {
           digitalWrite(i, LOW); 
           delay(10);
      SequenceLastFired = millis();
      DSStateMachine.transitionTo(Pausing);
      
      }
      }
      //  loadSequence();
      }
     
     
   
   // THIS CODE NEEDS TO STOP THE SEQUENCE AFTER 20 SECONDS, OR POSSIBLY WHEN THE eventTimestamp == 9999999?
   // if (millis() - (sequence[currentEventPtr].eventTimestamp) > 20000)
   //  {
   //    DSStateMachine.transitionTo(Pausing);  
   //  }
   //  SequenceLastFired = millis();  
 }
     
void DSFiringExit()
{
}
 
//PAUSING------------------------------/  

void DSPausingStart(){
  Serial.println("In State = Pausing");
  digitalWrite(REDled, HIGH);
  digitalWrite(GREENled,LOW);
  PausingEnteredTime = millis();
}

void DSPausingUpd(){
  if (millis() - PausingEnteredTime > SequenceResetTime){
   DSStateMachine.immediateTransitionTo(Armed);    
  }
}
  
void DSPausingExit()
{
}
 
//=======================LOAD SEQUENCE CODE===============================
void loadSequence ()
{
   
for (int i = 2; i < 6; i++) {
     digitalWrite(i, LOW); 
     delay(10);
  }
  
  sequenceSize = 0;
  
  if (file.open(&root, name, O_READ)) {
     
  } else{
    
    fileCounter = 0;
    name[0] = fileCounter/10 + '0';
    name[1] = fileCounter%10 + '0';
    if (!file.open(&root, name, O_READ)){
      error("file.open failed");
      
    }else{
         
    }
  }
  
  fileCounter++; // sequential
  
  name[0] = fileCounter/10 + '0';
  name[1] = fileCounter%10 + '0';    
  
  int n;
  char buf[32];  
  int sequenceIndex = 0;
  int index = 0;
  char timestampString[10] = {0,0,0,0,0,0,0,0,0,0};
  boolean isByteString = false;
  byte currentByte = B00000000;
  
 // Serial.println(name);
  
  // READ THROUGH EACH CHARACTER IN THE FILE
  while ((n = file.read(buf, sizeof(buf))) > 0) {
    
    // LOOP THROUGH BUFFER
    for (int i = 0; i < n; i++)
    {   
      // DELIMITER HIT - ADD PREVIOUS TO ARRAY
      if(buf[i] == ',' || buf[i] == '\n')
      { 
        // TIMESTAMP        
        if(isByteString == false) 
        {                  
          index++;
          timestampString[index] = '\0'; 
          long ts = atoi(timestampString);
          sequence[sequenceIndex].eventTimestamp = ts;
          char timestampString[10] = {0,0,0,0,0,0,0,0,0,0};
          index = 7;
          
          
        }
        // BYTE      
        if(isByteString == true)
        {
          sequence[sequenceIndex].address = currentByte;
          currentByte = B00000000;
          index = 0;                
        }
        isByteString = !isByteString; // SWITCHES BACK AND FORTH BETWEEN TIMESTAMP AND BYTE              
      } 
      // END - DELIMITER CODE
      
      if(buf[i] == '\n'){
        sequenceSize++;
        sequenceIndex++;
      }

      // BUILD DATA TYPES     
      if(buf[i] != ',' && buf[i] != '\n' && buf[i] != '\r'  && buf[i] != ' '){
        
        // TIMESTAMP
        if(isByteString == false)
        {
            timestampString[index] = char(buf[i]);
            index++;
        }          
        
        // BYTE
        if(isByteString == true)
        {
          if(char(buf[i]) == '1'){
            currentByte = currentByte | (1 << index);
          }
  
          if(char(buf[i]) == '0'){
            currentByte = currentByte | (0 << index);
          }
          index--;     
          
        }
       
      } // END - BUILD DATA TYPES    
    } // END - LOOP THROUGH BUFFER   
  } // END - LOOP THROUGH FILE

  resetMillis();  
  currentEventPtr = 0;
 
 
}
  
//==================THIS CODE FIRES THE CANNONS BASED ON TEXT FILES=====
 void loadBinaryCannonSequences(byte BinaryPinSequence) {
  int i=0;
  int pinState; 
  for (i=7; i>=0; i--)  {
    if ( BinaryPinSequence & (1<<i) ) {
      pinState= 1;
    }
    else {	
      pinState= 0;
    }
    
    digitalWrite(i, pinState);
  }
  
}


//==========================this code resets the millis() timer

extern volatile unsigned long timer0_millis;
void resetMillis()
{
 cli();  // disable interrupts
 timer0_millis = 0;
 sei();  // enable interrupts
}

It seems a bit of a waste of space to use 8 characters to store 8 bits of information.

If you want to use a "text" file to store your data, I suggest you learn hexadecimal numbers so your 0,0,0,1,0,0,1,1 gets stored as 03 (hex).