Disco bril met de WS2812b RGB LED Ring
Hallo en welkom bij een andere blog serie over onze WS2812b RGB LED Ring. Nogmaals, het draait allemaal om het huidige onderwerp van "upcycling". Immers, niemand moet kunnen zeggen dat de maker :) niet ook denken over het milieu.
Deze keer "upcyclen" we een oude zonnebril naar een stijlvolle "disco bril" voor de volgende disco bezoek. Hoewel ik niet langer een van de disco-gangers, ik denk dat er ook een project voor onze jongere makers onder de lezers. Ik hoop dat je het idee van Disco LED-glazen voor de volgende disco bezoek! Daarmee kom je zeker echt bij in de (dans)mis. De WS2812b LED ringen fungeren als "bril". Het frame rond de twee oogringen kan worden gemonteerd op een oude zonnebril. Als mc gebruiken we de Arduino Nano weer om ruimteredenen, als voeding een USB-powerbank van de mobiele telefoon. Voor de bedrading, adviseer ik offloading van de elektronica en voeding van de bril, dus het is voldoende om een dunne, 3 adrige kabel verdwijnen van de linker of rechter oor handvat over de top in een elektronische doos in het shirt zak of broekzak. In deze elektronische doos installeer je de drukknop en andere sensoren (in de komende delen) om de bril te bedienen. Voor onze blog van vandaag hebben we de volgende hardware-setup nodig:
Als onderdelen heb je niet veel nodig:
2 x RGB LED-ring WS2812b met 12 RGB LED's 5V voor Arduino 50 mm buitendiameter
1x drukknop
1x Usb power bank en USB kabel geschikt voor Arduino Nano
Wanneer we klaar zijn met het circuit, moeten we nu de Adafruit Neopixel bibliotheek opnemen, zodat we de LED's van de ring gemakkelijk kunnen bedienen.
De vereiste bibliotheek kan op 2 manieren aan onze IDE worden toegevoegd:
1.) Download de bibliotheek op de URL https://github.com/adafruit/Adafruit_NeoPixel. Vervolgens in de IDE in het menu-item Schets -> Bibliotheek opnemen ->Zip-bibliotheek handmatig toevoegen.
2.) Voer 'Adafruit Neopixel' in de bibliotheekbeheerder in als zoekterm, klik op de bibliotheek en selecteer vervolgens 'Installeren'. Selecteer ten minste versie 1.2.4.
Als alles uitgewerkt tot dit punt, upload dan de volgende code naar de nano:
#include <Adafruit_NeoPixel.H> #define BUTTON_CHANGEANIMATION 12 Digitale IO-pin verbonden met de knop. Dit zal aangedreven met een pull-up weerstand, zodat de schakelaar moet Trek de pin aan de grond. Op een hoge -> lage overgang de knop druk logica zal uitvoeren. #define PIXEL_PIN 6 Digitale IO-pin verbonden met de NeoPixels. #define PIXEL_COUNT 24 Alle pixels op Paraplu #define MaxAninmationsAvail 1 #define STATUS_PIN 13 Knop Animatiebesturingselement Adafruit_NeoPixel Strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, NEO_RGB + NEO_KHZ800); Const Int hueRedLow hueRedLow = 0; Const Int hueRedHigh hueRed = 255; Const Int hueBlue hueBlue = 170; De grootte van de hoek van één sector (1/6 van een kleurenwiel) en van een cyclus van het kleurenwiel. Const Int angleMin = 0; Const Int hoekSector = 60; Const Int angleMax = 360; Const Int brightMin = 0; Const Int brightMax = 255; Byte Tint, "Ik ben niet; De verzadiging is vastgesteld op 255 (volledig) om blead-through van verschillende "Ik ben niet Het kan worden gekoppeld aan een andere potentiometer als een demonstratie van tint Is gewenst. Byte Verzadiging = 255; Timervariabelen Int TimerSeconden = 0; Teller Int TimerAlarmSet = 15; Timer van 15 seconden Bool TimerStartFlagFlag = Valse; Bool Timerstop = Waar; Handmatige bewerkingen Bool ButtonADruk = Valse; Byte LedMode = 2; AnimatieControle Int ShouldAnimation = 0; Int IsAnimation = 0; Int OLDLightBorder OLDLightBorder = 0; Bool GetONOFFStatus = Valse; Bool OLDONOFFStatus = Valse; Bool PlayIntro (PlayIntro) = Valse; Intro Bool PlayOutro (PlayOutro) = Valse; Outro Bool ChangeAnimation = Valse; Bool Runonce = Waar; universele variabelen Byte A,C,D,E,F; Unsigned Int R, G, B; Routines onderbreken Isr(TIMER1_COMPA_vect) { Bool LEDChange,PressedZ (PressedZ); Wissel Abfrage PressedZ (PressedZ)= digitaalLezen(BUTTON_CHANGEANIMATION); Als ((PressedZ (PressedZ) == Lage) En (ButtonADruk == Valse)) { ButtonADruk = Waar; } TCNT1 = 0; Initialiseren registreren } Onderbreekt het einde programma starten Void Setup() { Strip.Beginnen(); Strip.Toon(); Initialiseer alle pixels om 'uit' pinMode(BUTTON_CHANGEANIMATION, INPUT_PULLUP); pinMode(STATUS_PIN,Output); digitalWrite(STATUS_PIN, Hoge); randomSeed randomSeed(analoogLezen(0)); noInterrupts(); Alle interrupts uitschakelen TCCR1A = 0x00; TCCR1B = 0x02; TCNT1 = 0; Initalisatie registreren OCR1A = 33353; Register van load output vergelijken TIMSK1 TIMSK1 |= (1 << OCIE1A); Timer vergelijken onderbreken activeren Interrupts(); Alle interrupts activeren Seriële.Beginnen(9600); Seriële.Flush(); } Help-functies Void HSBToRGB HSBToRGB( Unsigned Int inHue, Unsigned Int inSaturation, Unsigned Int inHelderheid, Unsigned Int *Of, Unsigned Int *Og, Unsigned Int *Ob ) { Als (inSaturation == 0) { achromatisch (grijs) *Of = *Og = *Ob = inHelderheid; } Anders { Unsigned Int geschaaldeHue = (inHue * 6); Unsigned Int Sector = geschaaldeHue >> 8; sector 0 tot 5 rond het kleurenwiel Unsigned Int offsetInSector = geschaaldeHue - (Sector << 8); positie binnen de sector Unsigned Int P = (inHelderheid * ( 255 - inSaturation )) >> 8; Unsigned Int V = (inHelderheid * ( 255 - ((inSaturation * offsetInSector) >> 8) )) >> 8; Unsigned Int T = (inHelderheid * ( 255 - ((inSaturation * ( 255 - offsetInSector )) >> 8) )) >> 8; Schakelen( Sector ) { Geval 0: *Of = inHelderheid; *Og = T; *Ob = P; Breken; Geval 1: *Of = V; *Og = inHelderheid; *Ob = P; Breken; Geval 2: *Of = P; *Og = inHelderheid; *Ob = T; Breken; Geval 3: *Of = P; *Og = V; *Ob = inHelderheid; Breken; Geval 4: *Of = T; *Og = P; *Ob = inHelderheid; Breken; Standaard: zaak 5: *Of = inHelderheid; *Og = P; *Ob = V; Breken; } } } Void ControleKnop () InterruptRoutine { Bool PressedZ (PressedZ); Als (ButtonADruk == Waar) { ShouldAnimation = !ShouldAnimation; Vertraging(250); ButtonADruk = Valse; } } Void AnimatieControle () { Int GetSelAnimation (GetSelAnimation) = 0; Als (GetONOFFStatus != OLDONOFFStatus) { OLDONOFFStatus = GetONOFFStatus; Als (GetONOFFStatus) { randomSeed randomSeed(analoogLezen(3)); GetSelAnimation (GetSelAnimation) = 1; ShouldAnimation = GetSelAnimation (GetSelAnimation); Seriële.Afdrukken ("Systeem OP. Geselecteerd: "); Seriële.println (ShouldAnimation); } Anders { Seriële.Afdrukken ("Systeem UIT. Seconden:"); TimerStartFlagFlag = Valse; Seriële.println (TimerSeconden); ShouldAnimation = 0; } } } Main Loop ----------------------------------------------------------------------- Void Lus() { AnimatieControle(); RunAnimations(); ControleKnop(); } Hoofdlus ----------------------------------------------------------------------- Ende Intros Void Intro_RaiseRainbow(Bool stijging) { Helderheid = 255; Int Regenboogkleur = 0; Als (stijging) { Voor (Int I=0; I < Strip.numPixels(); I++) { wdt_reset(); Tint = Kaart(I + Regenboogkleur, angleMin, 60, hueRedLow hueRedLow, hueRedHigh hueRed); Minutenkleur instellen HSBToRGB HSBToRGB(Tint, Verzadiging, Helderheid, &R, &G, &B); Urenkleur instellen Strip.setPixelColor(I, R, G, B); Calulate RGB-waarden voor uurpixel Strip.Toon(); Vertraging(40); } } Anders { Voor (Int I=0; I < Strip.numPixels(); I++) { wdt_reset(); Strip.setPixelColor(I, 0, 0, 0); Strip.Toon(); Vertraging(40); } } } Animaties Void Ani_AllOff () { Voor ( Int I = 0; I < Strip.numPixels(); I++) { Strip.setPixelColor(I,0, 0, 0); helemaal uit } Strip.Toon(); } Void Ani_Rainbow(Byte vertraging) { "Ik ben niet = 100; Int Regenboogkleur = 0; Do { Voor (Int I.=0; I. < Strip.numPixels(); I.++) { Tint = Kaart(I. + Regenboogkleur, angleMin, 60, hueRedLow hueRedLow, hueRedHigh hueRed); HSBToRGB HSBToRGB(Tint, Verzadiging, "Ik ben niet, &R, &G, &B); Strip.setPixelColor(I., R, G, B); } Strip.Toon(); Resultaten weergeven :) Vertraging(vertraging); Regenboogkleur++ ; } Terwijl (Regenboogkleur < 61); } Void RunAnimations() { Als (!(ShouldAnimation == IsAnimation)) { PlayOutro (PlayOutro) = Waar; ChangeAnimation = Waar; } Schakelen (IsAnimation) { Geval 0: alle LedsOFF Als (PlayIntro (PlayIntro)) { PlayIntro (PlayIntro) = Valse; Runonce = Waar; } Als ((!(PlayIntro (PlayIntro))) && (!(PlayOutro (PlayOutro)))) { Als (Runonce) { Ani_AllOff (); } Runonce = Valse; } Als (PlayOutro (PlayOutro)) { PlayOutro (PlayOutro) = Valse; PlayIntro (PlayIntro) = Waar; Runonce = Waar; IsAnimation = ShouldAnimation; } Breken; Geval 1: Als (PlayIntro (PlayIntro)) { Intro_RaiseRainbow(Waar); PlayIntro (PlayIntro) = Valse; } Als ((!(PlayIntro (PlayIntro))) && (!(PlayOutro (PlayOutro)))) { Ani_Rainbow(20); } Als (PlayOutro (PlayOutro)) { Intro_RaiseRainbow(Valse); PlayOutro (PlayOutro) = Valse; PlayIntro (PlayIntro) = Waar; IsAnimation = ShouldAnimation; } Breken; } }
Druk nu gewoon op de knop en geniet van het spektakel :). Een andere druk op de knop schakelt de bril uit.
Ik wens u veel plezier wederopbouw en, zoals altijd, tot de volgende keer.
4 Reacties
Tobias
In der Tat hat sich ein kleiner Fehler in das Fritzing Bild eingeschlichen. Natürlich müssen die Ringmassen auch mit GND verbunden werden. Für die Verbindung der Ringe ist folgendes zu beachten :
D6 > DI (Ring1) DO (Ring1) → DI (Ring2)
Sascha
Moin
Von der Idee her, finde ich es gut, aber mir stellt sich die Frage ob es funktioniert wenn die Ringe keinen Null bekommen.
Geht dir nichts an
Die Fritzing funktioniert so nicht, Masse (gnd) ist zwar zwischen den einzelnen Ringen verbunden, aber nicht zum Breadboard … dafür aber 2 mal die 5V Verbindung.
P.S.: Wenn ihr nächstes mal das Bild mit halb so vielen Pixeln veröffentlicht, dann sieht man auch solche Fehler nicht mehr. (Oder in anderen Worten: Bitte einen link zu einem Fritzing Bild mit höherer Auflösung damit die Leute auch erkennen können was wohin geht, denn hier sind die Beschriftungen nicht mehr zu erkennnen)
Bernd
Der Schaltplan sieht ja ganz nett aus, aber die zwei RGB LED Ringe brauchen nicht nur die GND Verbindung untereinander sondern auch noch die GND Verbindung zum Breadboard, oder nur zwei schwarze Verbindungen von den Ringen zum Breadboard auf GND. Etwa so wie bei zwei den roten +5V Verbindungen.