Soweit funktioniert unsere Laterne schon ganz gut, und kann schon mal mit den Basisfunktionen fernbedient werden. Jedoch, und das hatte ich ja auch schon im vorherigen teil etwas durchscheinen lassen, werden wir heute im letzten Teil unserer Stimmungslaternenreihe unsere Laterne noch etwas „pimpen“ und ihr nicht nur ein Flackerprogramm spendieren, sondern insgesamt 5 verschiedene Feuersimulations- Programme, die jeweils auch noch per Fernsteuerung einzeln auswählbar sind!
Der Code kann und soll! Natürlich auch um eigene Simulationsalgorithmen ergänzt werden, sodass dem geneigten Leser hier eine unendliche Anzahl an Möglichkeiten zur Verfügung steht der eigenen Kreativität freien Lauf zu lassen. Beschäftigen wir uns aber erst einmal mit den 5 Algorithmen die ich eingebaut habe und die voneinander abgeleitet sind.
- Programm 1: Kein Flackern, schnell wechselnde unterschiedliche Flammentemperatur.
- Programm 2: Kein Flackern, dauerhafte gleiche Flammentemperatur. Stehendes Licht.
- Programm 3: Starkes, häufiges Flackern, schnell wechselnde unterschiedliche Flammentemperatur.
- Programm 4: Starkes, seltenes Flackern, gleiche Flammentemperatur.
- Programm 5: mildes, häufiges Flackern, schnell wechselnde unterschiedliche Flammentemperatur.
- Programm 6: Starkes, seltenes Flackern, schnell wechselnde unterschiedliche Flammentemperatur.
Programm 5 ist das „Standardprogramm“ aus dem 2 Teil dieser Maker-Reihe.
Der geneigte Leser wird wahrscheinlich schon erkannt haben, das über die „switch-case“ Struktur dies unterschiedlichen Simulationsalgorithmen aufgerufen, bzw. gesteuert werden. Dies passiert in Abhängigkeit des eingelesenen Fernsteuercodes in folgendem Abschnitt:
switch (IRCode)
{
case -522182433: // In my case 1 on my TV - Remote
{
FireON = !FireON;
FireSequence = 1;
}
break;
case -522149793: // In my case 2 on my TV - Remote
{
FireON = !FireON;
FireSequence = 2;
}
break;
case -522166113: // In my case 3 on my TV - Remote
{
FireON = !FireON;
FireSequence = 3;
}
break;
case -522186513: // In my case 4 on my TV - Remote
{
FireON = !FireON;
FireSequence = 4;
}
break;
case -522153873: // In my case 5 on my TV - Remote
{
FireON = !FireON;
FireSequence = 5;
}
break;
case -522173873: // In my case 6 on my TV - Remote
{
FireON = !FireON;
FireSequence = 5;
}
break;
default:
Serial.println(IRCode);
break;
}
Um nun das Ganze mit unserer eigenen Fernbedienung zum laufen zu bringen, müssen wir uns nur noch über die serielle Schnittstelle als erstes (Funktioniert auch mit dem Code aus Teil 2) die Fernbedienungscodes von 5 Tasten ausgeben lassen, die wir zur Steuerung der Laterne verwenden wollen:
Wir laden folgenden Code auf unseren Arduino hoch, nachdem wir die Zahlen in der Case Anweisung entsprechend eingetragen haben:
#include <Adafruit_NeoPixel.h> #include <IRremote.h> #define PIN 6 // Which pin on the Arduino is connected to the NeoPixels? #define RECV_PIN 11 // define IR input pin on Arduino #define NUMPIXELS 12 // How many NeoPixels are attached to the Arduino? // Popular NeoPixel ring size Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800); IRrecv irrecv(RECV_PIN); decode_results results; // decode_results class is defined in IRremote.h long FirelastTime = 0; long IRlastTime = 0; long TimerlastTime = 0; int interval; long IRCode = 0; long OLDIRCode = 0; bool FireON = false; bool FireOFF = false; byte FireSequence = 0; void setup() { Serial.begin(115200); while (!Serial); //wait until Serial is established - required on some Platforms irrecv.enableIRIn(); // Start the receiver pixels.begin(); // INITIALIZE NeoPixels pixels.show(); // Initialize all pixels to 'off' interval = 300; randomSeed(analogRead(0)); } void SimulateFire (bool On, byte FireSq) { byte LightValue[NUMPIXELS * 3]; if (millis() - FirelastTime >= interval) { if (On) { FireOFF = false; FirelastTime = millis(); interval = 200; if (FireSq == 1) { for (int i = 0; i < NUMPIXELS; i++) { // For each pixel... LightValue[i * 3] = random(200, 255); // 250 LightValue[i * 3 + 1] = random(30, 70); // 50 LightValue[i * 3 + 2] = 0; } for (int i = 0; i < NUMPIXELS; i++) { // For each pixel... pixels.setPixelColor(i, LightValue[i * 3], LightValue[i * 3 + 1], LightValue[i * 3 + 2]); } noInterrupts(); pixels.show(); // Send the updated pixel colors to the hardware. interrupts(); } if (FireSq == 2) { for (int i = 0; i < NUMPIXELS; i++) { // For each pixel... pixels.setPixelColor(i, 250, 50, 0); } noInterrupts(); pixels.show(); // Send the updated pixel colors to the hardware. interrupts(); } if (FireSq == 3) { interval = random(50, 100); for (int i = 0; i < NUMPIXELS; i++) { // For each pixel... LightValue[i * 3] = random(240, 255); // 250 LightValue[i * 3 + 1] = random(30, 60); // 50 LightValue[i * 3 + 2] = 0; } // Switch some lights out byte LightsOff = random(0, 6); for (int i = 0; i < LightsOff; i++) { byte Selected = random(NUMPIXELS); LightValue[Selected * 3] = 0; LightValue[Selected * 3 + 1] = 0; LightValue[Selected * 3 + 2] = 0; } for (int i = 0; i < NUMPIXELS; i++) { // For each pixel... pixels.setPixelColor(i, LightValue[i * 3], LightValue[i * 3 + 1], LightValue[i * 3 + 2]); } noInterrupts(); pixels.show(); // Send the updated pixel colors to the hardware. interrupts(); } if (FireSq == 4) { interval = random(80); for (int i = 0; i < NUMPIXELS; i++) { // For each pixel... LightValue[i * 3] = 250; //random(240,255); // 250 LightValue[i * 3 + 1] = 50; //random(30,60); // 50 LightValue[i * 3 + 2] = 0; } // Switch some lights out if Chance Hit byte ChanceforLightsOff = random(0, 40); if (ChanceforLightsOff > 35) { byte LightsOff = random(5); for (int i = 0; i < LightsOff; i++) { byte Selected = random(NUMPIXELS); LightValue[Selected * 3] = 0; LightValue[Selected * 3 + 1] = 0; LightValue[Selected * 3 + 2] = 0; } } for (int i = 0; i < NUMPIXELS; i++) { // For each pixel... pixels.setPixelColor(i, LightValue[i * 3], LightValue[i * 3 + 1], LightValue[i * 3 + 2]); } noInterrupts(); pixels.show(); // Send the updated pixel colors to the hardware. interrupts(); } if (FireSq == 5) { interval = random(150, 200); for (int i = 0; i < NUMPIXELS; i++) { // For each pixel... LightValue[i * 3] = random(240, 255); // 250 LightValue[i * 3 + 1] = random(30, 60); // 50 LightValue[i * 3 + 2] = 0; } // Switch some lights darker byte LightsOff = random(0, 4); for (int i = 0; i < LightsOff; i++) { byte Selected = random(NUMPIXELS); LightValue[Selected * 3] = random(50, 60); LightValue[Selected * 3 + 1] = random(5, 10); LightValue[Selected * 3 + 2] = 0; } for (int i = 0; i < NUMPIXELS; i++) { // For each pixel... pixels.setPixelColor(i, LightValue[i * 3], LightValue[i * 3 + 1], LightValue[i * 3 + 2]); } noInterrupts(); pixels.show(); // Send the updated pixel colors to the hardware. interrupts(); } if (FireSq == 6) { interval = random(80); for (int i = 0; i < NUMPIXELS; i++) { // For each pixel... LightValue[i * 3] = random(240, 255); // 250 LightValue[i * 3 + 1] = random(40, 60); // 50 LightValue[i * 3 + 2] = 0; } // Switch some lights out if Chance Hit byte ChanceforLightsOff = random(0, 40); if (ChanceforLightsOff > 35) { byte LightsOff = random(5); for (int i = 0; i < LightsOff; i++) { byte Selected = random(NUMPIXELS); LightValue[Selected * 3] = 0; LightValue[Selected * 3 + 1] = 0; LightValue[Selected * 3 + 2] = 0; } } for (int i = 0; i < NUMPIXELS; i++) { // For each pixel... pixels.setPixelColor(i, LightValue[i * 3], LightValue[i * 3 + 1], LightValue[i * 3 + 2]); } noInterrupts(); pixels.show(); // Send the updated pixel colors to the hardware. interrupts(); } } else { if (!(FireOFF)) { pixels.clear(); noInterrupts(); pixels.show(); // Send the updated pixel colors to the hardware. interrupts(); FireOFF = true; } } } } long ReceiveIrCommand () { long result = 0; if (irrecv.decode(&results)) { result = results.value; irrecv.resume(); // Receive the next value return result; } return 0 ; } void IRCommandProcessor (long IrCommand) { if (IRCode == OLDIRCode) { TimerlastTime = millis(); //Some stuff about debouncing IR Remote } if (millis() - TimerlastTime >= 300) { OLDIRCode = 0 ; //Some stuff about debouncing IR Remote } if ((IRCode < -1) & (IRCode != OLDIRCode) & (IRCode > -600000000) & (IRCode < -500000000)) // Valid IR Signal Received { OLDIRCode = IRCode; //Some stuff about debouncing IR Remote switch (IRCode) { case -522182433: // In my case 1 on my TV - Remote { FireON = !FireON; FireSequence = 1; } break; case -522149793: // In my case 2 on my TV - Remote { FireON = !FireON; FireSequence = 2; } break; case -522166113: // In my case 3 on my TV - Remote { FireON = !FireON; FireSequence = 3; } break; case -522186513: // In my case 4 on my TV - Remote { FireON = !FireON; FireSequence = 4; } break; case -522153873: // In my case 5 on my TV - Remote { FireON = !FireON; FireSequence = 5; } break; case -522178353: // In my case 6 on my TV - Remote { FireON = !FireON; FireSequence = 6; } break; default: Serial.println(IRCode); break; } } } void loop() { IRCode = ReceiveIrCommand(); IRCommandProcessor(IRCode); SimulateFire(FireON, FireSequence); }
Die Funktion der Tasten hat sich etwas verändert. Es gibt jetzt keine dedizierte Taste mehr zum Ein- und Ausschalten der Laterne. Vielmehr kann jetzt jede der 6 definierten Tasten die Laterne durch eine weitere (erneute) Betätigung die Laterne wieder ausschalten., sofern zwischen den einzelnen Tastendrücken eine Pause von mindestens 1 Sekunde eingehalten wird (Taste loslassen).
Ich wünsche euch viel Spaß beim Upgrade euer Laternenfirmware.
8 comments
Joachim
Hallo, mich würde interessieren, was ich an der Programmierung ändern muss, damit der LED bereits mit z.B. Programm 1 startet sobald der Arduino gestartet wird? Habe schon einiges probiert, aber nichts gescheites hinbekommen, außer dauer an….
Ake
Hallo, was müsste ich am Code ändern, um z.B. immer mit FireSequenz 1 zu starten. Das quasi beim starten des Arduino Programm 1 läuft, ohne das die Fernbedienung benutzt wird…
Bert
Hallo Tobias,
vielen Dank für Deine Mühe.
Durch den Nachtrag funktioniert es nun PERFEKT &
“Oma’s Windlicht” erstrahlt (buchstäblich) in neuem Glanz :-)
Tobias
Hallo bert,
Für Fernbedienungen aus dem Einsteiger KIT verwende bitte im Code statt:
if ((IRCode < -1) & (IRCode != OLDIRCode) ….
den Code:
if ((IRCode > 0) & (IRCode != OLDIRCode)
Die Einsteiger-KIT Fernbedienungen haben ein komplett anderen Codebereich als die “normalen” Fernbedienungen"
Bert
Hallo Tobias,
Danke für den Tipp UND die tolle Projektidee.
Das mit den Strays hatte ich (Dank Google) herausgefunden, den Hinweis mit den Codes befolgt. Wie befürchtet hat es aber nicht geholfen – denn die Fernbedienung ist keine TV Fernbedienung (damit habe ich es übrigens auch probiert Fabr. LG), sondern eine aus den Einsteigerkits (aus da ist auch der LED Empfänger her) .
Ich kenn mich jetzt (noch) nicht mir der Arduino Programmiersprache aus, aber es sein,
dass da die Auswahlroutine “zu” gründlich ist ?
Anyway – “zum Laufen” habe ich den Aufbau ja bekommen, nur das mit den verschiedenen Lichtstimmungen bekomme ich nicht hin :-(
Da gibt es doch Funktions-/Routine Aufrufe ( void ?) – kannst Du da evtl. einzelne
Code Teile – wie “Programm 1: Kein Flackern, schnell wechselnde unterschiedliche Flammentemperatur” als >> Flacker(); << zum Download einstellen, die dann je nach Ereignis (IR Code) ausgeführt werden ?
Hoffe ich hab mich verständlich ausgedrückt – wie gesagt – was Arduino Programmierung angeht bin ich ein absoluter Neuling :-)
Tobias Kuch
Noch ein Nachtrag: Falls die u.g Änderungen keinen Erfolg bringen, kann es auch helfen die Zeile:
if ((IRCode < -1) & (IRCode != OLDIRCode) & (IRCode > -600000000) & (IRCode < -500000000)) // Valid IR Signal Received
{
in
if ((IRCode < -1) & (IRCode != OLDIRCode) ) // Valid IR Signal Received
zu ändern, um hier das Filtern der IR Codes auf einen Bereich zu unterdrücken, und “alle” Codebereiche damit freizugeben. Dies kann insbesondere bei NICHT-Samsung Fernbedienungen sinnvoll sein.
Tobias
Hallo Bert,
Der “Stray”-Fehler ist ein Klassiker. Er wird nicht durch den Code selbst oder ein evtl. Fehler erzeugt, sondern durch Sonderzeichen, die durch den Kopiervorgang in die Arduino IDE eingefügt werden. Umgehen lässt er sich, wenn die Sonderzeichen vor Einfügen in die IDE gelöscht werden. Das kleine Ausgabe der IR Codes erfolgt liegt evtl. daran, das eine ähnliche Fernbedienung genutzt wird, die ich zum Testen des Codes verwendet habe. (Samsung TV). Bei belegten Codes erfolgt keine Ausgabe mehr auf der seriellen Schnittstelle. Bitte ersetzte alle genannten Fernbedienungscodes im Code erst mal durch einen Dummy (Bsp: 111) und teste dann mit einer Schnittstellengeschwindigkeit von 115200 Baud. Gruß
Bert
Eigentlich ein klasse Projekt, aber bei Code kopieren “Stray” Fehler.
Beim copy & paste vom Quelltext hier auf der Seite kein Fehler.
Dafür wird aber auch im Seriellen Monitor kein IR Code angezeigt
und auch sonst “tut sich nix” .
Mit (angepassten) Programmen wie hier
=> https://funduino.de/nr-11-fernbedienung
wird wenigstens der / die Codes ausgegeben & LED Ring angeschaltet.
Hardware, Aufbau, etc. sollten also OK sein – wo ist der Haken ?