Hasta ahora, nuestra linterna funciona bastante bien, y se puede controlar remotamente con las funciones básicas. Sin embargo, y yo ya había dejado que esto brille a través de la parte anterior, hoy en la última parte de nuestra serie de linternas de estado de ánimo vamos a "pimp" nuestra linterna un poco y donar no sólo un programa de parpadeo, pero un total de 5 programas de simulación de fuego diferentes, que también se puede seleccionar individualmente por control remoto!
¡El código puede y debe! Por supuesto, también se complementa con algoritmos de simulación propios, por lo que el lector inclinado tiene un número infinito de posibilidades para dejar su propia creatividad correr libre. Pero vamos a tratar con los 5 algoritmos que he incorporado y que se derivan unos de otros.
- Programa 1: Sin parpadeos, cambiando rápidamente la temperatura de la llama.
- Programa 2: Sin parpadeo, temperatura de llama igual permanente. Luz de pie.
- Programa 3: Parpadeo fuerte y frecuente, cambiando rápidamente la temperatura de la llama.
- Programa 4: Parpadeo fuerte, raro, la misma temperatura de la llama.
- Programa 5: parpadeo suave y frecuente, cambiando rápidamente la temperatura de la llama.
- Programa 6: Parpadeo fuerte, raro, cambiando rápidamente la temperatura de la llama.
El programa 5 es el "programa estándar" de la 2 parte de esta serie Maker.
El lector inclinado probablemente ya habrá reconocido que estos diferentes algoritmos de simulación se llaman o controlan a través de la estructura "caso de conmutación". Esto sucede en función del código de control remoto de lectura en la siguiente sección:
interruptor (IRCode)
{
caso -522182433: " En mi caso 1 en mi TV - Remoto
{
FireON ! FireON;
FireSequence n.o 1;
}
descanso;
caso -522149793: " En mi caso 2 en mi TV - Remoto
{
FireON ! FireON;
FireSequence 2;
}
descanso;
caso -522166113: " En mi caso 3 en mi TV - Remoto
{
FireON ! FireON;
FireSequence n.o 3;
}
descanso;
caso -522186513: " En mi caso 4 en mi TV - Remoto
{
FireON ! FireON;
FireSequence n.o 4;
}
descanso;
caso -522153873: " En mi caso 5 en mi TV - Remoto
{
FireON ! FireON;
FireSequence n.o 5;
}
descanso;
caso -522173873: " En mi caso 6 en mi TV - Remoto
{
FireON ! FireON;
FireSequence n.o 5;
}
descanso;
Predeterminado:
Serial.println (IRCode);
descanso;
}
Para que todo funcione con nuestro propio mando a distancia, sólo tenemos que utilizar la interfaz serial primero (también funciona con el código de la parte 2) para emitir los códigos de control remoto de 5 botones, que queremos utilizar para controlar la linterna:
Subimos el siguiente código a nuestro Arduino después de introducir los números en la instrucción case en consecuencia:
#include <Adafruit_NeoPixel.H> #include <Irremote.H> #define anclar 6 ¿Qué pin del Arduino está conectado a los NeoPixels? #define RECV_PIN 11 definir pin de entrada IR en Arduino #define NUMPIXELS 12 ¿Cuántos NeoPixels están conectados al Arduino? Tamaño de anillo NeoPixel popular Adafruit_NeoPixel Píxeles(NUMPIXELS, anclar, NEO_GRB + NEO_KHZ800); IRrecv irrecv(RECV_PIN); decode_results Resultados; decode_results clase se define en IRremote.h Largo FirelastTime = 0; Largo IRlastTime = 0; Largo TimerlastTime = 0; Int Intervalo; Largo IRCode = 0; Largo OLDIRCode = 0; Bool FireON = Falso; Bool FireOFF = Falso; Byte FireSequence = 0; Vacío Configuración() { Serial.Comenzar(115200); Mientras (!Serial); esperar hasta que se establezca Serial - requerido en algunas plataformas irrecv.enableIRIn(); Inicie el receptor Píxeles.Comenzar(); INITIALIZE NeoPixels Píxeles.Mostrar(); Inicializar todos los píxeles en 'desactivado' Intervalo = 300; randomSeed(analogRead(0)); } Vacío SimulateFire (Bool En, Byte FireSq) { Byte LightValue[NUMPIXELS * 3]; Si (Millis() - FirelastTime >= Intervalo) { Si (En) { FireOFF = Falso; FirelastTime = Millis(); Intervalo = 200; Si (FireSq == 1) { Para (Int Ⅰ = 0; Ⅰ < NUMPIXELS; Ⅰ++) { Para cada píxel... LightValue[Ⅰ * 3] = Aleatorio(200, 255); // 250 LightValue[Ⅰ * 3 + 1] = Aleatorio(30, 70); // 50 LightValue[Ⅰ * 3 + 2] = 0; } Para (Int Ⅰ = 0; Ⅰ < NUMPIXELS; Ⅰ++) { Para cada píxel... Píxeles.setPixelColor(Ⅰ, LightValue[Ⅰ * 3], LightValue[Ⅰ * 3 + 1], LightValue[Ⅰ * 3 + 2]); } noInterrupts(); Píxeles.Mostrar(); Envíe los colores de píxeles actualizados al hardware. Interrumpe(); } Si (FireSq == 2) { Para (Int Ⅰ = 0; Ⅰ < NUMPIXELS; Ⅰ++) { Para cada píxel... Píxeles.setPixelColor(Ⅰ, 250, 50, 0); } noInterrupts(); Píxeles.Mostrar(); Envíe los colores de píxeles actualizados al hardware. Interrumpe(); } Si (FireSq == 3) { Intervalo = Aleatorio(50, 100); Para (Int Ⅰ = 0; Ⅰ < NUMPIXELS; Ⅰ++) { Para cada píxel... LightValue[Ⅰ * 3] = Aleatorio(240, 255); // 250 LightValue[Ⅰ * 3 + 1] = Aleatorio(30, 60); // 50 LightValue[Ⅰ * 3 + 2] = 0; } Apague algunas luces Byte LightsOff = Aleatorio(0, 6); Para (Int Ⅰ = 0; Ⅰ < LightsOff; Ⅰ++) { Byte Seleccionado = Aleatorio(NUMPIXELS); LightValue[Seleccionado * 3] = 0; LightValue[Seleccionado * 3 + 1] = 0; LightValue[Seleccionado * 3 + 2] = 0; } Para (Int Ⅰ = 0; Ⅰ < NUMPIXELS; Ⅰ++) { Para cada píxel... Píxeles.setPixelColor(Ⅰ, LightValue[Ⅰ * 3], LightValue[Ⅰ * 3 + 1], LightValue[Ⅰ * 3 + 2]); } noInterrupts(); Píxeles.Mostrar(); Envíe los colores de píxeles actualizados al hardware. Interrumpe(); } Si (FireSq == 4) { Intervalo = Aleatorio(80); Para (Int Ⅰ = 0; Ⅰ < NUMPIXELS; Ⅰ++) { Para cada píxel... LightValue[Ⅰ * 3] = 250; al azar(240,255); 250 LightValue[Ⅰ * 3 + 1] = 50; al azar(30,60); 50 LightValue[Ⅰ * 3 + 2] = 0; } Apague algunas luces si Chance Hit Byte ChanceforLightsOff = Aleatorio(0, 40); Si (ChanceforLightsOff > 35) { Byte LightsOff = Aleatorio(5); Para (Int Ⅰ = 0; Ⅰ < LightsOff; Ⅰ++) { Byte Seleccionado = Aleatorio(NUMPIXELS); LightValue[Seleccionado * 3] = 0; LightValue[Seleccionado * 3 + 1] = 0; LightValue[Seleccionado * 3 + 2] = 0; } } Para (Int Ⅰ = 0; Ⅰ < NUMPIXELS; Ⅰ++) { Para cada píxel... Píxeles.setPixelColor(Ⅰ, LightValue[Ⅰ * 3], LightValue[Ⅰ * 3 + 1], LightValue[Ⅰ * 3 + 2]); } noInterrupts(); Píxeles.Mostrar(); Envíe los colores de píxeles actualizados al hardware. Interrumpe(); } Si (FireSq == 5) { Intervalo = Aleatorio(150, 200); Para (Int Ⅰ = 0; Ⅰ < NUMPIXELS; Ⅰ++) { Para cada píxel... LightValue[Ⅰ * 3] = Aleatorio(240, 255); // 250 LightValue[Ⅰ * 3 + 1] = Aleatorio(30, 60); // 50 LightValue[Ⅰ * 3 + 2] = 0; } Cambiar algunas luces más oscuras Byte LightsOff = Aleatorio(0, 4); Para (Int Ⅰ = 0; Ⅰ < LightsOff; Ⅰ++) { Byte Seleccionado = Aleatorio(NUMPIXELS); LightValue[Seleccionado * 3] = Aleatorio(50, 60); LightValue[Seleccionado * 3 + 1] = Aleatorio(5, 10); LightValue[Seleccionado * 3 + 2] = 0; } Para (Int Ⅰ = 0; Ⅰ < NUMPIXELS; Ⅰ++) { Para cada píxel... Píxeles.setPixelColor(Ⅰ, LightValue[Ⅰ * 3], LightValue[Ⅰ * 3 + 1], LightValue[Ⅰ * 3 + 2]); } noInterrupts(); Píxeles.Mostrar(); Envíe los colores de píxeles actualizados al hardware. Interrumpe(); } Si (FireSq == 6) { Intervalo = Aleatorio(80); Para (Int Ⅰ = 0; Ⅰ < NUMPIXELS; Ⅰ++) { Para cada píxel... LightValue[Ⅰ * 3] = Aleatorio(240, 255); // 250 LightValue[Ⅰ * 3 + 1] = Aleatorio(40, 60); // 50 LightValue[Ⅰ * 3 + 2] = 0; } Apague algunas luces si Chance Hit Byte ChanceforLightsOff = Aleatorio(0, 40); Si (ChanceforLightsOff > 35) { Byte LightsOff = Aleatorio(5); Para (Int Ⅰ = 0; Ⅰ < LightsOff; Ⅰ++) { Byte Seleccionado = Aleatorio(NUMPIXELS); LightValue[Seleccionado * 3] = 0; LightValue[Seleccionado * 3 + 1] = 0; LightValue[Seleccionado * 3 + 2] = 0; } } Para (Int Ⅰ = 0; Ⅰ < NUMPIXELS; Ⅰ++) { Para cada píxel... Píxeles.setPixelColor(Ⅰ, LightValue[Ⅰ * 3], LightValue[Ⅰ * 3 + 1], LightValue[Ⅰ * 3 + 2]); } noInterrupts(); Píxeles.Mostrar(); Envíe los colores de píxeles actualizados al hardware. Interrumpe(); } } Más { Si (!(FireOFF)) { Píxeles.Claro(); noInterrupts(); Píxeles.Mostrar(); Envíe los colores de píxeles actualizados al hardware. Interrumpe(); FireOFF = Verdad; } } } } Largo ReceiveIrCommand () { Largo Resultado = 0; Si (irrecv.Decodificar(&Resultados)) { Resultado = Resultados.Valor; irrecv.Reanudar(); Recibir el siguiente valor devolución Resultado; } devolución 0 ; } Vacío IRCommandProcessor (Largo IrCommand) { Si (IRCode == OLDIRCode) { TimerlastTime = Millis(); Algunas cosas sobre el debouncing IR Remote } Si (Millis() - TimerlastTime >= 300) { OLDIRCode = 0 ; Algunas cosas sobre el debouncing IR Remote } Si ((IRCode < -1) & (IRCode != OLDIRCode) & (IRCode > -600000000) & (IRCode < -500000000)) Señal IR válida recibida { OLDIRCode = IRCode; Algunas cosas sobre el debouncing IR Remote Interruptor (IRCode) { Caso -522182433: En mi caso 1 en mi TV - Remoto { FireON = !FireON; FireSequence = 1; } Romper; Caso -522149793: En mi caso 2 en mi TV - Remoto { FireON = !FireON; FireSequence = 2; } Romper; Caso -522166113: En mi caso 3 en mi TV - Remoto { FireON = !FireON; FireSequence = 3; } Romper; Caso -522186513: En mi caso 4 en mi TV - Remoto { FireON = !FireON; FireSequence = 4; } Romper; Caso -522153873: En mi caso 5 en mi TV - Remoto { FireON = !FireON; FireSequence = 5; } Romper; Caso -522178353: En mi caso 6 en mi TV - Remoto { FireON = !FireON; FireSequence = 6; } Romper; Predeterminado: Serial.println(IRCode); Romper; } } } Vacío Bucle() { IRCode = ReceiveIrCommand(); IRCommandProcessor(IRCode); SimulateFire(FireON, FireSequence); }
La función de los botones ha cambiado un poco. Ya no hay un botón dedicado para encender y apagar la linterna. En su lugar, cada uno de los 6 botones definidos ahora puede apagar la linterna de nuevo por un actuador adicional (renovado), siempre que se observe una pausa de al menos 1 segundo entre las pulsaciones individuales (soltar el botón).
Le deseo un montón de diversión actualizando su firmware de linterna.
8 comentarios
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 ?