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.
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!
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!
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);}
}