Bonjour et bienvenue à la deuxième partie de la série de blogs "Discobrille".
Dans cette partie, comme beaucoup d’entre vous s’y attendaient, élargir les fonctionnalités de nos lunettes, mais nous répondrons également aux commentaires de la première partie de cette partie. Je vais donc vous fournir un plan de câblage mis à jour. Je vais également discuter explicitement des détails du câblage de la WS1812b.
En outre, nous faisons don d’une petite mise à niveau du firmware à notre matériel, qui vous permet de sélectionner jusqu’à 4 différentes animations d’éclairage passionnantes à la simple pression d’un bouton sur le bouton.
S’il vous plaît filer votre matériel selon ce plan de câblage mis à jour:
Puisque nous avons également reçu des questions spéciales sur le câblage détaillé des anneaux, ici en particulier cette partie est montrée agrandie :
On peut voir sur l’image que la ligne de données entre les anneaux est «sol». Cela signifie que le microcontrôleur a relié la sortie de données D6 au premier anneau après DI (données dans), puis de cet anneau à nouveau de la broche DO (Data Out) au deuxième anneau après DI (Data in). Ce type de connexion est nécessaire en raison de l’exploitation du bus de données en série.
Maintenant, nous pouvons oser mettre à niveau le firmware et télécharger le code suivant à notre Arduino:
#include <Adafruit_NeoPixel.H (en)> #define BUTTON_CHANGEANIMATION 12 Épingle IO numérique connectée au bouton. Ce sera conduit avec une résistance pull-up de sorte que le commutateur devrait Tirez la broche au sol momentanément. Sur un haut - bas transition de la logique de bouton appuyez sur s’exécutera. #define PIXEL_PIN 6 Épingle IO numérique connectée aux NeoPixels. #define PIXEL_COUNT 24 Tous les pixels sur bande #define MaxAninmationsAvail 4 Adafruit_NeoPixel Bande = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, NEO_RGB + NEO_KHZ800); Const Int hueRedLow = 0; Const Int hueRedHigh = 255; Const Int hueBlue = 170; Const Int angleMin = 0; Const Int angleSector = 60; Const Int angleMax = 360; Const Int brightMin = 0; Const Int brightMax (en) = 255; Octet Teinte, "Je ne suis pas; La saturation est fixée à 255 (plein) pour enlever le blead-through de différents "Je ne suis pas Il pourrait être lié à un autre potentiomètre si une démonstration de teinte Est désiré. Octet Saturation = 255; Contrôle interrut Bool A60telSecInterruptOccured = Vrai; Octet A60telSecondes24 = 0; Octet A4telSecondes24 = 0; Variables de minuterie Int TimerSeconds TimerSeconds = 0; Counter Int TimerAlarmSet (en anglais) = 15; Minuterie de 15 secondes Bool TimerStartFlagFlagFlag = Faux; Bool Timerstop = Vrai; Opérations manuelles Bool ButtonAPress (en) = Faux; Intenal LED LightEffects (LED 13) Octet LedMode (en) = 2; AnimationControl Int DevraitAnimation = 0; Int IsAnimation = 0; Int OLDLightBorder (en) = 0; Bool GetONOFFStatus GetONOFFStatus = Faux; Bool OLDONOFFStatus = Faux; Bool PlayIntro = Faux; Matchs d’intro Bool PlayOutro PlayOutro = Faux; Matchs Outro Bool ChangementAnimation = Faux; Bool Runonce (Runonce) = Vrai; Pour Switch-Off Amation - Anmation 0 variables universelles Octet Un, C, D, E, Q; Unsigned Int R, G, B; Interrompre les routines Isr (Isr)(TIMER1_COMPA_vect) { Bool LEDChange (en), PressedZ (pressedZ); Requête de commutateur PressedZ (pressedZ) = digitalRead (en)(BUTTON_CHANGEANIMATION); Si ((PressedZ (pressedZ) == Faible) Et (ButtonAPress (en) == Faux)) { ButtonAPress (en) = Vrai; } TCNT1 (en) = 0; Inscription initiale avec 0 } Interrompre la fin commencer le programme Vide Configuration() { Bande.Commencer(); Bande.Montrer(); Initialiser tous les pixels à 'off' pinMode(BUTTON_CHANGEANIMATION, INPUT_PULLUP); randomSeed(analogRead (en)(0)); noInterrupts(); Éteignez temporairement toutes les interruptions TCCR1A (EN) = 0x00; TCCR1B (EN) = 0x02; TCNT1 (en) = 0; // S'inscrire avec 0 initialisieren OCR1A = 33353; // Output Compare Register vorbelegen TIMSK1 |= (1 << OCIE1A); // Timer Compare Interrupt aktivieren interrompt(); // alle Interrupts scharf schalten En série.commencer(9600); En série.affleurer(); } // Hilfsfunktionen néant HSBToRGB( non signé int inHue, non signé int inSaturation, non signé int inBrightness, non signé int *ou, non signé int *oG, non signé int *oB ) { si (inSaturation == 0) { // achromatique (gris) *ou = *oG = *oB = inBrightness; } autre { non signé int scaledHue = (inHue * 6); non signé int secteur = scaledHue >> 8; // secteur 0 à 5 autour de la roue chromatique non signé int offsetInSector = scaledHue - (secteur << 8); // position dans le secteur non signé int p = (inBrightness * ( 255 - inSaturation )) >> 8; non signé int q = (inBrightness * ( 255 - ((inSaturation * offsetInSector) >> 8) )) >> 8; non signé int t = (inBrightness * ( 255 - ((inSaturation * ( 255 - offsetInSector )) >> 8) )) >> 8; commutateur ( secteur ) { Cas 0: *ou = inBrightness; *oG = t; *oB = p; Pause; Cas 1: *ou = q; *oG = inBrightness; *oB = p; Pause; Cas 2: *ou = p; *oG = inBrightness; *oB = t; Pause; Cas 3: *ou = p; *oG = q; *oB = inBrightness; Pause; Cas 4: *ou = t; *oG = p; *oB = inBrightness; Pause; défaut: // cas 5: *ou = inBrightness; *oG = p; *oB = q; Pause; } } } néant CheckConfigButtons () // InterruptRoutine { bool PressedZ; si (ButtonAPress == vrai) { si (ShouldAnimation < MaxAninmationsAvail ) { ShouldAnimation++; En série.println ("la phase 1"); En série.println (ShouldAnimation); // ShouldAnimation = 1; } autre { ShouldAnimation = 0; } retard(700); ButtonAPress = faux; } } néant AnimationControl () { int GetSelAnimation = 0; si (GetONOFFStatus != OLDONOFFStatus) { OLDONOFFStatus = GetONOFFStatus; si (GetONOFFStatus) { ShouldAnimation = 1; } autre { ShouldAnimation = 0; } } } // Boucle principale ---------------------------------------------- ------------------------- néant boucle() { AnimationControl(); RunAnimations(); CheckConfigButtons(); } // Boucle principale ---------------------------------------------- ------------------------- Ende // Intros néant Intro_CountUp (octet r, octet g, octet b, int temporisation, bool dir) { si (dir) { pour ( int je = 0; je < bande.numPixels(); je++) { bande.setPixelColor(je, r, g, b); // Calcul des valeurs RVB pour le pixel bande.spectacle(); // Montrer les résultats :) retard(temporisation); } } autre { pour ( int je = 0; je < bande.numPixels() + 1; je++) { octet pos = bande.numPixels() - je; bande.setPixelColor(pos, r, g, b); // Calcul des valeurs RVB pour le pixel bande.spectacle(); // Montrer les résultats :) retard(temporisation); } } } néant Intro_RaiseRainbow(bool montée) { luminosité = 255; int Rainbowcolor = 0; si (montée) { pour (int je = 0; je < bande.numPixels(); je++) { teinte = carte(je + Rainbowcolor, angleMin, 60, hueRedLow, hueRedHigh); // Définir la couleur HSBToRGB(teinte, saturation, luminosité, &r, &g, &b); // Définir la couleur bande.setPixelColor(je, r, g, b); // Calcul des valeurs RVB pour le pixel bande.spectacle(); retard(40); } } autre { pour (int je = 0; je < bande.numPixels(); je++) { bande.setPixelColor(je, 0, 0, 0); bande.spectacle(); retard(40); } } } // Outtros // Animations néant Ani_AllOff () { pour ( int je = 0; je < bande.numPixels(); je++) { bande.setPixelColor(je, 0, 0, 0); // tout est éteint } bande.spectacle(); } néant Ani_AllOn (octet r, octet g, octet b) { pour ( int je = 0; je < bande.numPixels(); je++) { bande.setPixelColor(je, r, g, b); // tout allumé } bande.spectacle(); } néant Ani_Starshower () { int tableau[10] ; pour ( int je = 0; je < bande.numPixels(); je++) { bande.setPixelColor(je, 0, 0, 15); // tout en bleu } pour (int je = 0; je < 10; je++) { int choisi = Aléatoire(bande.numPixels()); bande.setPixelColor(choisi, 255, 255, 255); // Blanc } bande.spectacle(); retard(100); pour ( int je = 0; je < bande.numPixels(); je++) { bande.setPixelColor(je, 0, 0, 15); // tout en bleu } bande.spectacle(); retard(500); } néant Ani_Rainbow(octet temporisation) { luminosité = 100; int Rainbowcolor = 0; faire { pour (int je = 0; je < bande.numPixels(); je++) { teinte = carte(je + Rainbowcolor, angleMin, 60, hueRedLow, hueRedHigh); HSBToRGB(teinte, saturation, luminosité, &r, &g, &b); bande.setPixelColor(je, r, g, b); } bande.spectacle(); // Montrer les résultats :) retard(temporisation); Rainbowcolor++ ; } tandis que (Rainbowcolor < 61); } néant Ani_Two_Color () { // Segments d'octets = PIXEL_COUNT / 5; octet Séparateur = Aléatoire (1, 10); bool Couleur; int X = 1; b = 0; pour (int s = 0; s > -1; s = s + X) { Couleur = faux; pour ( int je = 0; je < bande.numPixels(); je++) { une = je / Séparateur; si (!(une == b)) { b = une; Couleur = !Couleur; } si (Couleur) { bande.setPixelColor(je, 0, s, 0); // grün } si (!(Couleur)) { bande.setPixelColor(je, s, 0, 0); //pourrir } } bande.spectacle(); si (s == 255) { X = -1; retard(2000); } retard(10); } bande.spectacle(); } néant Ani_Halloween() { une = -10; pour (int je = 0; je < bande.numPixels(); je++) { bande.setPixelColor(je, Aléatoire(1, 254), Aléatoire(1, 204), Aléatoire(1, 254)); e = e + une; F = F + une; si (F <= 0) { une = +10; } si (F >= 60) { une = -10; } } bande.spectacle(); // Montrer les résultats :) retard(300); } néant FadeColor () { octet luminosité = 0; octet saturation = 0; int Colori = 49 ; faire { pour (int je = 0; je < bande.numPixels(); je++) { // wdt_reset (); HSBToRGB(Colori, saturation, luminosité, &r, &g, &b); // Définir la couleur bande.setPixelColor(je, r, g, b); // Calcul des valeurs RVB pour le pixel } luminosité ++; bande.spectacle(); // Montrer les résultats :) retard(40); } tandis que (luminosité < 50); } néant RunAnimations() { si (!(ShouldAnimation == IsAnimation)) { PlayOutro = vrai; ChangeAnimation = vrai; } commutateur (IsAnimation) { Cas 0: // tous les LedsOFF si (PlayIntro) { PlayIntro = faux; Exécuter une fois = vrai; } si ((!(PlayIntro)) && (!(PlayOutro))) { si (Exécuter une fois) { Ani_AllOff (); } Exécuter une fois = faux; } si (PlayOutro) { PlayOutro = faux; PlayIntro = vrai; Exécuter une fois = vrai; IsAnimation = ShouldAnimation; } Pause; Cas 1: si (PlayIntro) { Intro_CountUp (0, 0, 15, 100, vrai); PlayIntro = faux; } si ((!(PlayIntro)) && (!(PlayOutro))) { Ani_Starshower(); } si (PlayOutro) { Intro_CountUp (0, 0, 0, 100, faux); PlayOutro = faux; PlayIntro = vrai; IsAnimation = ShouldAnimation; } Pause; Cas 2: si (PlayIntro) { Intro_RaiseRainbow(vrai); PlayIntro = faux; } si ((!(PlayIntro)) && (!(PlayOutro))) { Ani_Rainbow(20); } si (PlayOutro) { Intro_RaiseRainbow(faux); PlayOutro = faux; PlayIntro = vrai; IsAnimation = ShouldAnimation; } Pause; Cas 3: si (PlayIntro) { Ani_AllOff (); PlayIntro = faux; } si ((!(PlayIntro)) && (!(PlayOutro))) { Ani_Two_Color (); // Ani_Two_Color (teinte octet, queue octet, luminosité octet, délai d'octet) } si (PlayOutro) { PlayOutro = faux; PlayIntro = vrai; IsAnimation = ShouldAnimation; } Pause; Cas 4: si (PlayIntro) { Ani_AllOff (); PlayIntro = faux; } si ((!(PlayIntro)) && (!(PlayOutro))) { Ani_Halloween (); // } si (PlayOutro) { PlayOutro = faux; PlayIntro = vrai; IsAnimation = ShouldAnimation; } Pause; } }
Funktionsweise: Durch kurzen Druck auf den Taster können jetzt folgende Animationen nacheinander aufgerufen werden. Ein
- Starshower
- arc en ciel
- Mouvement de deux couleurs
- Halloween
Bitte beachtet, dass die Animationen nicht sofort auf die nächste Animation umschalten, sondern immer erst die aktuelle Sequenz beenden, bevor die nächste Animation gestartet werden.
Auch hier seid ihr natürlich herzlich eingeladen, weitere Animationssequenzen zu programmieren, falls euch die 4 nicht ausreichen sollten. Die prinzipielle Vorgehensweise dazu ist aus dem Code ersichtlich.
Im nächsten und letzten Teil der Reihe werden wir unsere Brille auf „Umweltreize“ reagieren lassen.
Ich wünsche viel Spaß beim Nachbauen und bis zum nächsten mal.
2 commentaires
Andreas Wolter
@Sebastian: zu Beginn des Codes wird mit der Zeile
#define PIXEL_COUNT 24
die Anzahl aller Pixel festgelegt (hier zwei Ringe je 12 Pixel, also 24). Diese Konstante wird dann später verwendet, wenn das Neopixelsobjekt instanziiert wird.
Wenn Sie fünf Ringe verwenden, müssten Sie dort statt 24 dann 5x 12 = 60 eintragen. Dann sollte überall dort, wo mit der for-Schleife bis strip.numPixels() gezählt wird, jeder der Neopixel angesprochen werden.
Grüße,
Andreas Wolter
AZ-Delivery Blog
Sebastian
Hi,
ich möchte 5 von der 38mm Ringen nutzen. Wo genau muss ich denn die Anzahl der Ringe einstellen?