Offroad light controller with chase light

Hi guys.

I borrowed my brother's UNO a while back to start learning how to build a light controller for my jeep. I've figured out how to work multiple lights in binary (stay on/off individually) or to alternatively strobe two lights for a chase light (think cop car), but i've completely hit a wall trying to marry the two concepts. I also tried building off the blink without delay example for a proof of concept, but I couldn't get that to jive either. Could anyone give me some pointers as to where I'm going wrong?

const int strobebutt = 2;
const int bumpbutt = 3;
const int strobe1 = 13;
const int strobe2 = 11;
const int bumplight = 8;
int strobePushCounter = 0;
volatile int strobeState = 0;
int lastStrobeState = 0;
int bumpPushCounter = 0;
volatile int bumpState = 0;
int lastBumpState = 0;


void setup() {
  
  pinMode(strobebutt,INPUT_PULLUP);
  pinMode(bumpbutt,INPUT_PULLUP);
  pinMode(strobe1,OUTPUT);
  pinMode(strobe2,OUTPUT);
  pinMode(bumplight,OUTPUT);
  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(2),strobe,HIGH);
  attachInterrupt(digitalPinToInterrupt(3),bumper,HIGH);
  
}

void loop() {
  // put your main code here, to run repeatedly:
 

}

void strobe(){
   strobeState = digitalRead(strobebutt);

  // compare the buttonState to its previous state
  if (strobeState != lastStrobeState) {
    // if the state has changed, increment the counter
    if (strobeState == HIGH) {
      // if the current state is HIGH then the button went from off to on:
      strobePushCounter++;
      Serial.println("on");
      Serial.print("number of button pushes: ");
      Serial.println(strobePushCounter);
    } else {
      // if the current state is LOW then the button went from on to off:
      Serial.println("off");
    }
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  // save the current state as the last state, for next time through the loop
  lastStrobeState = strobeState;


  // turns on the LED every other button push by checking the modulo of the
  // button push counter. the modulo function gives you the remainder of the
  // division of two numbers:
  if (strobePushCounter % 2 == 0) {
   digitalWrite(strobe1,HIGH); // begin strobe on light 1
   delay(50);
   digitalWrite(strobe1,LOW);
   delay(50);
   digitalWrite(strobe1,HIGH);
   delay(50);
   digitalWrite(strobe1,LOW);
   delay(50);
   digitalWrite(strobe1,HIGH);
   delay(50);
   digitalWrite(strobe1,LOW);
   delay(50);
   digitalWrite(strobe1,HIGH);
   delay(50);
   digitalWrite(strobe1,LOW);
   delay(50);
   digitalWrite(strobe2,HIGH); // begin strobe on the light 2
   delay(50);
   digitalWrite(strobe2,LOW);
   delay(50);
   digitalWrite(strobe2,HIGH);
   delay(50);
   digitalWrite(strobe2,LOW);
   delay(50);
   digitalWrite(strobe2,HIGH);
   delay(50);
   digitalWrite(strobe2,LOW);
   delay(50);
   digitalWrite(strobe2,HIGH);
   delay(50);
   digitalWrite(strobe2,LOW);
   delay(50);
  } else {
    digitalWrite(strobe1, LOW);
    digitalWrite(strobe2, LOW);
  }
}

void bumper(){

   bumpState = digitalRead(bumpbutt);

  // compare the buttonState to its previous state
  if (bumpState != lastBumpState) {
    // if the state has changed, increment the counter
    if (bumpState == HIGH) {
      // if the current state is HIGH then the button went from off to on:
      bumpPushCounter++;
      Serial.println("on");
      Serial.print("number of button pushes: ");
      Serial.println(bumpPushCounter);
    } else {
      // if the current state is LOW then the button went from on to off:
      Serial.println("off");
    }
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  // save the current state as the last state, for next time through the loop
  lastBumpState = bumpState;


  // turns on the LED every other button push by checking the modulo of the
  // button push counter. the modulo function gives you the remainder of the
  // division of two numbers:
  if (bumpPushCounter % 2 == 0) {
    digitalWrite(bumplight, HIGH);
  } else {
    digitalWrite(bumplight, LOW);
  }
}

HUGE problem:

  attachInterrupt(digitalPinToInterrupt(2), strobe, HIGH);
  attachInterrupt(digitalPinToInterrupt(3), bumper, HIGH);

You are using interrupts in a completely inappropriate way. Never serial print from an interrupt and never use delay from an interrupt. Indeed, you don't need interrupts for your application.

Secondly, I see you are using INPUT_PULLUP for your buttons. This implies one leg of your button is attached to GND and the other to the digital input. If this is the case then that means the input is active LOW, in other words the input will be LOW when the button is pressed.

For fun I coded a version that just handles your strobe lights. If this works then adding bump light should be trivial. It compiles but I can’t guarantee it works. Study it, try it and let me know if you have any questions.

It allows for easily adding more strobe lights. Just adjust the constant and add the additional pins to the array. You can also vary the strobe length and number of strobe cycles per light.

const int strobebutt = 2;
const int bumpbutt = 3;
const int bumplight = 8;
const unsigned long strobeLength = 50;
const int numStrobeCycles = 4;
const int numStrobeLights = 2;

bool strobeOn = false;
int strobePins[numStrobeLights] = {13, 11};
int strobeIdx;
byte strobeState = HIGH;

void setup() {

  pinMode(strobebutt, INPUT_PULLUP);
  pinMode(bumpbutt, INPUT_PULLUP);
  for (int idx = 0; idx < numStrobeLights; idx++)
  {
    pinMode(strobePins[idx], OUTPUT);
  }  
  pinMode(bumplight, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  byte strobeButton;
  static byte lastStrobeButton = HIGH;
  byte bumpButton;
  static byte lastBumpButton = HIGH;
  static unsigned long lastStrobeMillis = 0;
  static int strobeIdx;
  static int strobeCycle;
  static byte strobeState;
  
  // put your main code here, to run repeatedly:
  strobeButton = digitalRead(strobebutt);

  // See if strobe button has been pressed
  if (strobeButton != lastStrobeButton) {
    if (strobeButton == LOW) {
      strobeOn = !strobeOn;
      if (strobeOn) {
        lastStrobeMillis = millis();
        strobeIdx = 0;
        strobeState = HIGH;
        strobeCycle = 0;
      }
      else {
        // turn all strobes off
        for (int idx = 0; idx < numStrobeLights; idx++)
        {
          digitalWrite(strobePins[idx], LOW);
        }  
      }
    }
    // Delay a little bit to avoid bouncing
    delay(50);
    lastStrobeButton = strobeButton;
  }

  // If the strobes are on then check to see if it is time to turn them on or off
  if (strobeOn && (millis() - lastStrobeMillis >= strobeLength)) {
    // Write the strobe state to the current strobe
    digitalWrite(strobePins[strobeIdx], strobeState);
    
    // Toggle strobe state
    if (strobeState == LOW) {
      // End of strobe cycle
      strobeState = HIGH;
      
      // Check to see if we are done with the current strobe
      if (strobeCycle++ >= numStrobeCycles) {
        // We are done with the current strobe, advance to the next
        strobeIdx++;
        strobeIdx%=numStrobeLights;
        // Reset strobe cycle count
        strobeCycle = 0;
      }
    }
    else {
      // Current strobe was ON so prepare to turn it OFF
      strobeState = LOW;
    }
    lastStrobeMillis = millis();
  }
}