Add two buttons inputs to Blinkwithoutdelay

Hi all,
I'm very new to arduino... very new. I have found a script I like online and modified it to suit my needs.

The design I have in mind is a dash light bar for a volunteer emergency responder that also has LED's in the tail lights that flash in an alternating pattern. Pins 4-12 are for the light bar and 2-3 are for the tail lights.

Here's where I need your help: I want to incorporate a momentary push button that turns the lights on and off (preferably a debounce one - that seems to be the better option).

Second thing I need is another signal input (pushbutton for the breadboard for now) that would turn off the outputs at pin 2 & 3 while the signal is detected, then when it goes back to 0 allow it to start flashing again.

The reason I want this is to have the lights in the tail lights stop flashing while the brake pedal is on. So for prototyping purpose I want to use a push button but in the future it'll be simply a signal in from the brake light wire.

Here's the code I have so far, any help would be much appreciated

// Timing suquences for the LED's in milliseconds
// First value is on time, second value is off time,
// third value on time and so on (up to 10 values)
// One row for each LED
unsigned int led_timing[][12] = {
  {75, 75, 75, 225},
  {0, 225, 75, 75, 75},    
  {50, 50, 50, 50, 50, 50, 50, 50, 50, 300},
  {0, 300, 50, 50, 50, 50, 50, 50, 50, 50, 50},
  {250, 250},
  {75, 75, 75, 225},
  {0, 225, 75, 75, 75},
  {0, 250, 250},
  {50, 50, 50, 50, 50, 50, 50, 50, 50, 300},
  {0, 300, 50, 50, 50, 50, 50, 50, 50, 50, 50},
};

// The pins the LED's are connected to
byte led_pins[] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12};

// Keep track of timing sequence
// Array size taken from led_pins
unsigned long last_change[sizeof(led_pins)/sizeof(led_pins[0])];
byte timing_i[sizeof(led_pins)/sizeof(led_pins[0])];

void setup()
{
  // Initialize LED's as output
  for (byte i = 0; i < sizeof(led_pins)/sizeof(led_pins[0]); i++)
  {
    pinMode(led_pins[i], OUTPUT);
    digitalWrite(led_pins[i], HIGH);
  }
}


void loop()
{
  // Current timestamp
  unsigned long now = millis();

  // Keep track of sequence for each LED
  for (byte i = 0; i < sizeof(led_pins)/sizeof(led_pins[0]); i++)
  {
    if (now - last_change[i] >= led_timing[i][timing_i[i]])
    {
      digitalWrite(led_pins[i], !digitalRead(led_pins[i]));
      timing_i[i]++;

      // Start over at the end of timing sequence
      timing_i[i] %= sizeof(led_timing[i])/sizeof(led_timing[i][0]);

      last_change[i] = now;
    }
  }
}

There's a debounce sketch in the IDE examples for a momentary button.

Thanks for your reply ribbonman. I am aware of the example scripts and I have seen how others have blended it with the blinkwithoutdelay . But I don't know how to add two buttons to this script which is more complex than a simple blinkwithoutdelay. Let alone to have one of those buttons cut out some of the flashing while it is pressed.

The reason I want this is to have the lights in the tail lights stop flashing while the brake pedal is on.

Then that doesn't require debouncing. a simple digitalRead() will tell you if the brake pedal is currently depressed.

On/off does require debouncing as that's a state-change.

MorganS:
Then that doesn't require debouncing. a simple digitalRead() will tell you if the brake pedal is currently depressed.

On/off does require debouncing as that's a state-change.

Yes, that is exactly what I asked for in my OP. Debouncing for the on/off and a signal (digitalRead) that momentarily stops pins 2&3 flashing. I know what I need. I need help with the actual writing of it.

I'm on my way out soon so I can't look too carefully but have a think along these lines:

  • Use the state change example which iirc uses modulo to determine every 4th press. Change that to 2 so you have every 2nd one. Then use if/else or switch..case to do the whole blink thing (both the dash and tail) when it's even amd nothing when it's odd.
  • Then inside the one where it's all on and you want the tail ones to go off, put the tail part inside a while (!digitalRead()) so when the brake light line* is high it's ignored,

*Don't forget to condition the 12V down to 5V if you didn't already else you'll let the magic smoke out.

ardy_guy:
I'm on my way out soon so I can't look too carefully but have a think along these lines:

  • Use the state change example which iirc uses modulo to determine every 4th press. Change that to 2 so you have every 2nd one. Then use if/else or switch..case to do the whole blink thing (both the dash and tail) when it's even amd nothing when it's odd.
  • Then inside the one where it's all on and you want the tail ones to go off, put the tail part inside a while (!digitalRead()) so when the brake light line* is high it's ignored,

*Don't forget to condition the 12V down to 5V if you didn't already else you'll let the magic smoke out.

Much appreciated...

and yes, next step will be to start playing with mosfets

lucmallet:
next step will be to start playing with mosfets

This shows a simple bjt approach to bringing 12V down to 5V. It inverts the signal but you can take care of that in your logic.

I used the state change with a 2 and it works... sort of.... The arduino powers up and when I press the button, the lights start flashing but the timing of the lights is way off! Also when I press the button to "turn off" the lights; some of them stay on - I get the feeling only the timer stops.

Any ideas?

// this constant won't change:
const int  buttonPin = 2;    // the pin that the pushbutton is attached to

// Lightbar code
unsigned int led_timing[][12] = {
  {0, 75, 75, 75, 75, 75, 375},
  {375, 75, 75, 75, 75, 75},    
  {0, 50, 50, 50, 50, 50, 50, 50, 50, 50, 300},
  {250, 250},
  {300, 50, 50, 50, 50, 50, 50, 50, 50, 50},
  {0, 75, 75, 75, 75, 75, 375},
  {375, 75, 75, 75, 75, 75},
  {0, 50, 50, 50, 50, 50, 50, 50, 50, 50, 300},
  {250, 250},
  {300, 50, 50, 50, 50, 50, 50, 50, 50, 50},
};

// The pins the LED's are connected to
byte led_pins[] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12};

// Keep track of timing sequence
// Array size taken from led_pins
unsigned long last_change[sizeof(led_pins)/sizeof(led_pins[0])];
byte timing_i[sizeof(led_pins)/sizeof(led_pins[0])];

// end lightbar code

// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

void setup() {
  // initialize the button pin as a input:
  pinMode(buttonPin, INPUT);
  // initialize serial communication:
  Serial.begin(9600);
  // lightbar code
  // Initialize LED's as output
  for (byte i = 0; i < sizeof(led_pins)/sizeof(led_pins[0]); i++)
  {
    pinMode(led_pins[i], OUTPUT);
    digitalWrite(led_pins[i], LOW);
  }

}


void loop() {
  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);

  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button
      // wend from off to on:
      buttonPushCounter++;
      Serial.println("on");
      Serial.print("number of button pushes:  ");
      Serial.println(buttonPushCounter);
    }
    else {
      // if the current state is LOW then the button
      // wend 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
  lastButtonState = buttonState;


  // turns on the LED every 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 (buttonPushCounter % 2 == 0) {
      // Current timestamp  
  } else {
    unsigned long now = millis();

  // Keep track of sequence for each LED
  for (byte i = 0; i < sizeof(led_pins)/sizeof(led_pins[0]); i++)
  {
    if (now - last_change[i] >= led_timing[i][timing_i[i]])
    {
      digitalWrite(led_pins[i], !digitalRead(led_pins[i]));
      timing_i[i]++;

      // Start over at the end of timing sequence
      timing_i[i] %= sizeof(led_timing[i])/sizeof(led_timing[i][0]);

      last_change[i] = now;
    }
  }
  }

}

Hmmm, that's not a particularly good way to do things. The delay(50) in the middle is just nasty.

Start by reading Planning and Implementing an Arduino Program.

Then think about the functions your program has to do thousands of times per second. You might end up with a loop() which looks like this:

void loop() {
  checkButtonInput();
  if(flashingState) {
    makeFlashing();
  } else {
    allLightsOff();
  }
}

checkButtonInput() should do the debouncing (without using delay()) and it should set the global variable flashingState. makeFlashing() will look like your current flashing code. allLightsOff() will just simply cycle through all outputs and set them to off.

I still think it is the millis() that are the problem with any button statement. the way I understand it ( and correct me if I am wrong) the clock starts running at the beginning. The milliseconds start at 0, they tick along and the lights go on and off in reference to millisecond 0 based on their pre determined sequence. But then if you interrupt the flash sequence, and suddenly start them flashing again, they start their flashing sequence from whenever in time the input is received. They aren't flashing from milli 0 anymore - I think thats why it isn't working.

I haven't been able to find a way to reset the millis() in any way. If it is possible it would be great to be able to state "with every button press, reset millis to 0". That would solve all my problems!!!

Alternatively....

Would there be any way to make the millis() work with a switch case script??

void setup() {
  // initialize serial communication:
  Serial.begin(9600);
  // initialize the LED pins:
  for (int thisPin = 2; thisPin < 7; thisPin++) {
    pinMode(thisPin, OUTPUT);
  }
}

void loop() {
  // read the sensor:
  if (Serial.available() > 0) {
    int inByte = Serial.read();
    // do something different depending on the character received.
    // The switch statement expects single number values for each case;
    // in this exmaple, though, you're using single quotes to tell
    // the controller to get the ASCII value for the character.  For
    // example 'a' = 97, 'b' = 98, and so forth:

    switch (inByte) {
      case 'a':
        digitalWrite(2, HIGH);
        break;
      case 'b':
        digitalWrite(3, HIGH);
        break;
      case 'c':
        digitalWrite(4, HIGH);
        break;
      case 'd':
        digitalWrite(5, HIGH);
        break;
      case 'e':
        digitalWrite(6, HIGH);
        break;
      default:
        // turn all the LEDs off:
        for (int thisPin = 2; thisPin < 7; thisPin++) {
          digitalWrite(thisPin, LOW);
        }
    }
  }
}

Take a read here, use millis() is explained nicely. No need to reset anything.
https://forum.arduino.cc/index.php?topic=466315.msg3197265#msg3197265

CrossRoads:
Take a read here, use millis() is explained nicely. No need to reset anything.
Comprehension 101 - #7 by system - Programming Questions - Arduino Forum

Thank you for that example. It makes sense in my head - I understand the logic behind it. I just don't understand how to write the script that implements it...