Go Down

Topic: Need Help With Police Light Modes (Read 2 times) previous topic - next topic

wally_z

Hello,

I am having quite a bit of trouble getting my code to work the way I would like. I am a volunteer firefighter, and I refuse to spend $200 on a light bar, when I can make one for around $30. This is how it works:

-Turn on, set button state, and mode to 0 "off"
-Once button is pressed, add 1 to the mode
-In mode 0, (the default), all the LED's are off
-In mode 1, the LED's flash a certain pattern (Supposed to loop UNTIL you push the button)
-Every time you push the button, the mode changes
-In mode 2, the LED's flash a different pattern
-In mode 3, the mode is reset to 0, making the LED's stop flashing.

The problem is that when the board is in the first mode, the LED's flash FOREVER, and it cannot change mode. I need it to change mode so I can use different flash patterns. This probably isn't working because of the "while" statements used.

TL;DR I want it to loop until I push the button. I cannot figure out how. It loops forever and won't change mode.

I cannot paste the code into this window because it exceeds the maximum allowed length of a post, so I will be attaching it to this post so you may review it at your pleasure.

Jack Christensen

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.
MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

wally_z

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

Jack Christensen

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.

Code: [Select]
#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
   }      

}
MCP79411/12 RTC ... "One Million Ohms" ATtiny kit ... available at http://www.tindie.com/stores/JChristensen/

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.

Go Up