LED schedule

Hi,
I want to program a daily schedule program for about 20 LEDs. The schedule is set by an array of events [timestamp, pin, value]. I like the value to increase smoothly from one event to the next one.
example 1: {0,1,0},{400,1,200} --> increase value by one every 2 seconds, 200 times
example 2: {400,1,200},{410,1,220} --> increase value by two every second, 10 times

First I thought about generating a temporary array for all individual steps, but this array could get really big. Each entry has 31bits (17bit time, 6bit pin, 8bit value) or 3.9bytes and has a maximum of 255 steps per LED. For 20 LEDs this is 19.9kB. So that’s it for the easy way.
My new thought is to calculate the current values for each LED in each loop, but as this isn’t a very nice solution I am searching for other suggestions.
Hopefully I get some ideas.

Best regards,
Kevin

You have an end value, an increment/decrement value and the current value along with a time value.

You can store the control array in program memory - can't change it unless you upload a new copy of the sketch.

3 bytes for the analog output info (0-255) and 1 INT for the time.100 bytes of RAM.

The calulate each time throught he loop means that you don't have to use as much RAM, and that is the commodity you have to conserve.

Attach a serial SRAM and store the array there. Than can make it as big as you want.

example 1: {0,1,0},{400,1,200} --> increase value by one every 2 seconds, 200 times
example 2: {400,1,200},{410,1,220} --> increase value by two every second, 10 times

I'm not following that exactly, but that sounds like a couple of loops to me! :wink:

When you say, "Do something 200 times", you are describing a loop-application. Of course, you can combine if-statements along with AND & OR logic if you don't want to do exactly the same thing each time through the loop, or if there is a condition where you want to break-out of the loop. And, you can use nested loops such as a 200-count outside loop for whatever you are doing 200 times plus a 20-count inside-loop for each LED, etc. (If that makes sense in your application).

My new thought is to calculate the current values for each LED in each loop, but as this isn’t a very nice solution I am searching for other suggestions.

You shouldn't need to "calculate" the current value... You have to know the value before you write it (output it), then you just have to remember it. So, you might need an array of 20 values to keep track of the values for each LED (if they are all different). Then, you just add one or two to calculate the next value, when it's time to do so.

@kf2qd: You descripe exactly my initial thoughts of how to save RAM. What bothers me is that the calculations could take some time every loop. If I try to do some parallel operations (e.g. reading some sensors) it might get pretty laggy.

@CrossRoads: This seems to be the best solution, but I don't have any ideas of where to get or how to install or use such a RAM. Could you give me some hints?

@DVDdough: Of course I need a loop. But I don't need a seperate loop for each LED. I planned cycling through the native loop, just checking every time if I should increase or decrease a value this time.
The bis question is, if I should do so by simply comparing the current time to timestamps in an array of steps (which needs a lot of RAM) or if I should recalculate all possible next steps in every loop (which slows it down).
"Calculating current value" means calculating the new current value, which should be set, not the ones already set.

Not much to hook up - +3.3V, Gnd, 0.1uF cap from 3.3V to Gnd.
Need a voltage level translator chip as well, like TXB0104 for the SCK, MISO, MOSI, Chip Select connections between the Arduino and the chip.
Probably 10K resistor from Hold/ to 3.3V also.

KevinT:
example 1: {0,1,0},{400,1,200} --> increase value by one every 2 seconds, 200 times
example 2: {400,1,200},{410,1,220} --> increase value by two every second, 10 times

So the first number is a time in seconds, the second is the PWM output pin, and the third is the PWM value at the specified time.

I remember writing such a sketch to simulate sunrise and sunset with color LED's but I can't find that sketch. It was for someone in the forums so I posted it here somewhere!

thanks for the RAM-hints. I'll read a little.

@johnwasser: That seems to be the sketch.
http://arduino.cc/forum/index.php/topic,95007.0.html

Thats a completely new approach. This sure helps. But as I need more than one fade per pin I need to adapt the code a bit.

Thanks again.

Now I think I have the final code. As my arduino broke I cannot check it, but it should do what I want.
I would like to convert this into a library, but I need help.

First of all: Are there any gerneral notes to this code? Anything problematic you see in it?
Second: Are there any general demands I need to meet to create a library?

here is my code so far:

#define max_milliseconds   86400000           // seconds per day
#define max_chanels   15                      // 3x RGBWW
#define max_programs  15                      // should be at least max_chanels
#define max_events    100                     // max. changes per day
#define max_calcArray 4                       // should be one for each color

class cEvent
{
  public:
    long   time;                              // timestamp | milliseconds until 00:00
    byte   bright;                            // brightness | 0-255
};

class cProgram
{
  public:
    cEvent arrEvents[max_events];
};

class cChanel
{
  public:
    cProgram  *currProgram;                   // pointer to current program
    cProgram  *strdProgram;                   // pointer to standard program
    int        actEvent;                      // active event | or rather passed event
    byte       pin;                           // pin for this chanel
    byte       calcArray;                     // ID of color | ID of corresponding gamma array
    int        SizeArrEvent;                  // size of the array arrEvents
    long       tmpEndTime;                    // end time of temporary setting
    boolean    tmpActive;                     // status of temporary setting
};

cProgram  arrPrograms[max_programs];          // array of all possible programs
cProgram  arrTmpProg[max_chanels];            // array of temporary programs for each chanel
cChanel  *arrChanels[max_chanels];            // array of all active chanels | one chanel has one pin

byte      arrGamma[max_calcArray][256];       // array to get LED-value from brightness

// sets the initial settings
void initialize()
{
  // for the test: gamma is linear
  for (byte i = 0; i <=255; i++) {arrGamma[1][i] = i;}

  // chanel 0 has sunrise at 07:00 (2h) and sunset at 17:00 (2h)
  arrChanels[0]->currProgram = &arrPrograms[0];
  arrChanels[0]->pin                 = 14;
  arrChanels[0]->actEvent            = 0;
  arrChanels[0]->calcArray           = 0;
  arrPrograms[0].arrEvents[0].time   = 25200000;
  arrPrograms[0].arrEvents[0].bright = 0;
  arrPrograms[0].arrEvents[1].time   = 32400000;
  arrPrograms[0].arrEvents[1].bright = 191;
  arrPrograms[0].arrEvents[2].time   = 61200000;
  arrPrograms[0].arrEvents[2].bright = 191;
  arrPrograms[0].arrEvents[3].time   = 68400000;
  arrPrograms[0].arrEvents[3].bright = 0;

  // FOR TEST: chanel 1 starts rising 20 seconds after program start, holds 3 seconds and dims down again
  arrChanels[1]->currProgram = &arrPrograms[1];
  arrChanels[1]->pin                   = 15;
  arrChanels[1]->actEvent            = 0;
  arrChanels[1]->calcArray           = 0;
  arrPrograms[1].arrEvents[0].time   = getDayTime() + 20000;
  arrPrograms[1].arrEvents[0].bright = 0;
  arrPrograms[1].arrEvents[1].time   = arrChanels[1]->currProgram->arrEvents[0].time + 5000;
  arrPrograms[1].arrEvents[1].bright = 255;
  arrPrograms[1].arrEvents[2].time   = arrChanels[1]->currProgram->arrEvents[1].time + 3000;
  arrPrograms[1].arrEvents[2].bright = 255;
  arrPrograms[1].arrEvents[3].time   = arrChanels[1]->currProgram->arrEvents[2].time + 10000;
  arrPrograms[1].arrEvents[3].bright = 0;

}

// get time of day in milliseconds from 00:00
long getDayTime()
{
  // here will be the reading the clock code
}

// calculates the time difference between timeA and timeB
long tDiff(long timeB, long timeA)
{
  // rollover
  if (timeB < timeA) timeB = timeB + max_milliseconds;
  return (timeB - timeA);
}

// checks if event is last event and calculates next event
int nextEvent(int Ch, int event)
{
  if (event < arrChanels[Ch]->SizeArrEvent) {
    return event + 1;
  } else {
    return 0;
  }
}

//calculates and sets value of a single chanel (pin)
void setBrightness(byte Ch, long time)
{
  int event;
  long time1;
  long time2;
  boolean eventChecked = false;

  do
  {
    event = arrChanels[Ch]->actEvent;
    time1 = arrChanels[Ch]->currProgram->arrEvents[event].time;
    time2 = arrChanels[Ch]->currProgram->arrEvents[nextEvent(Ch, event)].time;
    // move to next event if necessary
    if ((tDiff(time,time2)) < (tDiff(time,time1))) {arrChanels[Ch]->actEvent = nextEvent(Ch,event);} else {eventChecked = true;}
  } while (!eventChecked);

  byte bright1 = arrChanels[Ch]->currProgram->arrEvents[event].bright;
  byte bright2 = arrChanels[Ch]->currProgram->arrEvents[nextEvent(Ch, event)].bright;

  // milliseconds per one increment
  int millisPerInk = round((tDiff(time2,time1)) / (bright2 - bright1));

  byte brightness = byte(bright1 + ((tDiff(time,time1)) / millisPerInk));
    
  byte value = arrGamma[arrChanels[Ch]->calcArray][brightness];
  analogWrite(arrChanels[Ch]->pin, value);
}

void setup()
{
  initialize();
}

void loop()
{
  long tNow = getDayTime();
  // check if temporary programs are active
  for (byte i = 0; i < max_chanels; i++) {
    if (arrChanels[i]->tmpActive) {
      if (arrChanels[i]->tmpEndTime == 0) { // 0 is for endless
        if (tDiff(tNow,arrChanels[i]->tmpEndTime) < (max_milliseconds - 3000)) { // still active
          arrChanels[i]->currProgram = &arrTmpProg[i];
        } else {
          arrChanels[i]->tmpActive = false;
          arrChanels[i]->currProgram = arrChanels[i]->strdProgram;
        }
      }
    }
  }
  // if this is to slow than I change to one pin per loop
  for (byte chanel = 0; chanel < max_chanels;chanel++) {setBrightness(chanel,tNow);}
}