All Arduino Mega Pins + 5 shift Registers - 6x8 Grid Animation Code Help

PaulS:
At some point, OP should realize that there are smaller types that are more appropriate.

I agree, the type of variable should not be overly big if not necessary. I changed lots of int to byte where I could. I am now using a millis timer so there are some unsigned longs. Since I am using an Arduino Mega, I am still only at 3184 bytes (1%) of program storage space and 171bytes (2%) of dynamic memory.

I do think I will run into issues as the code gets longer but I will try to streamline as I go.


With the help of a friend and this forum, I set up a test of 48 relays and 3 shift registers. I have some simple animations going but nothing more complex than a light chase. One uses a delay but goes both directions. lineardance();

I got another one working without a delay but I cannot get it to go in reverse more than once. lineardancenodelay();

I am also interested in the individual rows of lights blinking in and out in sequence and at random intervals.

I also want to make the lights start in the middle and expand out like a ripple in a pond.

Do you have any suggestions on how to make the chase reverse in the no delay version or to make the other animations?

Thank you in advance

#include <ShiftRegister74HC595.h>

unsigned long currentMillis = 1;
unsigned long flashTime = 1;
unsigned long danceTime = millis();
unsigned long danceTimeReverse = millis();
int danceStepEnd = 48;
int danceStep = 0;
int i = 0;
int lightState = LOW; // Temp for additional blink without delay function

byte numberOfShiftRegisters = 3; // number of shift registers attached in series
byte serialDataPin = 51; // blue wire
byte clockPin = 52; // yellow wire
byte latchPin = 53; // green wire
ShiftRegister74HC595 sr (numberOfShiftRegisters, serialDataPin, clockPin, latchPin);

const byte numberOfLights = 48; // number of light strings 48 in testing 96 in production
byte numberOfArduinoPins = 24; // 24 in testing 66 in production
byte numberOfShiftRegisterPins = 24; // 24 in testing 30 in production
const byte lightPins[] = {A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, 1, 2, 3, 4, 5, 6, 7, 8};
// ,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50}; //An array to hold the pin each LED is connected to
// lights 1 - 66 use pins from Arduinio Mega
// lights 67 - 96 use pins from Shift registers in series
// lights 67 - 96 use shift register pins 1 - 30
const unsigned danceIntervals[numberOfLights] = {  // Milliseconds
  300, 290, 280, 270, 260, 250,
  240, 230, 220, 210, 220, 210,
   200, 190, 180, 170, 160, 150,
  140, 135, 130, 125, 120, 115,
   110, 105, 100, 95, 90, 85,
  80, 75, 70, 65, 60, 55,
   50, 45, 40, 35, 30, 25,
  20, 15, 10, 5, 4, 3
};

void setup () {

  //Set each pin connected to light string to output mode
  for (byte i = 0; i <= numberOfArduinoPins; i++)
  {
    pinMode(lightPins[i], OUTPUT);
  }

  // Prevent relays from starting up engaged
  for (byte i = 0; i <= numberOfArduinoPins; i++)
  {
    digitalWrite(lightPins[i], LOW);
  }

  // Prevent shift register controled relays from starting up engaged
  for (byte i = 0; i <= numberOfShiftRegisterPins; i++)
  {
    sr.set(i, HIGH); // HIGH in testing rig relays but LOW in production
  }
}

void loop() {
  currentMillis = millis();
 // newlineardance();
  lineardancenodelay();
  lineardancereversenodelay();
  blinkLightWithoutDelay(37);
  
  //lineardance();
  //or
  //outtoindance();
  //lightcontrolon(danceStep);
}

//Check if time expired function
boolean CheckTime(unsigned long &lastMillis, unsigned long wait)
{
  //is the time up for this task?
  if (currentMillis - lastMillis >= wait)
  {
    lastMillis += wait;  //get ready for the next iteration
    return true;
  }
  return false;
}
//END of CheckTime()

// linear run of lights in sequential order without delay
void lineardancenodelay() {
  if ((currentMillis - danceTime) >= danceIntervals[danceStep])
  {
    danceTime += danceIntervals[danceStep];
    lightcontroloff(danceStep); // Previous pin OFF
    danceStep = (danceStep + 1) % numberOfLights;
    lightcontrolon(danceStep);  // New pin ON
  }
}

// linear run of lights in reverse sequential order without delay but cannot figure out how to reverse
void lineardancereversenodelay() {
  if ((currentMillis - danceTimeReverse) >= danceIntervals[danceStepEnd])
  {
    danceTimeReverse += danceIntervals[danceStepEnd];
    lightcontroloff(danceStepEnd); // Previous pin OFF
    danceStepEnd = (danceStepEnd - 1) % numberOfLights;
    lightcontrolon(danceStepEnd);  // New pin ON
  }
}

// blink an individual light without delay
void blinkLightWithoutDelay(byte lightno) {
   if (CheckTime(flashTime, 500UL)) {
       flashTime = millis();
        if (lightState == LOW) {
          lightState = HIGH;
          lightcontrolon(lightno);        
        } else {
          lightState = LOW;
        lightcontroloff(lightno); 
        }   
      }
}

//just a linear test of lights in sequential order and then goes in reverse
void lineardance() {

  int lightpause = 20;
  for (byte i = 0; i <= numberOfLights; i++)
  {
    lightcontrolon(i);
    delay(lightpause);
    lightcontroloff(i);
    delay(lightpause);
  }

  for (byte i = numberOfLights; i <= numberOfLights; i--)
  {
    lightcontrolon(i);
    delay(lightpause);
    lightcontroloff(i);
    delay(lightpause);
  }
}

//lights on the outside light up, then turn off, while mid ones light up, then the inner ones
void outtoindance() {
  int lightpause = 100;

  //outer lights is first array group, mid lights our second group, and inner lights are third group
  int lightGroups[3][9] = {   {1, 2, 3, 4, 5, 6, 7, 8, 9} , {10, 11, 12, 13, 14, 15, 16, 17, 18}, {19, 20, 21, 22, 23, 24, 25, 26, 27} };
  for (int i = 0; i < 3; i++)
  {
    for (int j = 0; i < 9; j++) {
      lightcontrolon(lightGroups[i][j]);
    }
    delay(lightpause);
    for (int j = 0; i < 9; j++) {
      lightcontroloff(lightGroups[i][j]);
    }
  }
}

// turns lights on by pin and turns shift registers on by pin if greater than number of light pins
void lightcontrolon(byte lightno) {
  if (lightno < (numberOfArduinoPins + 1)) {
    digitalWrite(lightPins[lightno], HIGH); // HIGH trigger relays
  } else {
    byte shiftno = lightno - numberOfArduinoPins;
    sr.set(shiftno, LOW); // LOW in testing rig relays but HIGH in production
  }
}

// turns lights off by pin and turns shift registers off by pin if greater than number of light pins
void lightcontroloff(byte lightno) {
  if (lightno < (numberOfArduinoPins + 1)) {
    digitalWrite(lightPins[lightno], LOW); // HIGH trigger relays
  } else {
    byte shiftno = lightno - numberOfArduinoPins;
    sr.set(shiftno, HIGH); // HIGH in testing rig relays but LOW in production
  }
}

Currently I am only using 48 relays. I have 96 relays installed in the completed control board but do not have physical access to the 96 relay board during this code testing time.