Simple RGB LED color changing loop doubles last color

I created the following program as a starting point for a project to turn and Arduino into a DMX controller.

I started by creating a simple program that when running will simply cycle my DMX lighting and an on-board RGB LED from one color to the next until it gets to the last color then repeat.

The problem is it always displays the last color of the sequence for twice as long as the rest. My programming skills are limited and I cannot figure out why. I am using millis() and not just delays as the next phase of the program will introduce an IR remote and a MIDI foot controller for additional inputs.

Please help if you can.

/* This program created by Ken Barrett on Mar 31, 2016
* It is design to use the Arduino Mega as a DMX controller
* It also uses a simple RGB LED as a debug light when no DMX device connected
* 
* DMX channels controlled are as follows:
* 1.  Red Par Can 
* 2.  Blue Par Can
* 3.  Yellow Par Can
* 4.  Green Par Can
* 5.  Dimmer on Microh LEDP64KDII
*       0 - 189 Dimmer
*       190 - 250 Flash
*       251 - 255 No Function
* 6.  Red channel of Microh LEDP64KDII
* 7.  Green channel of Microh LEDP64KDII
* 8.  Blue channel of Microh LEDP64KDII
* 9.  Red channel of Ledge LED Strip Light
* 10. Green channel of Ledge LED Strip Light
* 11. Blue channel of Ledge LED Strip Light
* 12. Red channel of Left Box LED Strip Light
* 13. Green channel of Left Box LED Strip Light
* 14. Blue channel of Left Box LED Strip Light
* 15. Red channel of Right Box LED Strip Light
* 16. Green channel of Right Box LED Strip Light
* 17. Blue channel of Right Box LED Strip Light
* 
*/

#include <DmxSimple.h>

/*************************************************************************/
const int redPin = 11;  // R petal on RGB LED module connected to digital pin 11 
const int greenPin = 10;  // G petal on RGB LED module connected to digital pin 10 
const int bluePin = 9;  // B petal on RGB LED module connected to digital pin 9 
/* The most common pin for DMX output is pin 3, which DmxSimple
** uses by default. If you need to change that, do it here. */
const int dmxPin = 3;  // DMX ouput pin selection
/**************************************************************************/

// constants used here to set max DMX channels:
const int maxChan =  17;      // max DMX channels to be used

/* Use arrays to store the DMX channel intensities
* Each index of the array will correspond to a different channel
* Each scene will be a different array
* As DMX channels max out at 255 byte arrays will be used
* maxChan will be used to set the size of each array to easily
*/

byte redScene[maxChan] = {255, 0, 0, 0, 189, 255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0};
byte greenScene[maxChan] = {0, 0, 0, 255, 189, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0};
byte blueScene[maxChan] = {0, 255, 0, 0, 189, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 255};
byte yellowScene[maxChan] = {0, 0, 255, 0, 189, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0};
byte cyanScene[maxChan] = {0, 255, 0, 255, 189, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255};
byte magentaScene[maxChan] = {255, 255, 0, 0, 189, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255};
byte whiteScene[maxChan] = {255, 255, 255, 255, 189, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255};
byte blackoutScene[maxChan] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

// set variable for first scene array pointer
int currentScene = 0;

// Chases will use 2D arrays
// first create a variable for the max row pointer for each chase (one less than total rows)
int rgbChaseSize = 6;
// setup array for DMX chase scene values
byte rgbDmxchase [] [maxChan] = {
  {255, 0, 0, 0, 189, 255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0},
  {0, 0, 0, 255, 189, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0},
  {0, 255, 0, 0, 189, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 255},
  {255, 255, 0, 0, 189, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255},
  {0, 255, 0, 255, 189, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255},
  {0, 0, 255, 0, 189, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0},
  {255, 255, 255, 255, 189, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
};

// setup array for RGB LED chase scene values
byte rgbLedchase [] [3] = {
  {255, 0, 0},
  {0, 255, 0},
  {0, 0, 255},
  {255, 0, 255},
  {0, 255, 255},
  {255, 255, 0},
  {255, 255, 255}
};

// The value will quickly become too large for an int to store
unsigned long previousMillis = 0;        // will store last time scene was changed

// setup constants for scene length and fade times :
const long sceneTime = 500;           // interval for scene to stay on (milliseconds)
// const long fadeTime = 100;           // interval to fade from scene to scene (milliseconds)

void setup() {
  DmxSimple.usePin(dmxPin);

  /* DMX devices typically need to receive a complete set of channels
  ** even if you only need to adjust the first channel. You can
  ** easily change the number of channels sent here. If you don't
  ** do this, DmxSimple will set the maximum channel number to the
  ** highest channel you DmxSimple.write() to. */
  DmxSimple.maxChannel(maxChan);
}

void loop() {
  // check to see if it's time to change the scene; that is, if the
  // difference between the current time and last time you changed
  // the scene is bigger than the interval (sceneTime) at which you want to
  // hold the scene.
  unsigned long currentMillis = millis();
  
  if (currentMillis - previousMillis >= sceneTime) {
    // save the last time you changed the scene
    previousMillis = currentMillis;

    // Scene has run long enough so it is time to change it
    // 
    if (currentScene > rgbChaseSize) {
      // once we have made it to the last row of array we need to reset to first
      currentScene = 0;
      } else {
      for (int i=0; i < maxChan; i++){
        // DMX channels start at 1 but arrays start at 0 so we need to create a channel variable
        int chan = i + 1;
        // set current channel to the value stored in the array
        DmxSimple.write(chan, rgbDmxchase [currentScene] [i]);
      } 
      // here we will output the RGB LED color for this scene in the chase
      color(rgbLedchase [currentScene] [0], rgbLedchase [currentScene] [1], rgbLedchase [currentScene] [2]);
      // all channels are now set so we can increment current scene
      currentScene++;      
    }
  }
}

/******************************************************/
void color (unsigned char red, unsigned char green, unsigned char blue)     // the color generating function  
{    
  analogWrite(redPin, red);   
  analogWrite(greenPin, green); 
  analogWrite(bluePin, blue); 
}
/******************************************************/

Thanks Ken

change to:

    // Scene has run long enough so it is time to change it
    //
    if (currentScene > rgbChaseSize)
      // once we have made it to the last row of array we need to reset to first
      currentScene = 0;

    for (int i = 0; i < maxChan; i++) {
      // DMX channels start at 1 but arrays start at 0 so we need to create a channel variable
      int chan = i + 1;
      // set current channel to the value stored in the array
      DmxSimple.write(chan, rgbDmxchase [currentScene] [i]);
    }
    // here we will output the RGB LED color for this scene in the chase
    color(rgbLedchase [currentScene] [0], rgbLedchase [currentScene] [1], rgbLedchase [currentScene] [2]);
    // all channels are now set so we can increment current scene
    currentScene++;

(e.g. remove the else clause)

Doing that change does not turn on any LEDs as the if statement is never true.

Bassman314:
Doing that change does not turn on any LEDs as the if statement is never true.

Did you try it? The if statement should become true because you are continuously incrementing variable "currentscene" every time through the code.

Yes I removed the else clause and uploaded it to my Arduino and nothing happens now. LED never comes on. Was there another edit I was supposed to do as well?

Do you have this?

/* This program created by Ken Barrett on Mar 31, 2016
  It is design to use the Arduino Mega as a DMX controller
  It also uses a simple RGB LED as a debug light when no DMX device connected

  DMX channels controlled are as follows:
  1.  Red Par Can
  2.  Blue Par Can
  3.  Yellow Par Can
  4.  Green Par Can
  5.  Dimmer on Microh LEDP64KDII
        0 - 189 Dimmer
        190 - 250 Flash
        251 - 255 No Function
  6.  Red channel of Microh LEDP64KDII
  7.  Green channel of Microh LEDP64KDII
  8.  Blue channel of Microh LEDP64KDII
  9.  Red channel of Ledge LED Strip Light
  10. Green channel of Ledge LED Strip Light
  11. Blue channel of Ledge LED Strip Light
  12. Red channel of Left Box LED Strip Light
  13. Green channel of Left Box LED Strip Light
  14. Blue channel of Left Box LED Strip Light
  15. Red channel of Right Box LED Strip Light
  16. Green channel of Right Box LED Strip Light
  17. Blue channel of Right Box LED Strip Light

*/

#include <DmxSimple.h>

/*************************************************************************/
const int redPin = 11;  // R petal on RGB LED module connected to digital pin 11
const int greenPin = 10;  // G petal on RGB LED module connected to digital pin 10
const int bluePin = 9;  // B petal on RGB LED module connected to digital pin 9
/* The most common pin for DMX output is pin 3, which DmxSimple
** uses by default. If you need to change that, do it here. */
const int dmxPin = 3;  // DMX ouput pin selection
/**************************************************************************/

// constants used here to set max DMX channels:
const int maxChan =  17;      // max DMX channels to be used

/* Use arrays to store the DMX channel intensities
  Each index of the array will correspond to a different channel
  Each scene will be a different array
  As DMX channels max out at 255 byte arrays will be used
  maxChan will be used to set the size of each array to easily
*/

byte redScene[maxChan] = {255, 0, 0, 0, 189, 255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0};
byte greenScene[maxChan] = {0, 0, 0, 255, 189, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0};
byte blueScene[maxChan] = {0, 255, 0, 0, 189, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 255};
byte yellowScene[maxChan] = {0, 0, 255, 0, 189, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0};
byte cyanScene[maxChan] = {0, 255, 0, 255, 189, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255};
byte magentaScene[maxChan] = {255, 255, 0, 0, 189, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255};
byte whiteScene[maxChan] = {255, 255, 255, 255, 189, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255};
byte blackoutScene[maxChan] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

// set variable for first scene array pointer
int currentScene = 0;

// Chases will use 2D arrays
// first create a variable for the max row pointer for each chase (one less than total rows)
int rgbChaseSize = 6;
// setup array for DMX chase scene values
byte rgbDmxchase [] [maxChan] = {
  {255, 0, 0, 0, 189, 255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0},
  {0, 0, 0, 255, 189, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0},
  {0, 255, 0, 0, 189, 0, 0, 255, 0, 0, 255, 0, 0, 255, 0, 0, 255},
  {255, 255, 0, 0, 189, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255},
  {0, 255, 0, 255, 189, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255},
  {0, 0, 255, 0, 189, 255, 255, 0, 255, 255, 0, 255, 255, 0, 255, 255, 0},
  {255, 255, 255, 255, 189, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}
};

// setup array for RGB LED chase scene values
byte rgbLedchase [] [3] = {
  {255, 0, 0},
  {0, 255, 0},
  {0, 0, 255},
  {255, 0, 255},
  {0, 255, 255},
  {255, 255, 0},
  {255, 255, 255}
};

// The value will quickly become too large for an int to store
unsigned long previousMillis = 0;        // will store last time scene was changed

// setup constants for scene length and fade times :
const long sceneTime = 500;           // interval for scene to stay on (milliseconds)
// const long fadeTime = 100;           // interval to fade from scene to scene (milliseconds)

void setup() {
  DmxSimple.usePin(dmxPin);

  /* DMX devices typically need to receive a complete set of channels
  ** even if you only need to adjust the first channel. You can
  ** easily change the number of channels sent here. If you don't
  ** do this, DmxSimple will set the maximum channel number to the
  ** highest channel you DmxSimple.write() to. */
  DmxSimple.maxChannel(maxChan);
}

void loop() {
  // check to see if it's time to change the scene; that is, if the
  // difference between the current time and last time you changed
  // the scene is bigger than the interval (sceneTime) at which you want to
  // hold the scene.
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= sceneTime) {
    // save the last time you changed the scene
    previousMillis = currentMillis;

    // Scene has run long enough so it is time to change it
    //
    if (currentScene > rgbChaseSize)
      // once we have made it to the last row of array we need to reset to first
      currentScene = 0;

    for (int i = 0; i < maxChan; i++) {
      // DMX channels start at 1 but arrays start at 0 so we need to create a channel variable
      int chan = i + 1;
      // set current channel to the value stored in the array
      DmxSimple.write(chan, rgbDmxchase [currentScene] [i]);
    }
    // here we will output the RGB LED color for this scene in the chase
    color(rgbLedchase [currentScene] [0], rgbLedchase [currentScene] [1], rgbLedchase [currentScene] [2]);
    // all channels are now set so we can increment current scene
    currentScene++;

  }
}

/******************************************************/
void color (unsigned char red, unsigned char green, unsigned char blue)     // the color generating function
{
  analogWrite(redPin, red);
  analogWrite(greenPin, green);
  analogWrite(bluePin, blue);
}
/******************************************************/

That works. Forgot to remove the opening brace on the if line along with the else line.

Thanks for your help!

Ken