Dag Sterretje,
Mooie schets heb je geschreven, zoals ook voor Jarno Fokker met zijn boerderij in december 2022. Die schets heb ik gebruikt om mijn modelspoorbaan van verlichting te voorzien. Nu worstel ik met het schemerlicht. Ik wil graag het daglicht laten uitfaden en bij 50 procent het rode licht laten infaden. En weer uitfaden tot b.v 50 procent en tegelijk het blauwe in laten faden. Zo ook met het "daglicht", infaden als het blauw voor 50 procent is uitgefade. En andersom, wanneer de dag om is. En dan nog inpassen in jouw schets van de boerderij. Kun je mij aangeven hoe ik dat moet doen? Alvast bedankt.
Hallo led70, ik heb je vraag verhuisd naar zijn eigen onderwerp of op het forum. Gelieve niet een onderwerp van andere gebruiken om je vraag te stellen.
Ik heb geen idee om welk programma het gaat voor Jarno Fokker. Ik stel voor dat je je programma hier neer zet (vergeet aub niet zogenaamde code tags te gebruiken zoals beschreven in Hoe haal je het meeste uit het forum).
Het is me niet helemaal duidelijk wat je wilt bereiken. Kun je het in stappen beschrijven?
- Daglicht van 100% naar 50%
- Rood licht van 0% naar 50%.
- Moet het daglicht nog verder naar 0%
- Ander stappen hier.
Dag Sterretje, Leuk dat je zo snel antwoord. Ik stuur hierbij jouw code voor Jarno met (timerstructs)met mijn aanpassingen. Ik heb hier en daar wat geleend dus is het een rommeltje.
Mijn idee is na de nacht, komt het blauwe licht infaden. Bij uitfaden van blauw (tot nul), bijv. bij het punt van 50%, het rode licht infaden en bij het uitfaden van rood, (ook tot nul) bijv. weer bij 50% het daglicht laten infaden. In de avond het zelfde, maar dan andersom. De lantaarnpaaltjes op pinnen 8 en 9 hoeven niet te faden. En pin 5 voor groen gebruik ik nog niet.
Hopelijk ben ik duidelijk genoeg.
```cpp
// DIT IS VOOR LICHTBESTURING VAN MIJN TREINBAAN PER 24 FEBRUARI 2025//
//HIER MAG MEE GEROMMELD WORDEN// werkt nog steeds niet
// ROOD OP PEN 6 //
// GROEN OP PEN 5 //
// BLAUW OP PEN 3 //
// FALLERLAMPJE OP PEN 8 //
// LANTAARNPAAL LEDJES OP PEN 9 //
// DAGLICHTLEDSTRIP OP PEN 10 //
#define NUMELEMENTS(x) (sizeof(x) / sizeof(x[0]))
#define RED_PIN 6
#define GREEN_PIN 5
#define BLUE_PIN 3
#define FALLERLAMPJE 8
#define LANTAARNLED 9
#define LEDSTRIP_PIN 10
//#define setLeds (R,G,B,L);
// # of milliseconds to pause between each pass of the main Arduino loop
//#define Loop_Delay 200
//brightness level of each color (0..255)
int Brightness_R;
int Brightness_G;
int Brightness_B;
int Brightness_L;
int FadeStep_R;
int FadeStep_G;
int FadeStep_B;
int FadeStep_L;
// model tijden
const uint32_t oneMinute = 1000UL;
const uint32_t oneHour = 60000UL;
const uint32_t oneDay = 1440000UL;
struct TIMING
{
const uint32_t timeOn;
const uint32_t timeOff;
};
struct LIGHTS
{
const uint8_t pin;
const TIMING t[4]; // geeft aan dat er 4 schakelmomenten zijn.
};
LIGHTS lightTiming[] = {
{3, {{(4 * oneHour) + (45* oneMinute), (4 * oneHour) + (55* oneMinute)}, {(21 * oneHour) + (50* oneMinute), (22* oneHour)}, {0xFFFFFFFF, 0xFFFFFFFF}, {0xFFFFFFFF, 0xFFFFFFFF}}},
{5, {{0xFFFFFFFF, 0xFFFFFFFF}, {0xFFFFFFFF, 0xFFFFFFFF}}},
{6, {{( 4 * oneHour) + (55 * oneMinute), (5 * oneHour)}, {(21* oneHour) + (45* oneMinute), (21* oneHour)+(50*oneMinute)}, {0xFFFFFFFF, 0xFFFFFFFF}, {0xFFFFFFFF, 0xFFFFFFFF}}},
{8, {{( 21* oneHour) + ( 44 *oneMinute), (5*oneHour) + ( 15*oneMinute)}, {0xFFFFFFFF, 0xFFFFFFFF}, {0xFFFFFFFF, 0xFFFFFFFF}, {0xFFFFFFFF, 0xFFFFFFFF}}},
{9, {{( 21* oneHour) + ( 45 *oneMinute), (5*oneHour) + ( 16*oneMinute)}, {0xFFFFFFFF, 0xFFFFFFFF}, {0xFFFFFFFF, 0xFFFFFFFF}, {0xFFFFFFFF, 0xFFFFFFFF}}},
{10,{{( 5* oneHour), (22*oneHour)},{0xFFFFFFFF, 0xFFFFFFFF}, {0xFFFFFFFF, 0xFFFFFFFF}, {0xFFFFFFFF, 0xFFFFFFFF}}},
} ;
// middernacht
uint32_t midnight;
void setup()
{
Serial.begin(115200);
pinMode(RED_PIN, OUTPUT);
pinMode(GREEN_PIN, OUTPUT);
pinMode(BLUE_PIN, OUTPUT);
pinMode(LEDSTRIP_PIN, OUTPUT);
Brightness_R = 0;
Brightness_G = 0;
Brightness_B = 0;
Brightness_L = 0;
FadeStep_R = 0; //0 These setting for normal ROY G BIV
FadeStep_G = 325; //510
FadeStep_B = 650; //-510
FadeStep_L = 0;
// toon de configuratie
for (uint8_t ltCnt = 0; ltCnt < NUMELEMENTS(lightTiming); ltCnt++)
{
Serial.print(F("Lade "));
Serial.println(ltCnt);
Serial.print(F("\tPin "));
Serial.println(lightTiming[ltCnt].pin);
Serial.println(F("\tTijden"));
for (uint8_t tCnt = 0; tCnt < NUMELEMENTS(lightTiming[ltCnt].t); tCnt++)
{
if (lightTiming[ltCnt].t[tCnt].timeOn == 0xFFFFFFFF)
{
Serial.println(F("\t\tGeen tijden"));
}
else
{
Serial.print(F("\t\tAan "));
Serial.print(lightTiming[ltCnt].t[tCnt].timeOn);
Serial.print(F("\tUit "));
Serial.println(lightTiming[ltCnt].t[tCnt].timeOff);
}
}
}
// zet pinnen als uitgang
for (uint32_t ltCnt = 0; ltCnt < NUMELEMENTS(lightTiming); ltCnt++)
{
pinMode(lightTiming[ltCnt].pin, OUTPUT);
digitalWrite(lightTiming[ltCnt].pin, LOW);
// debugging
Serial.print(F("Pin "));
Serial.print(lightTiming[ltCnt].pin);
Serial.println(F(" output"));
}
// middernacht
midnight = millis();
}
void loop(){
FadeStep_R = FadeStep_R - 1;
FadeStep_G = FadeStep_G - 1;
FadeStep_B = FadeStep_B - 1;
FadeStep_L = FadeStep_L - 1;
//fade red LED according to it's fade step counter.
if (FadeStep_R == -764) {FadeStep_R = 765;}
if (FadeStep_R < 0) {Brightness_R = FadeStep_R * -1;}
if (FadeStep_R >= 510) {Brightness_R = FadeStep_R - 510;}
if (FadeStep_G == -764) {FadeStep_G = 765;}
if (FadeStep_G < 0) {Brightness_G = FadeStep_G * -1;}
if (FadeStep_G >= 510) {Brightness_G = FadeStep_G - 510;}
// if (FadeStep_G == -510) {CycleCountG = CycleCountG + 1;} //count + 1 for each full fade cycle
//fade blue LED according to it's fade step counter.
if (FadeStep_B == -764) {FadeStep_B = 765;}
if (FadeStep_B < 0) {Brightness_B = FadeStep_B * -1;}
if (FadeStep_B >= 510) {Brightness_B = FadeStep_B - 510;}
// if (FadeStep_B == -510) {CycleCountB = CycleCountB + 1;} // count + 1 for each full fade cycle
//fade blue LED according to it's fade step counter.
if (FadeStep_L == -764) {FadeStep_L = 765;}
if (FadeStep_L < 0) {Brightness_L = FadeStep_L * -1;}
if (FadeStep_L >= 510) {Brightness_L = FadeStep_B - 510;}
// if (FadeStep_L == -510) {CycleCountL = CycleCountL + 1;} // count + 1 for each full fade cycle
// if step counters are intialized 510 steps appart, -510 is the step in each LED's fade cycle
// that it will be on full brightness while the other 2 LED's are off.
Brightness_B = constrain(Brightness_B, 0, 255);
Brightness_G = constrain(Brightness_G, 0, 255);
Brightness_R = constrain(Brightness_R, 0, 255);
Brightness_L = constrain(Brightness_L, 0, 255);
//setLeds (Brightness_R, Brightness_G, Brightness_B, Brightness_L);
//delay (Loop_Delay);
}
// send the LED levels to the Arduino pins
void setLeds (int ipR, int ipG, int ipB, int ipL){
analogWrite (RED_PIN, ipR); // send the red brightness level to the red LED's pin
analogWrite (GREEN_PIN, ipG);
analogWrite (BLUE_PIN, ipB);
analogWrite (LEDSTRIP_PIN, ipL);
// test voor nieuwe dag//
if (millis() - midnight >= oneDay)
{
midnight = millis();
Serial.println(F("Een dag voorbij"));
}
lightControl();
}
void lightControl()
{
uint32_t timeAfterMidnight = millis() - midnight;
// loop door alle laden (LEDs)
for (uint8_t ltCnt = 0; ltCnt < NUMELEMENTS(lightTiming); ltCnt++)
{
// bijhouden of LED aan of uit moet; default uit
bool lightOn = false;
// loop door alle lightTimings rijen in een lade
for (uint8_t tCnt = 0; tCnt < NUMELEMENTS(lightTiming[ltCnt].t); tCnt++)
{
// overslaan indien niet gespecificeerd
if (lightTiming[ltCnt].t[tCnt].timeOn == 0xFFFFFFFF)
{
// volgende lightTiming rij in de lade
continue;
}
// controleren of de huidige tijd in een gespecificeerde aan/uit tijd valt
// aan tijd kleiner dan uit tijd
if (lightTiming[ltCnt].t[tCnt].timeOn < lightTiming[ltCnt].t[tCnt].timeOff)
{
if (timeAfterMidnight >= lightTiming[ltCnt].t[tCnt].timeOn && timeAfterMidnight < lightTiming[ltCnt].t[tCnt].timeOff)
{
// debugging
if (digitalRead(lightTiming[ltCnt].pin) == LOW)
{
Serial.print(F("Pin "));
Serial.print(lightTiming[ltCnt].pin);
Serial.print(F(" aan tussen "));
Serial.print(lightTiming[ltCnt].t[tCnt].timeOn);
Serial.print(F(" en "));
Serial.println(lightTiming[ltCnt].t[tCnt].timeOff);
}
// aangeven dat LED moet worden ingeschakeld
lightOn = true;
}
}
// (2) aan tijd groter dan uit tijd; bv 23 tot 1
else
{
if (timeAfterMidnight >= lightTiming[ltCnt].t[tCnt].timeOn || timeAfterMidnight < lightTiming[ltCnt].t[tCnt].timeOff)
{
if (digitalRead(lightTiming[ltCnt].pin) == LOW)
{
// debugging
Serial.print(F("Pin "));
Serial.print(lightTiming[ltCnt].pin);
Serial.print(F(" aan tussen "));
Serial.print(lightTiming[ltCnt].t[tCnt].timeOn);
Serial.print(F(" en "));
Serial.println(lightTiming[ltCnt].t[tCnt].timeOff);
}
// aangeven dat LED moet worden ingeschakeld
lightOn = true;
}
}
}
// indien de LED aan moet zijn
if (lightOn == true)
{
// schakel LED aan
digitalWrite(lightTiming[ltCnt].pin, HIGH);
}
else
{
// debugging
if (digitalRead(lightTiming[ltCnt].pin) == HIGH)
{
Serial.print(F("Pin "));
Serial.print(lightTiming[ltCnt].pin);
Serial.println(F(" uit "));
}
// schakel LED uit
digitalWrite(lightTiming[ltCnt].pin, LOW);
}
}
}
Is het mogelijk om het origineel hier neer te zetten? Of een link naar het onderwerp.
Hierbij de originele schets van jou.
Wellicht ter verduidelijking, de tijden zijn nog niet aangepast voor mijn doel. Het ledstripje op pin 10 mag je lezen als "daglicht". En met faden van kleur naar kleur bedoel ik eigenlijk kleurverloop, dus vloeien.
De pennen van de Arduino zijn via mosfed transistoren verbonden aan de leds die apart worden gevoed met 12 Volt. Hoef je je daar geen zorgen
over te maken.
```cpp
#define NUMELEMENTS(x) (sizeof(x) / sizeof(x[0]))
// model tijden
const uint32_t oneMinute = 1000UL;
const uint32_t oneHour = 60000UL;
const uint32_t oneDay = 1440000UL;
struct TIMING
{
const uint32_t timeOn;
const uint32_t timeOff;
};
struct LIGHTS
{
const uint8_t pin;
const TIMING t[4]; // geeft aan dat er 4 schakelmomenten zijn.
};
LIGHTS lightTiming[] = {
{3, {{(1 * oneHour), (2 * oneHour)}, {(3 * oneHour), (4 * oneHour)}, {0xFFFFFFFF, 0xFFFFFFFF}, {0xFFFFFFFF, 0xFFFFFFFF}}},
{5, {{(1 * oneHour), (2 * oneHour)}, {(3 * oneHour), (4 * oneHour)}, {0xFFFFFFFF, 0xFFFFFFFF}, {0xFFFFFFFF, 0xFFFFFFFF}}},
{6, {{(1 * oneHour), (2 * oneHour)}, {(3 * oneHour), (4 * oneHour)}, {0xFFFFFFFF, 0xFFFFFFFF}, {0xFFFFFFFF, 0xFFFFFFFF}}},
{8, {{(1 * oneHour), (2 * oneHour)}, {(3 * oneHour), (4 * oneHour)}, {0xFFFFFFFF, 0xFFFFFFFF}, {0xFFFFFFFF, 0xFFFFFFFF}}},
{9, {{(1 * oneHour), (3 * oneHour)}, {(5 * oneHour) + (7 * oneMinute), (20 * oneHour)}, {0xFFFFFFFF, 0xFFFFFFFF}, {0xFFFFFFFF, 0xFFFFFFFF}}},
{10, {{(23 * oneHour), (1 * oneHour)}, {0xFFFFFFFF, 0xFFFFFFFF}, {0xFFFFFFFF, 0xFFFFFFFF}, {0xFFFFFFFF, 0xFFFFFFFF}}},
};
// middernacht
uint32_t midnight;
void setup()
{
Serial.begin(115200);
// toon de configuratie
for (uint8_t ltCnt = 0; ltCnt < NUMELEMENTS(lightTiming); ltCnt++)
{
Serial.print(F("Lade "));
Serial.println(ltCnt);
Serial.print(F("\tPin "));
Serial.println(lightTiming[ltCnt].pin);
Serial.println(F("\tTijden"));
for (uint8_t tCnt = 0; tCnt < NUMELEMENTS(lightTiming[ltCnt].t); tCnt++)
{
if (lightTiming[ltCnt].t[tCnt].timeOn == 0xFFFFFFFF)
{
Serial.println(F("\t\tGeen tijden"));
}
else
{
Serial.print(F("\t\tAan "));
Serial.print(lightTiming[ltCnt].t[tCnt].timeOn);
Serial.print(F("\tUit "));
Serial.println(lightTiming[ltCnt].t[tCnt].timeOff);
}
}
}
// zet pinnen als uitgang
for (uint32_t ltCnt = 0; ltCnt < NUMELEMENTS(lightTiming); ltCnt++)
{
pinMode(lightTiming[ltCnt].pin, OUTPUT);
digitalWrite(lightTiming[ltCnt].pin, LOW);
// debugging
Serial.print(F("Pin "));
Serial.print(lightTiming[ltCnt].pin);
Serial.println(F(" output"));
}
// middernacht
midnight = millis();
}
void loop()
{
// test voor nieuwe dag
if (millis() - midnight >= oneDay)
{
midnight = millis();
Serial.println(F("Een dag voorbij"));
}
lightControl();
}
void lightControl()
{
uint32_t timeAfterMidnight = millis() - midnight;
// loop door alle laden (LEDs)
for (uint8_t ltCnt = 0; ltCnt < NUMELEMENTS(lightTiming); ltCnt++)
{
// bijhouden of LED aan of uit moet; default uit
bool lightOn = false;
// loop door alle lightTimings rijen in een lade
for (uint8_t tCnt = 0; tCnt < NUMELEMENTS(lightTiming[ltCnt].t); tCnt++)
{
// overslaan indien niet gespecificeerd
if (lightTiming[ltCnt].t[tCnt].timeOn == 0xFFFFFFFF)
{
// volgende lightTiming rij in de lade
continue;
}
// controleren of de huidige tijd in een gespecificeerde aan/uit tijd valt
// aan tijd kleiner dan uit tijd
if (lightTiming[ltCnt].t[tCnt].timeOn < lightTiming[ltCnt].t[tCnt].timeOff)
{
if (timeAfterMidnight >= lightTiming[ltCnt].t[tCnt].timeOn && timeAfterMidnight < lightTiming[ltCnt].t[tCnt].timeOff)
{
// debugging
if (digitalRead(lightTiming[ltCnt].pin) == LOW)
{
Serial.print(F("Pin "));
Serial.print(lightTiming[ltCnt].pin);
Serial.print(F(" aan tussen "));
Serial.print(lightTiming[ltCnt].t[tCnt].timeOn);
Serial.print(F(" en "));
Serial.println(lightTiming[ltCnt].t[tCnt].timeOff);
}
// aangeven dat LED moet worden ingeschakeld
lightOn = true;
}
}
// (2) aan tijd groter dan uit tijd; bv 23 tot 1
else
{
if (timeAfterMidnight >= lightTiming[ltCnt].t[tCnt].timeOn || timeAfterMidnight < lightTiming[ltCnt].t[tCnt].timeOff)
{
if (digitalRead(lightTiming[ltCnt].pin) == LOW)
{
// debugging
Serial.print(F("Pin "));
Serial.print(lightTiming[ltCnt].pin);
Serial.print(F(" aan tussen "));
Serial.print(lightTiming[ltCnt].t[tCnt].timeOn);
Serial.print(F(" en "));
Serial.println(lightTiming[ltCnt].t[tCnt].timeOff);
}
// aangeven dat LED moet worden ingeschakeld
lightOn = true;
}
}
}
// indien de LED aan moet zijn
if (lightOn == true)
{
// schakel LED aan
digitalWrite(lightTiming[ltCnt].pin, HIGH);
}
else
{
// debugging
if (digitalRead(lightTiming[ltCnt].pin) == HIGH)
{
Serial.print(F("Pin "));
Serial.print(lightTiming[ltCnt].pin);
Serial.println(F(" uit "));
}
// schakel LED uit
digitalWrite(lightTiming[ltCnt].pin, LOW);
}
}
}
Ik moet hier wat over nadenken; geef me een paar dagen.
Natuurlijk. Ik ben al een hele tijd aan het zoeken naar een oplossing. Die paar dagen maakt niet .
Ik vermoed dat wat je wil, gecompliceerder za blijken dan je had verwacht.
Het menselijk oog heeft een logarithmische gevoeligheid voor licht, en het is ook gevoeliger voor rood dan voor blauw licht.
Daarom kun je niet uitgaan van percentages / vaste stappen in het verloop van de betreffende helderheden.
Dat is allemaal wel op te lossen, maar maakt het daarmee wel ingewikkelder.
Je hebt gelijk, maar het is maar voor een modelbaan en in de natuur is het ook elke dag anders. Kan misschien ook met niet tot de volle sterkte van 255 laten komen, maar tot 200. Ook zag ik deze optie: misschien ook bruikbaar?
// DIM factor voor felle LEDstrips, waarde 0.1 - 1.0, waarbij 1.0 niet gedimd is
#define DIMFACTOR 0.8
// Presets dag / avond / nacht / ochtend
#define PRESET1_R DIMFACTOR76 // Dag
#define PRESET1_G DIMFACTOR93
#define PRESET1_B DIMFACTOR79
#define PRESET1_W DIMFACTOR214
Dit is slechts een deel van de instellingen. Misschien ook bruikbaar.
Deze lijst toont waarden voor R(ood), G(roen), B(lauw) en W(it).
Daarmee kun je dan behoorlijk nauwkeurig een kleur aansturen.
Je zult dan ook zien in het voorbeeld waar je dit vandaan hebt, dat er voor elk van de 4 verschillende dagdelen, ook voor elk van de 4 lichtkleuren een andere waarde zal zijn ingevuld.
Dat is inderdaad wel waar ik op wees in mijn vorige bericht, en je zult je daarmee dan ook bewust zijn van de complexiteit die dit met zich zal meebrengen wanneer je dit een geleidelijk verloop wil laten maken.
Het klopt dat dit gecompliceerd is. Daarom ben ik al weken aan het stoeien om het zover te krijgen en heb ik hulp ingeroepen via het forum.
Er wordt aan gewerkt ![]()
Neem gerust je tijd. Ik heb geen haast.
Eindelijk, het heeft even geduurd.
Het bijgevoegde programma is gebaseerd op een finite state machine (fsm in het kort) met regels ('rules'); regels worden gecombineerd in een stap ('state') van de fsm. Regels die in dezelfde stap van de fsm zitten worden parallel uitgevoerd. Een regel vertelt het programma wat er moet gebeuren met een pin.
Hieronder een voorbeeld waar de eerste stap een regel bevat om de intensiteit van het witte licht te verlagen (FADEOUT) tot 128 (de 50% die je noemde) en de tweede stap twee regels bevat om (parallel) de intensiteit van het witte licht verder te verlagen naar 64 (een waarde die ik uit mijn duim gezogen heb) en de intensiteit van het rode licht te verhogen (FADEIN) naar 64 (weer uit de duim gezogen).
RULE fsm[][NUMELEMENTS(pins)] = {
{
// fade white from start value (255) to 128 (50%)
{ idxWhite, 128, 1 * oneMinute, 0, FADEOUT, false, true },
},
{
// fade white from previous value to 64 (25%)
{ idxWhite, 64, 1 * oneMinute, 0, FADEOUT, false, true },
// fade red from start value (0) to 64 (25%)
{ idxRed, 64, 1 * oneMinute, 0, FADEIN, false, true },
},
...
...
}
Er zijn 5 opties voor een regel.
// fade direction and delay
enum CTRLOPTION : uint8_t
{
FADEIN, // increase brightness
FADEOUT, // decrease brightness
LIGHTON, // switch light on
LIGHTOFF, // switch light off
DELAY, // indicates a delay
};
Ik denk dat de namen vanzelfsprekend zijn. DELAY maakt het mogelijk een regel te maken in een stap die een vertraging tussen twee andere stappen creëert. Bijvoorbeeld je begint in de morgen en en laat het lichter worden en na een vertraging van bijvoorbeeld 12 uur laat je het weer donkerder worden.
In grote lijnen is de flow van het programma als volgt.
In loop() wordt runFsm() aangeroepen; dit is gedaan om het makkelijker te maken later andere functionaliteiten aan je programma toe te voegen. runFsm() doorloopt de stappen van de fsm. De huidige stap van de fsm die uitgevoerd wordt wordt aangegeven in de variabele fsmIdx. Voor iedere stap worden alle regels uitgevoerd in een for-loop; als alle regels in een stap compleet zijn wordt er naar de volgende stap gegaan. Als alle stappen afgehandeld zijn wordt fsmIdx weer terug gezet op 0 en worden de variabelen van de regels terug gezet op default waardes; als een resultaat begint het proces weer vanaf het begin.
// macro that calculates the number of elements in any type of array
#define NUMELEMENTS(x) (sizeof(x) / sizeof(x[0]))
// fade direction and delay
enum CTRLOPTION : uint8_t
{
FADEIN, // increase brightness
FADEOUT, // decrease brightness
LIGHTON, // switch light on
LIGHTOFF, // switch light off
DELAY, // indicates a delay
};
// for testing to speed up the cycles
//const uint8_t speedFactor = 1;
const uint8_t speedFactor = 10;
// model times
const uint32_t oneMinute = 1000UL / speedFactor; //
const uint32_t oneHour = 60 * oneMinute; //
const uint32_t oneDay = 24 * oneHour; //
// our pins
const uint8_t pinRed = 6;
const uint8_t pinGreen = 5;
const uint8_t pinBlue = 3;
const uint8_t pinWhite = 10;
//const uint8_t pinWhite = LED_BUILTIN; // sterretje testing fade
// structure with information about a pin
struct PIN
{
const uint8_t pin; // arduino pin
const uint8_t rstPwm; // reset value when sequence (re)starts
uint8_t curPwm; // current
const char *name; // display name for display and debugging
};
PIN pins[] = {
{ pinWhite, 255, 0, "pinWhite" },
{ pinRed, 0, 0, "pinRed" },
{ pinGreen, 0, 0, "pinGreen" },
{ pinBlue, 0, 0, "pinBlue" },
};
// convenience
const uint8_t idxWhite = 0;
const uint8_t idxRed = 1;
const uint8_t idxGreen = 2;
const uint8_t idxBlue = 3;
const uint8_t idxDelay = 255;
// struct containing information about a rule
struct RULE
{
const uint8_t pinIdx; // index in pin array
const uint8_t endPwm; // PWM value when to stop
const uint32_t interval; // interval between fade updates or delay duration
uint32_t lastUpdateTime; // last time that fade step was adjusted
CTRLOPTION option; // FADEIN -> increase brightness, FADEOUT -> decrease brigtness, LIGHTON, LIGHTOFF, DELAY
bool isFinished; // indicate if this step is completed
bool configured;
};
// RULE definition for finite state machine
RULE fsm[][NUMELEMENTS(pins)] = {
{
// fade white from start value (255) to 128 (50%)
{ idxWhite, 128, 1 * oneMinute, 0, FADEOUT, false, true },
},
{
// fade white from previous value to 64 (25%)
{ idxWhite, 64, 1 * oneMinute, 0, FADEOUT, false, true },
// fade red from start value (0) to 64 (25%)
{ idxRed, 64, 1 * oneMinute, 0, FADEIN, false, true },
},
{
// fade red from previous value to 0
{ idxRed, 0, 1 * oneMinute, 0, FADEOUT, false, true },
// fade blue from start value (0) to 64
{ idxBlue, 64, 1 * oneMinute, 0, FADEIN, false, true },
},
{
// fade daylight from previous value to 0
{ idxWhite, 0, 1 * oneMinute, 0, FADEOUT, false, true },
// fade blue from previous value to 0
{ idxBlue, 0, 1 * oneMinute, 0, FADEOUT, false, true },
},
{
{ idxGreen, 255, 1 * oneMinute, 0, LIGHTON, false, true },
},
{
// delay for 10 minutes
{ idxDelay, 0, 10 * oneMinute, 0, DELAY, false, true },
},
{
{ idxGreen, 0, 1 * oneMinute, 0, LIGHTOFF, false, true },
},
};
void setup()
{
Serial.begin(115200);
while (!Serial) {};
Serial.println(F("Light fade demo 0.1"));
for (uint8_t pinCnt = 0; pinCnt < NUMELEMENTS(pins); pinCnt++)
{
// set pin's current PWM to initial PWM
pins[pinCnt].curPwm = pins[pinCnt].rstPwm;
// and apply
analogWrite(pins[pinCnt].pin, pins[pinCnt].curPwm);
}
showConfig();
Serial.println(F("==============================="));
}
void loop()
{
bool rb = runFsm();
if(rb == true)
{
Serial.println(F("==============="));
Serial.println(F("Cyclus afgerond"));
Serial.println(F("==============="));
}
}
/*
Run the fsm
Returns:
true if the fsm has cdcone the last step, else false.
*/
bool runFsm()
{
// flag indicating if fsm step is finished
bool isFinished = true;
// return value
bool rb = false;
// current time
uint32_t currentTime = millis();
// current fsm step
static uint16_t fsmIdx;
// previous fsm step; only needed to prevent repetitive printing
static uint16_t lastFsmIdx = 0xFFFF;
// if there was a change from the current step to the next step
if (fsmIdx != lastFsmIdx)
{
// remember
lastFsmIdx = fsmIdx;
// print some info
Serial.print(F("fsm stap "));
Serial.println(fsmIdx);
}
// loop through the rules of the current fsm step
for (uint16_t ruleCnt = 0; ruleCnt < NUMELEMENTS(fsm[fsmIdx]); ruleCnt++)
{
// clang-format off
if (fsm[fsmIdx][ruleCnt].configured == true &&
fsm[fsmIdx][ruleCnt].isFinished == false &&
currentTime - fsm[fsmIdx][ruleCnt].lastUpdateTime >= fsm[fsmIdx][ruleCnt].interval)
// clang-format on
{
// update the time that the rule 'was' executed
fsm[fsmIdx][ruleCnt].lastUpdateTime = currentTime;
if (fsm[fsmIdx][ruleCnt].option != DELAY)
{
// update the light
doLight(fsm[fsmIdx][ruleCnt]);
}
else
{
fsm[fsmIdx][ruleCnt].isFinished = doDelay();
}
}
}
// check if all lights in this sequence step are finished
for (uint8_t ruleCnt = 0; ruleCnt < NUMELEMENTS(fsm[fsmIdx]); ruleCnt++)
{
if (fsm[fsmIdx][ruleCnt].configured == true && fsm[fsmIdx][ruleCnt].isFinished == false)
{
isFinished = false;
}
}
// if the sequence step is finished
if (isFinished == true)
{
Serial.print(F("fsm stap "));
Serial.print(fsmIdx);
Serial.println(F(" afgerond"));
// next sequence step
fsmIdx++;
// if all sequence steps are completed
if (fsmIdx == NUMELEMENTS(fsm))
{
// start from the beginning
fsmIdx = 0;
// reset sequence steps and reset initial PWM values
resetFsm();
// indicate that has is finished on cycle
rb = true;
}
}
return rb;
}
/*
adjust pwm value for a light
In:
reference to light
Returns:
flag indicating if endPwm has been reached
*/
bool doLight(RULE &rule)
{
// return value
bool rb = false;
Serial.print(F(" Aanpassen licht op pin "));
Serial.print(pins[rule.pinIdx].pin);
Serial.print(F(" ("));
Serial.print(pins[rule.pinIdx].name);
Serial.print(F("), pwm waarde = "));
// calculate and set new PWM value
calcPwm(pins[rule.pinIdx].curPwm, rule.endPwm, rule.option);
// print and apply
Serial.print(pins[rule.pinIdx].curPwm);
analogWrite(pins[rule.pinIdx].pin, pins[rule.pinIdx].curPwm);
// if the endPwm has been reached
if (pins[rule.pinIdx].curPwm == rule.endPwm)
{
rule.isFinished = true;
Serial.println(F(". Afgerond!"));
rb = true;
}
else
{
Serial.println();
}
// tell caller the state
return rb;
}
/*
Basic delay
Returns:
true if delay is finished, else false
*/
bool doDelay()
{
static uint8_t counter = 2;
bool rb = false;
Serial.println(F(" Wachten"));
//Serial.println(counter);
if (--counter == 0)
{
counter = 2;
rb = true;
}
return rb;
}
/*
calculate a PWM between 0 and 255
In:
reference to pwm value to be adjusted
end value to reach
option
*/
void calcPwm(uint8_t &curPwm, uint8_t endPwm, CTRLOPTION option)
{
switch (option)
{
case FADEIN:
if (curPwm < endPwm)
{
curPwm++;
}
break;
case FADEOUT:
if (curPwm > endPwm)
{
curPwm--;
}
break;
case LIGHTON:
curPwm = 255;
break;
case LIGHTOFF:
curPwm = 0;
break;
case DELAY:
// not applicable, keep compiler happy
break;
}
}
/*
Reset the finite state machine rule variables
*/
void resetFsm()
{
Serial.println(F("Reset fsm"));
for (uint16_t fsmCnt = 0; fsmCnt < NUMELEMENTS(fsm); fsmCnt++)
{
for (uint8_t ruleCnt = 0; ruleCnt < NUMELEMENTS(fsm[fsmCnt]); ruleCnt++)
{
fsm[fsmCnt][ruleCnt].isFinished = false;
fsm[fsmCnt][ruleCnt].lastUpdateTime = 0;
if (fsm[fsmCnt][ruleCnt].option != DELAY)
{
pins[fsm[fsmCnt][ruleCnt].pinIdx].curPwm = pins[fsm[fsmCnt][ruleCnt].pinIdx].rstPwm;
analogWrite(pins[fsm[fsmCnt][ruleCnt].pinIdx].pin, pins[fsm[fsmCnt][ruleCnt].pinIdx].curPwm);
}
}
}
}
/*
Show configuration
*/
void showConfig()
{
for (uint16_t fsmCnt = 0; fsmCnt < NUMELEMENTS(fsm); fsmCnt++)
{
Serial.print(F("fsm["));
Serial.print(fsmCnt);
Serial.println(F("]"));
for (uint8_t ruleCnt = 0; ruleCnt < NUMELEMENTS(fsm[fsmCnt]); ruleCnt++)
{
if (fsm[fsmCnt][ruleCnt].configured == true)
{
if (fsm[fsmCnt][ruleCnt].option == DELAY)
{
Serial.print(F(" wacht gedurende "));
Serial.print(fsm[fsmCnt][ruleCnt].interval);
Serial.println(F(" ms"));
}
else
{
Serial.print(F(" "));
Serial.print(pins[fsm[fsmCnt][ruleCnt].pinIdx].pin);
Serial.print(F(" ("));
Serial.print(pins[fsm[fsmCnt][ruleCnt].pinIdx].name);
Serial.print(F(")"));
switch (fsm[fsmCnt][ruleCnt].option)
{
case FADEIN:
Serial.print(F(", iedere "));
Serial.print(fsm[fsmCnt][ruleCnt].interval);
Serial.print(F(" ms helderheid verhogen tot "));
Serial.print(fsm[fsmCnt][ruleCnt].endPwm);
Serial.println(F(" bereikt is"));
break;
case FADEOUT:
Serial.print(F(", iedere "));
Serial.print(fsm[fsmCnt][ruleCnt].interval);
Serial.print(F(" ms helderheid verlagen tot "));
Serial.print(fsm[fsmCnt][ruleCnt].endPwm);
Serial.println(F(" bereikt is"));
break;
case LIGHTON:
Serial.println(F(", licht aan "));
break;
case LIGHTOFF:
Serial.println(F(", licht uit "));
break;
case DELAY:
// keep compiler happy
break;
}
}
}
}
}
}
Wat opmerkingen.
- Het veld
configuredin deRULEstruct is nodig om te voorkomen dat het programma later niet-gewenste acties onderneemt voor een regel die niet gespecificeerd is. In het programma zijn er nu 4 regels per stap; als je bijvoorbeeld maar regel één plaatst in een stap zijn er drie lege regels die je niet wilt uitvoeren. In een lege regel zalpinIdx0 zijn en zal er dus actie gedaan worden op de witte pin; ook zalconfiguredfalsezijn en dat voorkomt dat probleem. Je moet de regel altijd de waardetruemeegeven. - Voor regels die
LIGHTONofLIGHTOFFbevatten moet je het veldendPWMin deRULEstruct respectievelijk op 255 en 0 zetten in de regel. Het programma maakt gebruik van het feit dat voor de waardes 0 en 255analogWrite()onderhuids eendigitalWrite()doet (in ieder geval bij Arduinos zoals de Uno of Mega). - De functie
doDelay()implementeert een simpele vertraging door een teller te verlagen als de functie aangeroepen wordt; dit werkt omdat de daadwerkelijke tijdsbepaling inloop()gedaan wordt. - Je zult de fsm zelf moeten invullen; het voorbeeld is geschreven om de beginselen en de verschillende opties voor het
optieveld te tonen . Verder was het me niet 100% duidelijk wat er precies moet gebeuren (bijvoorbeeld moet daglicht verder dimmen terwijl rood langzaam opgehoogd wordt of niet). - Het verhogen/verlagen van de intensiteit is getest op en Arduino Micro. Verdere testen waren gebaseerd op de uitvoer naar de seriële monitor.
Ik denk dat dat het zo'n beetje is. Als je vragen hebt hoor ik het wel.
Dit is gewoon weg GEWELDIG. Ik verwachtte dat je de schets, die je eerst had geschreven voor de boerderijverlichting, zou aanpassen naar naar avond/nachtverlichting. Maar je schrijft gewoon een nieuwe schets. Begon ik de eerste schets net een beetje te begrijpen, kan ik weer opnieuw gaan studeren hoe dit in elkaar zit.
Dit is hoge schoolwerk!!
Momenteel werk ik aan het overzetten van de componenten van het breadboard naar een shield, dus even testen gaat nog niet, maar ik ben je heel dankbaar voor al het werk dat je verzet hebt. Mijn vader zou gezegd hebben "geef die vent een doos sigaren". Maar hoe kan ik mijn dank uiten? Heel hartelijk dank! Zodra ik klaar ben met solderen, ga ik testen en kom ik zeker nog met vragen bij je terug.
Daar was ik mee begonnen maar was eigenlijk niet de eenvoudigste oplossing. Als het gebaseerd was op de boerderij schets moet je bijhouden hoelang een stap voor het verhogen/verlagen van bv 256 naar 128 (50% duurt); met de gegeven oplossing wordt er automatisch doorgegaan met de volgende stap dus hoef je geen tijden bij te houden; alleen voor de vertraging nadat de schemer volledig is uitgevoerd en het begin van de dageraad moet je (op dit moment) even wat rekenen.
Ik probeer van het roken af te komen maar zal eigenlijk nooit nee zeggen tegen een doosje La Paz Wilde Brazil Cigarillos
Maar verschepen naar Zuid Afrika is relatief wel erg duur ![]()
Je hebt de uitvoer naar de seriële monitor; dat zal je referentie moeten zijn. Ik heb de speedFactor geïntroduceerd om het geheel was sneller te laten draaien voor mijn testen; ik kan geen minuten wachten totdat een cyclus afgerond is ![]()
Als je wilt kan ik proberen weer een volledige beschrijving te geven. Zo'n beetje iedere regel code is gedocumenteerd dus ik weet niet of dat nodig is.
Ik hoop dat je dit al tegengekomen bent
// clang-format off
if (fsm[fsmIdx][ruleCnt].configured == true &&
fsm[fsmIdx][ruleCnt].isFinished == false &&
currentTime - fsm[fsmIdx][ruleCnt].lastUpdateTime >= fsm[fsmIdx][ruleCnt].interval)
// clang-format on
De twee commentaar lijnen zijn eigenlijk geen commentaar. Ze beïnvloeden de werking van de auto-format in IDE 2.x en voorkomen dat de auto-format in de IDE één lange lijn maakt met alle condities.
En voor het geval je uitleg nodig hebt, de condities lezen als: *Als een regel in het array inderdaad geconfigureerd is en de regel nog niet volledig afgerond is en het tijd is".
Nou het solderen is klaar, wat een gepruts op zo'n klein printje. En ik heb getest. Mooi verloop van de kleuren! En natuurlijk komen nu de vragen. Ik heb toegevoegd de lantaarnpaaltjes, met gloeilampje op pin 9 en met led op pin 8. Die wil ik graag in het begin van stap 2 aan hebben en dan laten branden tot de nacht voorbij is. Hoe krijg ik ze in stap 2? Nu flitst de led wel, maar het gloeilampje komt niet eens tot lichtgeven. Wat doe ik fout?
In jouw uitleg bij punt 2 staat bij lighton en lightoff moet je het veld endPWM in de rule struct zetten. Bij de groene led, die niet fade, staat het niet vermeld. Hoe doe ik dat? Kan ik voor de dagstand, en pin 10 blijft aan, het beste een interval zetten of kan het ook met delay? Ook zo voor de nacht als blauw uit gaat, en de lantaarns pin 8 en 9 aan blijven.
Nou voorlopig zijn dit mijn vragen. Er volgen er nog meer...
Kun je je aangepaste programma hier neer zetten, dan kan ik kijken wat je gedaan hebt.
Ik weet niet zeker wat je bedoelt. Het onderstaande stukje zorgt er voor dat de pinGreen aangezet wordt and 10 model minuten later weer uitgezet wordt. De eerste endPWM staat op 255, de laatste endPWM op 0.
15:00:02.945 -> fsm stap 4
15:00:02.945 -> Aanpassen licht op pin 5 (pinGreen), pwm waarde = 255. Afgerond!
15:00:02.945 -> fsm stap 4 afgerond
15:00:02.945 -> fsm stap 5
15:00:02.945 -> Wachten
15:00:03.955 -> Wachten
15:00:03.955 -> fsm stap 5 afgerond
15:00:03.955 -> fsm stap 6
15:00:03.955 -> Aanpassen licht op pin 5 (pinGreen), pwm waarde = 0. Afgerond!
15:00:03.955 -> fsm stap 6 afgerond
Als je een LED instap twee aan wilt zetten, voeg je een regel toe in stap twee zoals die voor de groene LED toe aan stap 2. Voor de groene LED ziet de tweede stap (stap met fsmIdx 1 er dan zo uit
{
// fade white from previous value to 64 (25%)
{ idxWhite, 64, 1 * oneMinute, 0, FADEOUT, false, true },
// fade red from start value (0) to 64 (25%)
{ idxRed, 64, 1 * oneMinute, 0, FADEIN, false, true },
// switch green
{ idxGreen, 255, 1 * oneMinute, 0, LIGHTON, false, true },
},
De groene LED zal aanblijven totdat er ergens een stap is die deze uit zet.
Het is nu bijna gelukt. Dankzij jouw antwoorden op mijn vragen heb ik het nu bijna zover klaar. Ik zit nog met een probleempje. In de ochtend gaat het licht op pin 10 aan naar waarde 128 maar de lantaarnpaaltjes gaan te vroeg uit. Dit zou mooi zijn indien de pinnen gelijktijdig zouden faden en de lantaarnpaaltjes uit gaan. Samen in 1 stap. Hoe doe ik dat?
Ik heb er een beschrijving van in de schets gezet. Ik las dat je delay niet lang kan laten duren, maar ik wil naar ongeveer 10 minuten voor de dag en ook 10 minuten voor de nacht. Zal dit een probleem geven? Hoe doe ik dat nou met die sigarillos?
typ of plak
```cpp
//Met deze schets kan gerommeld worden.//
<code>
//KOPIE VAN DE SCHETS DIE DOOR STERRETJE GEMAAKT IS //
// macro that calculates the number of elements in any type of array
#define NUMELEMENTS(x) (sizeof(x) / sizeof(x[0]))
// fade direction and delay
enum CTRLOPTION : uint8_t
{
FADEIN, // increase brightness
FADEOUT, // decrease brightness
LIGHTON, // switch light on
LIGHTOFF, // switch light off
DELAY, // indicates a delay
};
// for testing to speed up the cycles
//const uint8_t speedFactor = 1;
const uint8_t speedFactor = 5;
// model times
const uint32_t oneMinute = 1000UL / speedFactor; //
const uint32_t oneHour = 60 * oneMinute; //
const uint32_t oneDay = 24 * oneHour; //
// our pins
const uint8_t pinRed = 6;
const uint8_t pinGreen = 5;
const uint8_t pinBlue = 3;
const uint8_t pinLP1 = 8; // Gloeilampje lantaarnpaaltjes
const uint8_t pinLP2 = 9; // Ledlampje lantaarnpaaltjes
const uint8_t pinWhite = 10; // Daglicht ledstrip
//const uint8_t pinWhite = LED_BUILTIN; // sterretje testing fade
// structure with information about a pin
struct PIN
{
const uint8_t pin; // arduino pin
const uint8_t rstPwm; // reset value when sequence (re)starts
uint8_t curPwm; // current
const char *name; // display name for display and debugging
};
PIN pins[] = {
{ pinWhite, 255, 0, "pinWhite" },
{ pinRed, 0, 0, "pinRed" },
{ pinGreen, 0, 0, "pinGreen" },
{ pinBlue, 0, 0, "pinBlue" },
{ pinLP1, 0, 0, "pinLP1" },
{ pinLP2, 0, 0, "pinLP2" },
};
// convenience
const uint8_t idxWhite = 0;
const uint8_t idxRed = 1;
const uint8_t idxGreen = 2;
const uint8_t idxBlue = 3;
const uint8_t idxLP1 = 4;
const uint8_t idxLP2 = 5;
const uint8_t idxDelay = 255;
// struct containing information about a rule
struct RULE
{
const uint8_t pinIdx; // index in pin array
const uint8_t endPwm; // PWM value when to stop
const uint32_t interval; // interval between fade updates or delay duration
uint32_t lastUpdateTime; // last time that fade step was adjusted
CTRLOPTION option; // FADEIN -> increase brightness, FADEOUT -> decrease brigtness, LIGHTON, LIGHTOFF, DELAY
bool isFinished; // indicate if this step is completed
bool configured;
};
// RULE definition for finite state machine
RULE fsm[][NUMELEMENTS(pins)] = {
{
// fade white from start value (255) to 128 (50%) // namiddag
{ idxWhite, 128, 1 * oneMinute, 0, FADEOUT, false, true }, //dit is stap 0
},
{
// fade white from previous value to 0) // avond valt waarde 64 is 25%
{ idxWhite, 0, 1 * oneMinute, 0, FADEOUT, false, true }, // dit is stap 1 waarde 128 is 50%
// fade red from start value (0) to 128 (50%) waarde 255 is 100%
{ idxRed, 128, 1 * oneMinute, 0, FADEIN, false, true }, // dit is stap 1 simultaaan
},
{
{ idxLP1, 255, 1 * oneMinute, 0, LIGHTON, false, true }, // dit is stap 2
{ idxLP2, 255, 1 * oneMinute, 0, LIGHTON, false, true }, // lantaarnpaaltjes aan
// fade red from previous value to 0
{ idxRed, 0, 1 * oneMinute, 0, FADEOUT, false, true }, // avondrood naar nachtblauw
// fade blue from start value (0) to 128 // dit is stap 2 simultaan
{ idxBlue, 128, 1 * oneMinute, 0, FADEIN, false, true }, // nacht valt
},
{
// fade blue from previous value to 0
{ idxBlue, 0, 1 * oneMinute, 0, FADEOUT, false, true }, // dit is stap 3 simultaan
{ idxDelay, 0, 660 * oneMinute, 0, DELAY, false, true }, // duistere nacht gedurende 3 minuten op speedfactor 5
},
{
// { idxGreen, 255, 1 * oneMinute, 0, LIGHTON, false, true },
},
{
},
{ idxBlue, 128, 1 * oneMinute, 0, FADEIN, false, true }, //ochtend
{ idxRed, 128, 1 * oneMinute, 0, FADEIN, false, true },
{ idxBlue, 255, 1 * oneMinute, 0, FADEIN, false, true },
{ idxBlue, 0, 1 * oneMinute, 0, FADEOUT, false, true },
{
{ idxWhite, 128, 1 * oneMinute, 0, FADEIN, false, true }, // deze drie (wit,rood en LP1-2) zouden gelijktijdig mogen
{ idxRed, 0, 1 * oneMinute, 0, FADEOUT, false, true },
{ idxLP1, 0, 1 * oneMinute, 0, LIGHTOFF, false, true },
{ idxLP2, 0, 1 * oneMinute, 0, LIGHTOFF, false, true },
{idxWhite, 255, 1 * oneMinute, 0, FADEIN, false, true }, // dag gedurende 3 minuten op speedfactor 5
{ idxDelay, 0, 660 * oneMinute, 0, DELAY, false, true },
}, // { idxGreen, 0, 1 * oneMinute, 0, LIGHTOFF, false, true },
};
void setup()
{
Serial.begin(115200);
while (!Serial) {};
Serial.println(F("Light fade demo 0.1"));
for (uint8_t pinCnt = 0; pinCnt < NUMELEMENTS(pins); pinCnt++)
{
// set pin's current PWM to initial PWM
pins[pinCnt].curPwm = pins[pinCnt].rstPwm;
// and apply
analogWrite(pins[pinCnt].pin, pins[pinCnt].curPwm);
}
showConfig();
Serial.println(F("==============================="));
}
void loop()
{
bool rb = runFsm();
if(rb == true)
{
Serial.println(F("==============="));
Serial.println(F("Cyclus afgerond"));
Serial.println(F("==============="));
}
}
/*
Run the fsm
Returns:
true if the fsm has cdcone the last step, else false.
*/
bool runFsm()
{
// flag indicating if fsm step is finished
bool isFinished = true;
// return value
bool rb = false;
// current time
uint32_t currentTime = millis();
// current fsm step
static uint16_t fsmIdx;
// previous fsm step; only needed to prevent repetitive printing
static uint16_t lastFsmIdx = 0xFFFF;
// if there was a change from the current step to the next step
if (fsmIdx != lastFsmIdx)
{
// remember
lastFsmIdx = fsmIdx;
// print some info
Serial.print(F("fsm stap "));
Serial.println(fsmIdx);
}
// loop through the rules of the current fsm step
for (uint16_t ruleCnt = 0; ruleCnt < NUMELEMENTS(fsm[fsmIdx]); ruleCnt++)
{
// clang-format off
if (fsm[fsmIdx][ruleCnt].configured == true &&
fsm[fsmIdx][ruleCnt].isFinished == false &&
currentTime - fsm[fsmIdx][ruleCnt].lastUpdateTime >= fsm[fsmIdx][ruleCnt].interval)
// clang-format on
{
// update the time that the rule 'was' executed
fsm[fsmIdx][ruleCnt].lastUpdateTime = currentTime;
if (fsm[fsmIdx][ruleCnt].option != DELAY)
{
// update the light
doLight(fsm[fsmIdx][ruleCnt]);
}
else
{
fsm[fsmIdx][ruleCnt].isFinished = doDelay();
}
}
}
// check if all lights in this sequence step are finished
for (uint8_t ruleCnt = 0; ruleCnt < NUMELEMENTS(fsm[fsmIdx]); ruleCnt++)
{
if (fsm[fsmIdx][ruleCnt].configured == true && fsm[fsmIdx][ruleCnt].isFinished == false)
{
isFinished = false;
}
}
// if the sequence step is finished
if (isFinished == true)
{
Serial.print(F("fsm stap "));
Serial.print(fsmIdx);
Serial.println(F(" afgerond"));
// next sequence step
fsmIdx++;
// if all sequence steps are completed
if (fsmIdx == NUMELEMENTS(fsm))
{
// start from the beginning
fsmIdx = 0;
// reset sequence steps and reset initial PWM values
resetFsm();
// indicate that has is finished on cycle
rb = true;
}
}
return rb;
}
/*
adjust pwm value for a light
In:
reference to light
Returns:
flag indicating if endPwm has been reached
*/
bool doLight(RULE &rule)
{
// return value
bool rb = false;
Serial.print(F(" Aanpassen licht op pin "));
Serial.print(pins[rule.pinIdx].pin);
Serial.print(F(" ("));
Serial.print(pins[rule.pinIdx].name);
Serial.print(F("), pwm waarde = "));
// calculate and set new PWM value
calcPwm(pins[rule.pinIdx].curPwm, rule.endPwm, rule.option);
// print and apply
Serial.print(pins[rule.pinIdx].curPwm);
analogWrite(pins[rule.pinIdx].pin, pins[rule.pinIdx].curPwm);
// if the endPwm has been reached
if (pins[rule.pinIdx].curPwm == rule.endPwm)
{
rule.isFinished = true;
Serial.println(F(". Afgerond!"));
rb = true;
}
else
{
Serial.println();
}
// tell caller the state
return rb;
}
/*
Basic delay
Returns:
true if delay is finished, else false
*/
bool doDelay()
{
static uint8_t counter = 2;
bool rb = false;
Serial.println(F(" Wachten"));
//Serial.println(counter);
if (--counter == 0)
{
counter = 2;
rb = true;
}
return rb;
}
/*
calculate a PWM between 0 and 255
In:
reference to pwm value to be adjusted
end value to reach
option
*/
void calcPwm(uint8_t &curPwm, uint8_t endPwm, CTRLOPTION option)
{
switch (option)
{
case FADEIN:
if (curPwm < endPwm)
{
curPwm++;
}
break;
case FADEOUT:
if (curPwm > endPwm)
{
curPwm--;
}
break;
case LIGHTON:
curPwm = 255;
break;
case LIGHTOFF:
curPwm = 0;
break;
case DELAY:
// not applicable, keep compiler happy
break;
}
}
/*
Reset the finite state machine rule variables
*/
void resetFsm()
{
Serial.println(F("Reset fsm"));
for (uint16_t fsmCnt = 0; fsmCnt < NUMELEMENTS(fsm); fsmCnt++)
{
for (uint8_t ruleCnt = 0; ruleCnt < NUMELEMENTS(fsm[fsmCnt]); ruleCnt++)
{
fsm[fsmCnt][ruleCnt].isFinished = false;
fsm[fsmCnt][ruleCnt].lastUpdateTime = 0;
if (fsm[fsmCnt][ruleCnt].option != DELAY)
{
pins[fsm[fsmCnt][ruleCnt].pinIdx].curPwm = pins[fsm[fsmCnt][ruleCnt].pinIdx].rstPwm;
analogWrite(pins[fsm[fsmCnt][ruleCnt].pinIdx].pin, pins[fsm[fsmCnt][ruleCnt].pinIdx].curPwm);
}
}
}
}
/*
Show configuration
*/
void showConfig()
{
for (uint16_t fsmCnt = 0; fsmCnt < NUMELEMENTS(fsm); fsmCnt++)
{
Serial.print(F("fsm["));
Serial.print(fsmCnt);
Serial.println(F("]"));
for (uint8_t ruleCnt = 0; ruleCnt < NUMELEMENTS(fsm[fsmCnt]); ruleCnt++)
{
if (fsm[fsmCnt][ruleCnt].configured == true)
{
if (fsm[fsmCnt][ruleCnt].option == DELAY)
{
Serial.print(F(" wacht gedurende "));
Serial.print(fsm[fsmCnt][ruleCnt].interval);
Serial.println(F(" ms"));
}
else
{
Serial.print(F(" "));
Serial.print(pins[fsm[fsmCnt][ruleCnt].pinIdx].pin);
Serial.print(F(" ("));
Serial.print(pins[fsm[fsmCnt][ruleCnt].pinIdx].name);
Serial.print(F(")"));
switch (fsm[fsmCnt][ruleCnt].option)
{
case FADEIN:
Serial.print(F(", iedere "));
Serial.print(fsm[fsmCnt][ruleCnt].interval);
Serial.print(F(" ms helderheid verhogen tot "));
Serial.print(fsm[fsmCnt][ruleCnt].endPwm);
Serial.println(F(" bereikt is"));
break;
case FADEOUT:
Serial.print(F(", iedere "));
Serial.print(fsm[fsmCnt][ruleCnt].interval);
Serial.print(F(" ms helderheid verlagen tot "));
Serial.print(fsm[fsmCnt][ruleCnt].endPwm);
Serial.println(F(" bereikt is"));
break;
case LIGHTON:
Serial.println(F(", licht aan "));
break;
case LIGHTOFF:
Serial.println(F(", licht uit "));
break;
case DELAY:
// keep compiler happy
break;
}
}
}
}
}
}
</code>
hier code
Ik vermoed dat je iets nog niet helemaal begrijpt.
18:54:52.342 -> fsm[10]
18:54:52.342 -> 10 (pinWhite), iedere 100 ms helderheid verhogen tot 128 bereikt is
18:54:52.342 -> 6 (pinRed), iedere 100 ms helderheid verlagen tot 0 bereikt is
18:54:52.342 -> 8 (pinLP1), licht uit
18:54:52.342 -> 9 (pinLP2), licht uit
18:54:52.342 -> 10 (pinWhite), iedere 100 ms helderheid verhogen tot 255 bereikt is
18:54:52.342 -> wacht gedurende 66000 ms
Je hebt 2 regels voor pinWhite in die stap; die draaien dus parallel en het effect is dat tot 128 pinWhite 2x wordt opgehoogd binnen de for-loop.
18:58:10.196 -> Aanpassen licht op pin 10 (pinWhite), pwm waarde = 126
18:58:10.292 -> Aanpassen licht op pin 10 (pinWhite), pwm waarde = 127
en daarna (tot 255) één keer.
Die eerste regel voor pinWhite is dus overbodig tenzij je dat bewust gedaan hebt. Maar gebaseerd op het feit dat je lantaarnpalen te vroeg uitschakelen denk ik dat het de bedoeling is dat als pinWhite 128 bereikt heeft de lantaarnpalen uit gaan en daarna het helderder worden wordt voortgezet.
Je zult die laatste stap moeten splitsen in twee stappen. Bijvoorbeeld
//10
{
{ idxWhite, 128, 1 * oneMinute, 0, FADEIN, false, true }, // deze drie (wit,rood en LP1-2) zouden gelijktijdig mogen
{ idxRed, 0, 1 * oneMinute, 0, FADEOUT, false, true },
}, // { idxGreen, 0, 1 * oneMinute, 0, LIGHTOFF, false, true },
//11
{
{ idxLP1, 0, 1 * oneMinute, 0, LIGHTOFF, false, true },
{ idxLP2, 0, 1 * oneMinute, 0, LIGHTOFF, false, true },
{ idxWhite, 255, 1 * oneMinute, 0, FADEIN, false, true }, // dag gedurende 3 minuten op speedfactor 5
{ idxDelay, 0, 660 * oneMinute, 0, DELAY, false, true },
}
Ik weet verder niet zeker of het onderstaande de bedoeling was.
//6
{ idxBlue, 128, 1 * oneMinute, 0, FADEIN, false, true }, //ochtend
//7
{ idxRed, 128, 1 * oneMinute, 0, FADEIN, false, true },
//8
{ idxBlue, 255, 1 * oneMinute, 0, FADEIN, false, true },
//9
{ idxBlue, 0, 1 * oneMinute, 0, FADEOUT, false, true },
Dit zijn 4 stappen, ieder met 1 regel. Dus zal eerst blauw geleidelijk naar 128 gaan, daarna rood naar 128, blauw verder naar 255 en daarna blauw geleidelijk naar 0.
Misschien ben ik verward omdat er wat accolades missen? Stap 6 zou er eigenlijlk zo uit moeten zien
//6
{ // open accolade voor stap
{ idxBlue, 128, 1 * oneMinute, 0, FADEIN, false, true }, //ochtend
}, // sluit accolade voor stap
En als blauw en rood in parallel moeten
//6
{ // open accolade voor stap
{ idxBlue, 128, 1 * oneMinute, 0, FADEIN, false, true }, //ochtend
{ idxRed, 128, 1 * oneMinute, 0, FADEIN, false, true },
}, // sluit accolade voor stap
Iedere regel heeft ook een eigen openings accolade en een sluit accolade.
Een laatste opmerking
Het was nooit mijn bedoeling dat idxDelay onderdeel was van een stap die ook de lichten veranderde. Het lijkt echter te werken dus dat is OK.
Laat maar horen of het lukt.
PS
Ik heb voor de duidelijkheid de stap nummers er even in gezet (bv //6 en //10).