Das geht durchaus, wenn Du als Zeiteinheit das kleinste gemeinsame Vielfache verwendest. Beispiel: Zeit1 = 12 s, Zeit2 = 16 s, kgV = 4, also schaust Du alle 4 s, ob Zähler1 den Wert 3 oder Zähler2 den Wert 4 erreicht hat, dann machst Du mit Led1 oder Led2 etwas. Das kann ich Dir programmieren, denn so habe ich mit Arduino angefangen.
Bei mehreren Zeiten wird das dann ganz schnell unflexibel. Also verwendet man kgV = 1 und macht was, wenn der zugehörige Zähler 12 oder 16 erreicht hat. Bei kürzeren Zeiten bietet sich dann eine Veränderung der Zähler bei 1 ms an, also delay(1).
Letztlich führt Dich das in eine Sackgasse, aber es war mein Umweg zum Verständnis von millis(). Wenn Du Zeit hast, spiele einfach mal mit diesen Überlegungen. Das geht auch in der Simulation
Nein, viele Wege führen zum Ziel, beispielsweise:
- Die Arduinos haben Timer in Hardware eingebaut, die Du direkt verwenden kannst. Da muß man sich tief in das Datenblatt des µC einarbeiten.
delay()
und millis()
basieren auch darauf.
- Es gibt Bibliotheken, die Dir das abnehmen. Beispielsweise bieten Dir die MobaTools Zeitgeber an.
- Andere µCs bieten Dir mehrere Kerne an, um Dinge getrennt abhandeln zu können. Bei besonders zeitkritischen Aufgabenstellungen kann das durchaus sinnvoll sein.
- Und auch mit
delay()
kann man Deine Aufgabe lösen, wenn der Arduino sonst nichts machen soll, sonst eine Sackgasse.
Dein Therapeut sagt: "Wir treffen uns in zehn Minuten!", Du schaust auf Deine Uhr, addierst zu der bestehenden Zeit die zehn Minuten und merkst Dir beispielsweise 13:20 Uhr. Zeit zum Händewaschen, Blick zur Uhr, noch nicht 13:20 Uhr, Keks essen, Blick zur Uhr, noch nicht 13:20 Uhr, Schluck trinken, Blick zur Uhr, noch nicht 13:20 Uhr, Haare kämmen, Blick zur Uhr, es ist 13:20 Uhr, auf zum Therapeuten, der vor der Tür wartet, viel Erfolg!
Denksportaufgaben:
- Deine Uhr ist heute um Mitternacht auf 0:00 Uhr gewechselt, wärst Du auch pünktlich gewesen, wenn Deine Uhr vor oder nach ginge?
- Wärst Du auch pünktlich gewesen, wenn Deine Uhr nur die Minuten seit dem Aufstehen zählen würde?
Dein Arduino zählt die Millisekunden seit Reset, also seit seinem Aufstehen. Der Zahlenbereich von millis() umfaßt 2³² Millisekunden. Diesen Überlauf kann man durch if (aktuelleZeit - gemerkteZeit >= zeitIntervall
unproblematisch passieren. Also noch mal mit überlaufsicherer Zeitdifferenz:
Dein Therapeut sagt: "Wir treffen uns in zehn Minuten!", Du schaust auf Deine Uhr und merkst Dir die aktuelle Uhrzeit, beispielsweise 13:10 Uhr. Zeit zum Händewaschen, Blick zur Uhr, Du berechnest die Differenz zwischen aktueller und gemerkter Zeit, noch nicht 10 Minuten, Keks essen, Blick zur Uhr, Du berechnest die Differenz zwischen aktueller und gemerkter Zeit, noch nicht 10 Minuten, Schluck trinken, Blick zur Uhr, Du berechnest die Differenz zwischen aktueller und gemerkter Zeit, noch nicht 10 Minuten, Haare kämmen, Blick zur Uhr, Du berechnest die Differenz zwischen aktueller und gemerkter Zeit, es sind 10 Minuten, auf zum Therapeuten, der vor der Tür wartet, viel Erfolg!
Du kannst FastLED die Farbwerte berechnen lassen. Anstelle 0 bis 360 Grad für den Winkel nutzt FastLED 0 bis 255, also einen Wert vom Typ byte. Rot ist 0, Gelb ist 64. Ich habe mein Programm mal etwas umgeschrieben, damit die RGB-LED zwischen Rot und Gelb pendelt:
#include <FastLED.h>
const byte REDPIN = 5;
const byte GREENPIN = 3;
const byte BLUEPIN = 6;
const byte SMOKEPIN = 13;
#define DATA_PIN 4
#define NUM_LEDS 9
CRGB leds[NUM_LEDS];
void showAnalogRGB( const CRGB& rgb )
{
analogWrite(REDPIN, rgb.r );
analogWrite(GREENPIN, rgb.g );
analogWrite(BLUEPIN, rgb.b );
leds[0] = rgb;
FastLED.show();
}
void ausgabeRGB( const CRGB& rgb, const uint8_t hue )
{
static uint8_t alt_hue = hue;
static bool ausgabe = true;
if (hue < alt_hue) ausgabe = false;
if (ausgabe)
{
char buf[100] = {'\0'};
snprintf(buf, sizeof(buf), "hue=%d\tR=%d\tG=%d\tB=%d\n", hue, rgb.r, rgb.g, rgb.b);
Serial.print(buf);
}
alt_hue = hue;
}
void setup() {
Serial.begin(9600);
Serial.println("\nStart");
FastLED.addLeds<WS2812, DATA_PIN, RGB>(leds, NUM_LEDS); // GRB ordering is typical
FastLED.show();
pinMode(REDPIN, OUTPUT);
pinMode(GREENPIN, OUTPUT);
pinMode(BLUEPIN, OUTPUT);
pinMode(SMOKEPIN, OUTPUT);
}
void loop()
{
glut();
rauch();
}
void glut() {
uint32_t jetzt = millis();
static uint32_t vorhin = 0;
const uint32_t intervall = 20;
const uint8_t FARBE_MAX = 64;
const uint8_t FARBE_MIN = 0;
static uint8_t hue = FARBE_MIN;
static int8_t delta = 0;
if (jetzt - vorhin >= intervall)
{
vorhin = jetzt;
hue = hue + delta;
if (hue >= FARBE_MAX) delta = -1;
if (hue <= FARBE_MIN) delta = 1;
// Use FastLED automatic HSV->RGB conversion
showAnalogRGB( CHSV( hue, 255, 255) );
ausgabeRGB( CHSV( hue, 255, 255), hue );
}
}
void rauch()
{
uint32_t jetzt = millis();
static uint32_t vorhin = 0;
static uint32_t intervall = 0;
static bool ausEIN = false;
if (jetzt - vorhin >= intervall)
{
vorhin = jetzt;
if (ausEIN)
{
intervall = 100;
} else {
intervall = 2000;
}
digitalWrite(SMOKEPIN, ausEIN);
ausEIN = !ausEIN;
}
}
Der serielle Monitor zeigt dann:
Start
hue=0 R=255 G=0 B=0
hue=1 R=253 G=2 B=0
hue=2 R=250 G=5 B=0
hue=3 R=247 G=8 B=0
hue=4 R=245 G=10 B=0
hue=5 R=242 G=13 B=0
hue=6 R=239 G=16 B=0
hue=7 R=237 G=18 B=0
hue=8 R=234 G=21 B=0
hue=9 R=231 G=24 B=0
hue=10 R=229 G=26 B=0
hue=11 R=226 G=29 B=0
hue=12 R=223 G=32 B=0
hue=13 R=221 G=34 B=0
hue=14 R=218 G=37 B=0
hue=15 R=215 G=40 B=0
hue=16 R=212 G=43 B=0
hue=17 R=210 G=45 B=0
hue=18 R=207 G=48 B=0
hue=19 R=204 G=51 B=0
hue=20 R=202 G=53 B=0
hue=21 R=199 G=56 B=0
hue=22 R=196 G=59 B=0
hue=23 R=194 G=61 B=0
hue=24 R=191 G=64 B=0
hue=25 R=188 G=67 B=0
hue=26 R=186 G=69 B=0
hue=27 R=183 G=72 B=0
hue=28 R=180 G=75 B=0
hue=29 R=178 G=77 B=0
hue=30 R=175 G=80 B=0
hue=31 R=172 G=83 B=0
hue=32 R=171 G=85 B=0
hue=33 R=171 G=87 B=0
hue=34 R=171 G=90 B=0
hue=35 R=171 G=93 B=0
hue=36 R=171 G=95 B=0
hue=37 R=171 G=98 B=0
hue=38 R=171 G=101 B=0
hue=39 R=171 G=103 B=0
hue=40 R=171 G=106 B=0
hue=41 R=171 G=109 B=0
hue=42 R=171 G=111 B=0
hue=43 R=171 G=114 B=0
hue=44 R=171 G=117 B=0
hue=45 R=171 G=119 B=0
hue=46 R=171 G=122 B=0
hue=47 R=171 G=125 B=0
hue=48 R=171 G=128 B=0
hue=49 R=171 G=130 B=0
hue=50 R=171 G=133 B=0
hue=51 R=171 G=136 B=0
hue=52 R=171 G=138 B=0
hue=53 R=171 G=141 B=0
hue=54 R=171 G=144 B=0
hue=55 R=171 G=146 B=0
hue=56 R=171 G=149 B=0
hue=57 R=171 G=152 B=0
hue=58 R=171 G=154 B=0
hue=59 R=171 G=157 B=0
hue=60 R=171 G=160 B=0
hue=61 R=171 G=162 B=0
hue=62 R=171 G=165 B=0
hue=63 R=171 G=168 B=0
hue=64 R=171 G=170 B=0
Die Werte für Rot und Grün kannst Du für Dein Programm übernehmen, bei meiner WS2812-LED sieht das ganz gut aus.
#include <FastLED.h>
#define DATA_PIN 4
#define NUM_PIX 9
CRGB pix[NUM_PIX];
// FastLED ENDE
struct Glutfarben
{
const byte r, g;
};
Glutfarben glutfarben[] =
{
//Rot, Grün
{255, 0},
{253, 2},
{250, 5},
{247, 8},
{245, 10},
{242, 13},
{239, 16},
{237, 18},
{234, 21},
{231, 24},
{229, 26},
{226, 29},
{223, 32},
{221, 34},
{218, 37},
{215, 40},
{212, 43},
{210, 45},
{207, 48},
{204, 51},
{202, 53},
{199, 56},
{196, 59},
{194, 61},
{191, 64},
{188, 67},
{186, 69},
{183, 72},
{180, 75},
{178, 77},
{175, 80},
{172, 83},
{171, 85},
{171, 87},
{171, 90},
{171, 93},
{171, 95},
{171, 98},
{171, 101},
{171, 103},
{171, 106},
{171, 109},
{171, 111},
{171, 114},
{171, 117},
{171, 119},
{171, 122},
{171, 125},
{171, 128},
{171, 130},
{171, 133},
{171, 136},
{171, 138},
{171, 141},
{171, 144},
{171, 146},
{171, 149},
{171, 152},
{171, 154},
{171, 157},
{171, 160},
{171, 162},
{171, 165},
{171, 168},
{171, 170},
};
const byte REDPIN = 5;
const byte GREENPIN = 3;
const byte SMOKEPIN = 13;
void setup() {
// FastLED ANFANG
FastLED.addLeds<WS2812, DATA_PIN, RGB>(pix, NUM_PIX); // GRB ordering is typical
FastLED.show();
// FastLED ENDE
pinMode(SMOKEPIN, OUTPUT);
}
void loop()
{
glut();
rauch();
}
void glut() {
uint32_t jetzt = millis();
static uint32_t vorhin = 0;
const uint32_t intervall = 20;
const uint8_t FARBE_MAX = 64;
const uint8_t FARBE_MIN = 0;
static uint8_t hue = FARBE_MIN;
static int8_t delta = 0;
if (jetzt - vorhin >= intervall)
{
vorhin = jetzt;
hue = hue + delta;
if (hue >= FARBE_MAX) delta = -1;
if (hue <= FARBE_MIN) delta = 1;
analogWrite(REDPIN, glutfarben[hue].r );
analogWrite(GREENPIN, glutfarben[hue].g );
// FastLED ANFANG
pix[0] = CHSV( hue, 255, 255);
FastLED.show();
// FastLED ENDE
}
}
void rauch()
{
uint32_t jetzt = millis();
static uint32_t vorhin = 0;
static uint32_t intervall = 0;
static bool ausEIN = false;
if (jetzt - vorhin >= intervall)
{
vorhin = jetzt;
if (ausEIN)
{
intervall = 100;
} else {
intervall = 2000;
}
digitalWrite(SMOKEPIN, ausEIN);
ausEIN = !ausEIN;
}
}
Wenn Du die FastLED-Sachen rausnimmst, geht das auch gut in der Simulation