Fade and Chase some lights in ONE system

So, shortly after you become a professional in this railroad hobby, you start getting good at this, build a Fading LED here and a chaser on a movie theater over there, and then you realize, I have enough pins on one Arduino to maybe combine the two.

After you waited for the coffee machine to finish, you move over to the microwave to wait for the bacon to cook and after that you push the bread into the toaster, and stand there and wait to get the jolt when the toast pops out and then you realize that your coffee is cold. Well, that is not how we make breakfast, you get it all started and tend to it as each task completes and have a full tummy in a third of the time.

With the Arduino's single thread, you can't really schedule them like your microwave, because you still need to make the 'waves'. If you simply use 'delay()' to wait for time to go by, everything else has to wait too, so what we do here is use 'millis()' to tell use how much time has gone by since the chip started running, compare that to a value we stored, and when 2 minutes went by, we pop the bread from the toaster, when 3 minutes has gone by since we started the microwave, we take the bacon out of the microwave, and every 5 minute mark, we make the next cup of coffee.

This is a lot easier when we use Object Orientated Programming (OOP), since all the data and code stays together and we can reuse it over and over, without raking 50 lines of code from an older program. You simply copy the Class over, make the object you need (instantiate, sorry) with the pins and timeouts required, and then call the Update() function when you want to, so it can figure out if enough time as gone by to do the next thing. So in the end you have:
void loop() {
  chaser1.Update();
fader1.Update();
fader2.Update();
} // and that is the end of your loop!
So here is the code we combined for Vance's Haunted House (fading in and out the lights of the top and bottom floor, one after the other) and the Chasing lights on or around his movie theater sign (notice no delay() anywhere!!!):
// Fading FADE1 and FADE2 LEDs in and out, one after the other, like the 
// top and bottom floor of a haunted house;
// while also running CHASING LEDs,
// 1 thru 6 (max 10), like on top of a movie theater.
//
// Two classes, FadeLite to fade a light from off to on and from on to off when needed.
// ChaseLites for turning LEDs on in a sequence.
//
// Author Vance Nurmi, under very tight supervision of Speed
// Version 1.2 on 2016/07/08
//
// Chaser LED pin numbers 
#define CHASE6   7          
#define CHASE5   6          
#define CHASE4   5
#define CHASE3   4
#define CHASE2   3
#define CHASE1   2

// Fading LED pins
#define FADE1    9
#define FADE2   10
     
int analog0Pin = A0;      // button to start wave
int val0 = 0;             // variable to store the value read

// time in milliseconds, better values for a demo
#define FADETIME    1000
#define UPDATETIME    50
#define CHASERTIME   150

#define MAXCHASELITES 10

class FadeLite {
  // Class Member Variables
  // These are initialized at startup
  int ledPin;              // the number of the LED pin
  long int fadeTime;       // how long to spend fading
  long int stepSize;       // size of steps to take to fade
  long int updateTime;     // how often to update
   
  // These maintain the current state
  int ledState;             		  // ledState used to set the LED, 0 off, 1 on, 2 fading to on, 3 fading to off
  int ledValue;                           // 0 thru 255 for full off thru full on
  unsigned long previousMillis;           // will store last time LED was updated
   
  void Output() {
    analogWrite( ledPin, ledValue );   
  } // Outout

  public:
  // Constructor - creates a Flasher 
  // and initializes the member variables and state
  FadeLite( int pin, long int fTime ) {
    ledPin = pin;
    pinMode( ledPin, OUTPUT ); 
    updateTime = UPDATETIME;
    fadeTime = fTime;
    stepSize = int( 256 * ( (1.0 * UPDATETIME ) / ( 1.0 * fadeTime ) ) ); 
    if ( stepSize < 1 ) { 
      stepSize = 1; 
      updateTime = fadeTime / 255;
    } // if
    	  
    FullOff();
    previousMillis = millis();
  } // FadeLite constructor

  // I used this to send some serial data to the PC. Nice to use when you need
  // to see what the math looks like when you want to increase the updatetime since
  // your steps are already 255 and you want the fading to take longer than UPDATETIME * 255!

  void FullOn() {      
    ledValue = 255;
    ledState = 1;
    Output();  
  } // FullOn

  void FullOff() { 
    ledValue = 0;
    ledState = 0;
    Output();  
  } // FullOff

  void Reset() {
    FullOff();
    previousMillis = millis();  
  } // Reset
  
  bool IsOn() {
    return ledState == 1;
  } // IsOn()
  
  bool IsOff() {
    return ledState == 0;
  } // IsOff()
  
  void Toggle() {
    if ( ledState == 0 ) {
      //FullOn();//
      TurnOn();
    } else {
      if ( ledState == 1 ) {
      //FullOff(); //
      TurnOff();
      } // if
    } // if      
  } // Toggle()

  void TurnOn() {
    ledState = 2;
  } // TurnOn()
  
  void TurnOff() {
    ledState = 3;
  } // TurnOff()
  
  void Update() {
    // check to see if it's time to change the state of the LED
    unsigned long now = millis();
     
    if ( now - previousMillis >= updateTime ) {
      previousMillis = now;

      switch ( ledState ) {
      case 0:
        break;
      case 1:        
        break;
      case 2:  
        ledValue += stepSize;
        if ( ledValue >= 255 ) {
          ledValue = 255;   
          ledState = 1;
        } // if on 
        break;
      case 3:        
        ledValue -= stepSize;
        if ( ledValue <= 0 ) {
          ledValue = 0;   
          ledState = 0;
        } // if of       
        break;          
      }; // switch
      Output();                           // Update the actual LED
    } // if, time for change yet?
  } // Update
}; // FadeLite

class ChaseLites {
  // Class Member Variables
  // These are initialized at startup
  int led[MAXCHASELITES];                 // array storing LED pins
  int numLEDs;
  long int updateTime;                    // how often to update
   
  // These maintain the current state
  int whichLedOn = 4;                     // 0 is none
  int ledState;                           // 0 off, 1 running
  unsigned long previousMillis;           // will store last time LED was updated
   
  public:
  // Constructor - creates a Flasher 
  // and initializes the member variables and state
  ChaseLites( long int fTime, int numPins, int pins[] ) {
    numLEDs = numPins;
    ledState = 0;  // off
    for ( int i = 0; i < numLEDs; i++ ) {
      led[i] = pins[i];
      pinMode( led[i], OUTPUT );
      //digitalWrite( led[i], LOW ); 
    } // for
    
    updateTime = fTime;
 
    FullOff();
    previousMillis = millis();
  } // FadeLite constructor

  void Output() {
    if ( ledState == 1 ) {
      for ( int i = 0; i < numLEDs; i++ ) {                // run through all the LEDs
        digitalWrite( led[i], whichLedOn == i?HIGH:LOW );  // and only turn the selected one on
      } // for
    } else {
      for ( int i = 0; i < numLEDs; i++ ) {               // run through all the LEDs
        digitalWrite( led[i], LOW );                       // and turn them off
      } // for     
    } // if ledState on
  } // Outout

  void FullOff() { 
    ledState = 0;
    Output();  
  } // FullOff

  void Reset() {
    FullOff();                           // turn all off 
    previousMillis = millis();           // and reset the previousTime
  } // Reset
  
  bool IsAnyOn() {
    return ledState != 0;
  } // IsOn()
  
  bool IsOff() {
    return ledState == 0;
  } // IsOff()
 
  void TurnOff() {
    ledState = 0;
    Output();
  } // TurnOff()
  
  void Update() {
    // check to see if it's time to change to the next LED
    unsigned long now = millis();                    // the time now
     
    if ( now - previousMillis >= updateTime ) {      // if it is time for the next one
      previousMillis = now;                          // save the time
      whichLedOn++;                                  // and increase to the next LED
      if ( whichLedOn >= numLEDs ) whichLedOn = 0;   // if at max, go back to zero
      Output();                                      // Update the actual LED
    } // if, time for change yet?
  } // Update
}; // ChaseUpTo10LEDs

// creating the objects
FadeLite fader1( FADE1, FADETIME );
FadeLite fader2( FADE2, FADETIME );
boolean leftOn;                                      // we are using a variable to keep track of which FadeLite to fade.

int chaserPins[] = { CHASE1, CHASE2, CHASE3, CHASE4, CHASE5, CHASE6 };    // simply add or remove a pin here
ChaseLites chaser1( CHASERTIME, sizeof( chaserPins) 
                    / sizeof( chaserPins[0] ), chaserPins );              // this will figure out how many pins in use

void setup() {
  pinMode( analog0Pin, INPUT );
 
  Serial.begin( 115200 );                                                 //  setup serial for 115200 baud
  Serial.println( "Fade_and_Chase version 2016.07.08_1.2" );              //  print the version, use Ctrl-M to see
  
  leftOn = true;                                                          // starting with the left LED
  fader1.TurnOn();  // need to turn it on to get it out of state 0        // and tell it we are turning it on
} // setup

void loop() {
  chaser1.Update();                                                       // chaser is ready, update it!
  
  // the next if code will cycle between fader1 and fader2, fading it in and and out, one after the other
  // could have created a Class that uses two pins and deal with this internally, and then you only need fadeTwo.Update()
  if ( leftOn ) {
    // do fader1 this round
    fader1.Update();        // update the first one
    if ( fader1.IsOn() )    // if it is fully on, turn it off now
      fader1.TurnOff();
 
    if ( fader1.IsOff() ) { // when it is fully off, lets go back to the other lite
      fader2.TurnOn();      // need to turn it on to get it out of state 0
      leftOn = false;
    } // if
  } else {  
    // do fader2 now
    fader2.Update();        // update the second one, if it is its turn
    if ( fader2.IsOn() )    // if it is fully on, turn it off now
      fader2.TurnOff();
      
    if ( fader2.IsOff() ) { // when it is fully off, lets go back to the other lite
      fader1.TurnOn();      // need to turn it on to get it out of state 0
      leftOn = true;
    } // if
  } // else
} // loop



ċ
FADE_and_CHASE_v1_2.ino
(8k)
Gert (TxAdmin) Muller,
Jul 8, 2016, 8:11 PM
Comments