Need Help With Police Light Modes

All those calls to delay() are your enemy. Learn to flash the LEDs without delay(). See the BlinkWithoutDelay example that comes with the Arduino IDE. Also search the forum, there are probably literally hundred of posts about BlinkWithoutDelay.

I'd probably implement it as a state machine, where each button push advances to the next state. Each flashing pattern could be implemented as a separate function.

How could I make each one as a separate function? I don't really understand what you mean.

I just happened to have a board here with a few LEDs, so I threw this together quickly. Not as many LEDs, and just two flashing modes, but just to show the idea. Note there are no calls to delay().

Also note the switch is wired differently from yours, just from the pin to ground, no resistor, since the internal pullup resistor is used instead.

There are three modes: Off, Blinker and Chaser. There is a function for each: ledsOff(), blinker() and chaser().

Each has one argument to indicate initialization, i.e. the first call after changing modes. This is to ensure each mode always starts in a consistent state.

Therefore the state machine has six modes, an init mode for each mode, that only calls the function once, then a run mode for each.

#include <Button.h>                            //https://github.com/JChristensen/Button
#define BUTTON_PIN 2                           //wire the button between this pin and ground
#define TACT_DEBOUNCE 25                       //debounce time for tact switches, milliseconds
#define BLINK_INTERVAL 500                     //interval for blinker(), ms
#define CHASE_INTERVAL 200                     //interval for chaser(), ms
int8_t LED[] = { 5, 6, 7, 8 };                 //LEDs connected from these pins to ground, through appropriate current-limiting resistors
#define nLED sizeof(LED)/sizeof(LED[0])        //number of LEDs

Button btnMode = Button(BUTTON_PIN, true, true, TACT_DEBOUNCE);            //instantiate the button
enum MODES {OFF_INIT, OFF, BLINK_INIT, BLINK, CHASE_INIT, CHASE, LAST};    //LAST is not a "real" mode, just used to wrap back to the first mode.
uint8_t MODE;
unsigned long ms;

void setup(void)
{
    for (int i = 0; i < nLED; i++) {
        pinMode(LED[i], OUTPUT);
    }
}

void loop(void)
{
    ms = millis();
    btnMode.read();
    if ( btnMode.wasReleased() )
        if (++MODE >= LAST) MODE = OFF_INIT;
    
    switch (MODE) {
        case OFF_INIT:
            ledsOff(true);
            ++MODE;
            break;
        
        case OFF:
            ledsOff(false);
            break;
        
        case BLINK_INIT:
            blinker(true);
            ++MODE;
            break;
            
        case BLINK:
            blinker(false);
            break;
            
        case CHASE_INIT:
            chaser(true);
            ++MODE;
            break;

        case CHASE:
            chaser(false);
            break;
            
    }        
}

void ledsOff(boolean init)
{
    if (init) {
        for (int i = 0; i < nLED; i++) {
            digitalWrite(LED[i], LOW);
        }
    }
}

void blinker(boolean init)
{
    static unsigned long msLast;
    static boolean ledState;
    
    if (init) {
        msLast = ms;
        ledState = HIGH;
        for (int i = 0; i < nLED; i++) {
            digitalWrite(LED[i], ledState);
        }
    }
    else if (ms - msLast >= BLINK_INTERVAL) {
        msLast = ms;
        ledState = !ledState;
        for (int i = 0; i < nLED; i++) {
            digitalWrite(LED[i], ledState);
        }
    }       
}
    
void chaser(boolean init)
{
    static unsigned long msLast;
    static uint8_t onLED;

    if (init) {
        msLast = ms;
        onLED = 1;
        digitalWrite(LED[0], HIGH);
        for (int i = 1; i < nLED; i++) {
            digitalWrite(LED[i], LOW);
        }
    }
    else if (ms - msLast >= CHASE_INTERVAL) {
        msLast = ms;
        for (int i = 0; i < nLED; i++) {        //iterate through all the LEDs
            if (i == onLED)                     //just turn the current LED on, turn the rest off
                digitalWrite(LED[i], HIGH);
            else
                digitalWrite(LED[i], LOW);
        }
        if (++onLED >= nLED) onLED = 0;         //next LED, or start over with the first LED
    }       

}

I appreciate the reply, but this doesn't really help me at all. I would rather use delay(), and if I try to use "for()" it just loops until it reaches the certain integer that it is supposed to stop at.

wally_z:
I appreciate the reply, but this doesn't really help me at all. I would rather use delay(), and if I try to use "for()" it just loops until it reaches the certain integer that it is supposed to stop at.

If you insist on using delays, then you'll have to liter your code if a bunch of selection statements checking for a state change (implemented through interrupts). That would be a pretty poor way to implement it, though. Another option is to tie the button to reset, and store the state change in EEPROM. On startup, it pulls the data from memory, increments it, and goes into the loop. That method would work if you plan on doing nothing else with the micro.

I'm not sure what you mean by the for() loops. Yes that's what it does, why is that a problem?

wally_z:
I would rather use delay() ...

Why is that??

I would rather use delay()

There's no free lunch, I'm afraid; delay() is conceptually simple, but because it stop the processor doing anything except respond to interrupts, you can't write simple but responsive software.

The only things the Arduino should be doing is blinking the lights, and changing state when the button is pressed. I don't need it to be doing anything else, so delay() works fine for me in this situation.

Using "for()" is not the way i want to go. It will only loop until it reaches that certain integer. I need it to loop continuously until the buttonMode variable changes.

The only things the Arduino should be doing is blinking the lights, and changing state when the button is pressed.

That's two things, and whilst you're in delay(), you can do only one thing (which is sit twiddling thumbs), so the button goes unnoticed.

Using "for()" is not the way i want to go. It will only loop until it reaches that certain integer.

As the old song goes, 'tain't necessarily so. Here's a for loop that just goes on and on.for (;;)

Since you are apparently in NJ, unless you are a fire chief, as far as I know, you may not use red lights - just blue.

Edit: It's certainly that way in my town

@wildbill
The blue lights in my area are legal. As long as they are only blue. I only plan on using blue lights. I don't really want to pay a fine, or anything like that.

As the old song goes, 'tain't necessarily so. Here's a for loop that just goes on and on.

for (;;)

The question is, will it stop looping once the state is changed? I will be home in ~6 hours to test it. I'll let you know if it works properly. If it doesn't, then I will consider using BlinkWithoutDelay because as a few of you have said, delay() stops everything until that delay period is over.

So I'm guessing I would implement the "for()" statement as such:

while (buttonMode == 1){  //Do I even need the while if the "for()" statement is there?
for(;;){
digitalWrite(ledFrontLeft, HIGH);
delay(50); //Yes, I know. I'm using delays until I can figure out how to use BlinkWithoutDelay
digitalWrite(ledFrontLeft, LOW);
delay(50);
}
}

because as a few of you have said, delay() stops everything until that delay period is over.

No, not just a few of us; EVERYONE says that.

At one point in troubleshooting, I had the flashing patterns in their own "void()" statement, and tried looping like that. I might just redo that to shorten my code.

A fundamental issue here is that all your modes have loops like this:

while (buttonMode == 2){ //All LED's are off.
digitalWrite(ledFrontLeft, LOW);
digitalWrite(ledFrontRight, LOW);
digitalWrite(ledFogLightLeft, LOW);
digitalWrite(ledFogLightRight, LOW);
digitalWrite(ledBackLeft, LOW);
digitalWrite(ledBackRight, LOW);
digitalWrite(ledReverseLeft, LOW);
digitalWrite(ledReverseRight, LOW);
}

There is nothing in the body of the while loop that will change buttonMode, hence those loops never exit. You need to either restructure you code as Jack suggested (good) or check the button within each of your while loops (bad)

I have restructured my code. It looks a bit better.

/* This program will make police lights flash in certain patterns whiele in certain modes.
*/

const int buttonPin = 3; 
//Declares the button pin. Hook up the button to +5v, then the other end to a 10k resistor to ground. 
//Then from the button where the 10K resistor is hooked up, you hook that up to pin 3.

const int ledFrontLeft = 5; //Declares the front LED's
const int ledFrontRight = 6;
const int ledFogLightLeft = 7;
const int ledFogLightRight = 8;

const int ledBackLeft = 9; //Declares the rear LED's
const int ledBackRight = 10;
const int ledReverseLeft = 11;
const int ledReverseRight = 12;

int buttonMode = 0;
int buttonState = 0;

void setup(){
pinMode(buttonPin, INPUT);
pinMode(ledFrontLeft, OUTPUT); //For the front, you can put them into the headlights as long as they are bright enough.
pinMode(ledFrontRight, OUTPUT);
pinMode(ledFogLightLeft, OUTPUT); //Put them in the fog lights as well since they would barely be used.
pinMode(ledFogLightRight, OUTPUT);

pinMode(ledBackLeft, OUTPUT); //Use the tail-lights if you can find clear housings for them. If not, see how they look with blue LED's in the red housing.
pinMode(ledBackRight, OUTPUT);
pinMode(ledReverseLeft, OUTPUT); //The reverse lights should be used as long as they have a clear housing and are easily visible.
pinMode(ledReverseRight, OUTPUT);
}

//Declaring the flash patterns

void 3flash(){ //3x flash pattern
digitalWrite(ledFrontLeft, HIGH); //Flashes alternate LED's in the front and back 3x
digitalWrite(ledFogLightRight, HIGH);
digitalWrite(ledBackRight, HIGH);
digitalWrite(ledReverseLeft, HIGH);
delay(50);
digitalWrite(ledFrontLeft, LOW);
digitalWrite(ledFogLightRight, LOW);
digitalWrite(ledBackRight, LOW);
digitalWrite(ledReverseLeft, LOW);
delay(50);
digitalWrite(ledFrontLeft, HIGH); 
digitalWrite(ledFogLightRight, HIGH);
digitalWrite(ledBackRight, HIGH);
digitalWrite(ledReverseLeft, HIGH);
delay(50);
digitalWrite(ledFrontLeft, LOW);
digitalWrite(ledFogLightRight, LOW);
digitalWrite(ledBackRight, LOW);
digitalWrite(ledReverseLeft, LOW);
delay(50);
digitalWrite(ledFrontLeft, HIGH); 
digitalWrite(ledFogLightRight, HIGH);
digitalWrite(ledBackRight, HIGH);
digitalWrite(ledReverseLeft, HIGH);
delay(50);
digitalWrite(ledFrontLeft, LOW);
digitalWrite(ledFogLightRight, LOW);
digitalWrite(ledBackRight, LOW);
digitalWrite(ledReverseLeft, LOW);
delay(50);

digitalWrite(ledFrontRight, HIGH);
digitalWrite(ledFogLightLeft, HIGH);
digitalWrite(ledBackLeft, HIGH);
digitalWrite(ledReverseRight, HIGH);
delay(50);
digitalWrite(ledFrontRight, LOW);
digitalWrite(ledFogLightLeft, LOW);
digitalWrite(ledBackLeft, LOW);
digitalWrite(ledReverseRight, LOW);
delay(50);
digitalWrite(ledFrontRight, HIGH); 
digitalWrite(ledFogLightLeft, HIGH);
digitalWrite(ledBackLeft, HIGH);
digitalWrite(ledReverseRight, HIGH);
delay(50);
digitalWrite(ledFrontRight, LOW);
digitalWrite(ledFogLightLeft, LOW);
digitalWrite(ledBackLeft, LOW);
digitalWrite(ledReverseRight, LOW);
delay(50);
digitalWrite(ledFrontRight, HIGH); 
digitalWrite(ledFogLightLeft, HIGH);
digitalWrite(ledBackLeft, HIGH);
digitalWrite(ledReverseRight, HIGH);
delay(50);
digitalWrite(ledFrontRight, LOW);
digitalWrite(ledFogLightLeft, LOW);
digitalWrite(ledBackLeft, LOW);
digitalWrite(ledReverseRight, LOW);
delay(50);
}

void altFlash(){ //Alternating flashing
digitalWrite(ledFrontLeft, HIGH);
digitalWrite(ledFogLightRight, HIGH);
digitalWrite(ledBackRight, HIGH);
digitalWrite(ledReverseLeft, HIGH);
delay(50);
digitalWrite(ledFrontLeft, LOW);
digitalWrite(ledFogLightRight, LOW);
digitalWrite(ledBackRight, LOW);
digitalWrite(ledReverseLeft, LOW);
delay(50);

digitalWrite(ledFrontRight, HIGH);
digitalWrite(ledFogLightLeft, HIGH);
digitalWrite(ledBackLeft, HIGH);
digitalWrite(ledReverseRight, HIGH);
delay(50);
digitalWrite(ledFrontRight, LOW);
digitalWrite(ledFogLightLeft, LOW);
digitalWrite(ledBackLeft, LOW);
digitalWrite(ledReverseRight, LOW);
delay(50);
}

void Strobe(){  //Strobe all lights at the same time
digitalWrite(ledFrontLeft, HIGH);
digitalWrite(ledFrontRight, HIGH);
digitalWrite(ledFogLightLeft, HIGH);
digitalWrite(ledFogLightRight, HIGH);
digitalWrite(ledBackLeft, HIGH);
digitalWrite(ledBackRight, HIGH);
digitalWrite(ledReverseLeft, HIGH);
digitalWrite(ledReverseRight, HIGH);
delay(50);
digitalWrite(ledFrontLeft, LOW);
digitalWrite(ledFrontRight, LOW);
digitalWrite(ledFogLightLeft, LOW);
digitalWrite(ledFogLightRight, LOW);
digitalWrite(ledBackLeft, LOW);
digitalWrite(ledBackRight, LOW);
digitalWrite(ledReverseLeft, LOW);
digitalWrite(ledReverseRight, LOW);
delay(50);
}

void off(){ //Off statement
digitalWrite(ledFrontLeft, LOW);
digitalWrite(ledFrontRight, LOW);
digitalWrite(ledFogLightLeft, LOW);
digitalWrite(ledFogLightRight, LOW);
digitalWrite(ledBackLeft, LOW);
digitalWrite(ledBackRight, LOW);
digitalWrite(ledReverseLeft, LOW);
digitalWrite(ledReverseRight, LOW);
}

void loop() {
buttonState = digitalRead(buttonPin);
//buttonMode = 0; Uncomment if necessary.

if (buttonState == HIGH){ //When the button is pressed, it adds to the counter, and changes mode.
buttonMode++;
delay(500);
}

if (buttonMode == 0){
off;
}

while (buttonMode == 1){ //While the buttonMode variable equals 1, it will forever loop the LED's until the variable changes.
for(;;){
3flash;
}
}

while (buttonMode ==2){
for(;;){
altFlash;
}
}

while (buttonMode ==3){
for(;;){
Strobe
}
}

while (buttonMode ==4){
for(;;){
3flash;
altFlash;
Strobe;
}
}

if (buttonMode == 4){ //In mode 5, the counter is reset to 0, forcing the lights to turn off.
buttonMode = 0;
}
}
3flash;

Nope, sorry.

One of the most useful features of the IDE is the auto-format tool.
Please use it before posting code.

You're also still missing the bit about there being no way of testing the change of state within your infinite loops.

One way to consider implementing lighting patterns without delays is to create a function for each block of code in between the delays. Then create an array of function pointers containing all these and an array with the delay values. Example:

void allOn() { // code here }
void allOff() { // code here }
void halfOn() { // code here }
void halfOff() { // code here }

// Create an array of function pointers
void (*steps[4]) () = { allOn, allOff, halfOn, halfOff };
// Create an array of interval times
unsigned long intervals[4] = { 0, 50, 50, 50 };

You then need a variable to keep track of where you are in your arrays and last time you moved on:

int t=0;
unsigned long lastChange=0;

Then in your loop, you check if it's been long enough:

if (millis() - lastChange > intervals[t]) {
  ...
}

Then you simple have to reset the timer, run the appropriately indexed function, and increment your index. Of course, you'll also have to check if the index goesd above your bounds and reset it to 0. Completely untested, but this should give you a good template to use as it is organized, uses no delays, and scales up very easily.

Keep in mind that I am not home, and do not have the IDE on my work computer. I am using notepad. I will definitely look over everything said, and do research to find out what works and what doesn't.

Arrch:
One way to consider implementing lighting patterns without delays is to create a function for each block of code in between the delays. Then create an array of function pointers containing all these and an array with the delay values. Example:

void allOn() { // code here }

void allOff() { // code here }
void halfOn() { // code here }
void halfOff() { // code here }

// Create an array of function pointers
void (*steps[4]) () = { allOn, allOff, halfOn, halfOff };
// Create an array of interval times
unsigned long intervals[4] = { 0, 50, 50, 50 };




You then need a variable to keep track of where you are in your arrays and last time you moved on:


int t=0;
unsigned long lastChange=0;




Then in your loop, you check if it's been long enough:


if (millis() - lastChange > intervals[t]) {
  ...
}




Then you simple have to reset the timer, run the appropriately indexed function, and increment your index. Of course, you'll also have to check if the index goesd above your bounds and reset it to 0. Completely untested, but this should give you a good template to use as it is organized, uses no delays, and scales up very easily.

@Arrch So basically what you are saying is, put the LED's I want on in a "void()" statement, and make enough for it to flash properly. Then use the intervals set in place to switch between the "void()" statements? I kind of see what you mean. I am not completely understanding though.

wally_z:
@Arrch So basically what you are saying is, put the LED's I want on in a "void()" statement, and make enough for it to flash properly. Then use the intervals set in place to switch between the "void()" statements? I kind of see what you mean. I am not completely understanding though.

Each function statement should contain an "instantaneous" action. A simple example would be this:

void loop() {
  // At this "instant" you want to turn led 3 on and led 2 off
  digitalWrite(3, HIGH); 
  digitalWrite(2, LOW);
  delay(500);
  // At this "instant" you want to turn led 2 on and led 3 off
  digitalWrite(3, LOW);
  digitalWrite(2, HIGH);
delay(500);
}

Any digitalWrite commands that happen between delays happen "instantaneously." That usually involves turning on some LED and turning off others. Those commands are placed in a single function so that you just have to call that single function for all of those to happen at that instant. It then moves on to the next interval and repeats once that interval is reached.

Of course, it's not actually instantaneous, it just appears to be to the naked eye.