Salve e benvenuti nell'ultima parte della nostra gamma Disco Glasses.
Nella parte di oggi riassumeremo ancora una volta tutte le informazioni rilevanti per la costruzione degli occhiali, mostreremo alcune immagini delle sequenze di animazione e, naturalmente, doneremo un aggiornamento funzionale ai nostri occhiali. L'aggiornamento funzionale nella parte di oggi è costituito da un sensore di vibrazione, che viene attivato dai tuoi movimenti di danza in discoteca e quindi fornisce al nostro micro controller informazioni sul tuo "comportamento di danza" sulla pista da ballo. Da queste informazioni, le sequenze luminose degli occhiali sono controllate.
In altre parole, i tuoi occhiali rispondono alle tue mosse di danza ritmica! Beh, come funziona tutto tecnicamente?
Come elemento centrale, abbiamo bisogno di un sensore di vibrazione. Questo può essere trovato nel nostro negozio in diverse versioni. Ognuno dei sensori menzionati reagisce in modo leggermente diverso ai movimenti. Pertanto, il risultato finale dipenderà ovviamente anche dal sensore utilizzato. Raccomando il Modulo sensore KY-002n come sensore di vibrazione. Ho anche fatto questo nella mia configurazione di provaTe durante lo sviluppo del codice. È importante che il sensore passi attivamente a terra. Ciò significa che in caso di "shock", il sensore utilizzato chiude brevemente il contatto dopo la GND.
mancia: Provare diversi sensori, se necessario, per ottenere il miglior risultato. Una selezione di sensori alternativi può essere trovato alla fine di questo blog!
Il secondo nuovo componente hardware è uno switch più semplice. Questo interruttore viene utilizzato per passare dalla vecchia modalità autosufficiente nota dalla Parte 2 alla nuova modalità che reagisce ai movimenti. Il passaggio da una modalità all'altra può avvenire in qualsiasi momento. Inoltre, per esempio, durante un programma in corso!
Ma passiamo al cablaggio dei due nuovi componenti nei nostri occhiali.
Come si può vedere sullo schema, il sensore di vibrazione si trova tra GND e porta 10 e il passaggio tra GND e porta 11 del processore. Il cablaggio del pulsante, d'altra parte, non è cambiato:
Anche il cablaggio dei due anelli WS2812 non è cambiato rispetto alla parte precedente della serie:
Si prega di caricare il seguente codice aggiornato alle funzionalità per gli occhiali dopo l'aggiornamento hardware:
#include <Adafruit_NeoPixel.H> # define BUTTON_CHANGEANIMATION 12 Pin I/O digitale collegato al pulsante. Questo sarà guidato con un resistore pull-up in modo che l'interruttore dovrebbe Tirare il perno a terra momentaneamente. Su un alto -> basso transizione verrà eseguita la logica di pressione del pulsante. # define PIXEL_PIN 6 Pin I/O digitale connesso a NeoPixels. # define SHOCK_SENSOR 10 Sensore d'urto/vibrazione collegato # define MODE_SWITCH 11 Modalità operativa # define PIXEL_COUNT 24 Tutti i pixel sulla striscia # define MaxAninmationsAvail 4 Adafruit_NeoPixel Striscia = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, NEO_RGB + NEO_KHZ800); Const Int tonalitàRedLow = 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 = 255; Byte Hue, "Io non sono; La saturazione è fissata a 255 (completa) per rimuovere la "Io non sono Byte Saturazione = 255; Controllo interrut Bool A60telSecInterruptOccured = Vero; Bool Modalità Funzione = False; Byte A60telSeconds24 = 0; Byte A4telSeconds24 = 0; Variabili timer Int TimerSecondi = 0; Contatore Int TimerAlarmSet = 15; Timer di 15 secondi Bool TimerStartFlagFlagFlag = False; Bool TimerStop = Vero; Operazioni manuali Bool ButtonAPress = False; AnimazioneControllo Int ShouldAnimation = 0; Int IsAnimation = 0; Int OLDLightBorder = 0; Bool GetONOFFStatus (Stato) GetONOFF = False; Bool OLDONOFFStatus = False; Bool PlayIntro = False; Riproduci Introduzione Bool PlayOutro = False; Gioca Outro Bool ModificaAnimazione = False; Bool Runonce = Vero; Animazione di Spegnimento - Anmation 0 variabili universali byte Un, C, D, e, F; Unsigned Int R, G, B; Routine di interrupt Pvr(TIMER1_COMPA_vect) { Bool LEDCambia, Premuto; Premuto = digitalRead (Lettura digitale)(BUTTON_CHANGEANIMATION); Pulsante Leggi Push Modalità Funzione = digitalRead (Lettura digitale)(MODE_SWITCH); Se ((Premuto == Basso) E (ButtonAPress == False)) { ButtonAPress = Vero; } TCNT1 (in questo stato in stato di = 0; Inizializzazione del registro } Gli interrupt terminano Inizio Programma Principale Vuoto Installazione() { Striscia.Iniziare(); Striscia.Visualizza(); Inizializzare tutti i pixel su 'off' PinMode (Modalità pin)(BUTTON_CHANGEANIMATION, INPUT_PULLUP); PinMode (Modalità pin)(SHOCK_SENSOR, INPUT_PULLUP); PinMode (Modalità pin)(MODE_SWITCH, INPUT_PULLUP); randomSeed (Seed randomse)(analogicOLettura(0)); noInterruzioni(); Disattiva tutti gli interrrupt TCCR1A = 0x00 (in questo 0x00); TCCR1B = 0x02 (in tissuta 0x0; TCNT1 (in questo stato in stato di = 0; Inizializzazione del registro OCR1A = 33353; Registro di confronto dell'output del caricoLoad Output Compare Register TIMSK1 |= (1 << CIE1A); Attiva interruzione confronto timer Interrompe(); Abilita tutti gli interrupt } Funzioni di supporto Vuoto HSBToRGB ( Unsigned Int inHue, Unsigned Int inSaturazione, Unsigned Int inLuminosità, Unsigned Int *O, Unsigned Int *Og, Unsigned Int *Ob ) { Se (inSaturazione == 0) { acromatico (grigio) *O = *Og = *Ob = inLuminosità; } Altro { Unsigned Int scaledHue = (inHue * 6); Unsigned Int Settore = scaledHue >> 8; settore da 0 a 5 intorno alla ruota dei colori Unsigned Int offsetInSector = scaledHue - (Settore << 8); posizione all'interno del settore Unsigned Int P = (inLuminosità * ( 255 - inSaturazione )) >> 8; Unsigned Int D = (inLuminosità * ( 255 - ((inSaturazione * offsetInSector) >> 8) )) >> 8; Unsigned Int T = (inLuminosità * ( 255 - ((inSaturazione * ( 255 - offsetInSector )) >> 8) )) >> 8; Interruttore ( Settore ) { Caso 0: *O = inLuminosità; *Og = T; *Ob = P; Pausa; Caso 1: *O = D; *Og = inLuminosità; *Ob = P; Pausa; Caso 2: *O = P; *Og = inLuminosità; *Ob = T; Pausa; Caso 3: *O = P; *Og = D; *Ob = inLuminosità; Pausa; Caso 4: *O = T; *Og = P; *Ob = inLuminosità; Pausa; Predefinito: caso 5: *O = inLuminosità; *Og = P; *Ob = D; Pausa; } } } Vuoto CheckConfigButtons () InterruptRoutine { Bool Premuto; Se (ButtonAPress == Vero) { Se (ShouldAnimation < MaxAninmationsAvail ) { ShouldAnimation++; } Altro { ShouldAnimation = 0; } Ritardo(400); ButtonAPress = False; } } Vuoto AnimazioneControllo () { Int GetSelAnimation = 0; Se (GetONOFFStatus (Stato) GetONOFF != OLDONOFFStatus) { OLDONOFFStatus = GetONOFFStatus (Stato) GetONOFF; Se (GetONOFFStatus (Stato) GetONOFF) { ShouldAnimation = 1; } Altro { ShouldAnimation = 0; } } } ----------------------------------------------------------------------- loop principale Vuoto Ciclo() { AnimazioneControllo(); Animazioni RunAnimations(); CheckConfigButtons(); } Fine ----------------------------------------------------------------------- loop principale Intros Vuoto Intro_CountUp (byte R, byte G, byte B, Int tempo di ritardo, Bool Dir) { Se (Dir) { Per ( Int Ho = 0; Ho < Striscia.numPixel(); Ho++) { Striscia.setPixelColor(Ho, R, G, B); Calulate Valori RGB per Pixel Striscia.Visualizza(); Mostra :) risultati Ritardo(tempo di ritardo); } } Altro { Per ( Int Ho = 0; Ho < Striscia.numPixel() + 1; Ho++) { byte Pos = Striscia.numPixel() - Ho; Striscia.setPixelColor(Pos, R, G, B); Calulate Valori RGB per Pixel Striscia.Visualizza(); Mostra :) risultati Ritardo(tempo di ritardo); } } } Vuoto Intro_RaiseRainbow(Bool risefall) { Luminosità = 255; Int Colore arcobaleno = 0; Se (risefall) { Per (Int Ho = 0; Ho < Striscia.numPixel(); Ho++) { Hue = Mappa(Ho + Colore arcobaleno, angleMin, 60, tonalitàRedLow, hueRedHigh); Imposta colore HSBToRGB(Hue, Saturazione, Luminosità, &R, &G, &B); Imposta colore Striscia.setPixelColor(Ho, R, G, B); Calulate Valori RGB per Pixel Striscia.Visualizza(); Ritardo(40); } } Altro { Per (Int Ho = 0; Ho < Striscia.numPixel(); Ho++) { Striscia.setPixelColor(Ho, 0, 0, 0); Striscia.Visualizza(); Ritardo(40); } } } Estruzioni animazioni Vuoto Ani_AllOff () { Per ( Int Ho = 0; Ho < Striscia.numPixel(); Ho++) { Striscia.setPixelColor(Ho, 0, 0, 0); tutto fuori } Striscia.Visualizza(); } Vuoto Ani_AllOn (byte R, byte G, byte B) { Per ( Int Ho = 0; Ho < Striscia.numPixel(); Ho++) { Striscia.setPixelColor(Ho, R, G, B); tutto il } Striscia.Visualizza(); } Vuoto Ani_Starshower () { Int Matrice[10] ; Bool shockValue = Vero; Bool Premuto = Vero; Per ( Int Ho = 0; Ho < Striscia.numPixel(); Ho++) { Striscia.setPixelColor(Ho, 0, 0, 15); tutti a base blu } Per (Int Ho = 0; Ho < 10; Ho++) { Int Selezionato = Casuale(Striscia.numPixel()); Striscia.setPixelColor(Selezionato, 255, 255, 255); Bianco } Striscia.Visualizza(); Ritardo(100); Per ( Int Ho = 0; Ho < Striscia.numPixel(); Ho++) { Striscia.setPixelColor(Ho, 0, 0, 15); tutti a base blu } Striscia.Visualizza(); Se (Modalità Funzione) { Ritardo(500); } Altro { fare { shockValue = digitalRead (Lettura digitale)(SHOCK_SENSOR); Premuto = digitalRead (Lettura digitale)(BUTTON_CHANGEANIMATION); Modalità Funzione = digitalRead (Lettura digitale)(MODE_SWITCH); } Mentre ((shockValue) && (!Modalità Funzione) && ( Premuto)) ; } } Vuoto Ani_Rainbow(byte tempo di ritardo) { Luminosità = 100; Int Colore arcobaleno = 0; Bool shockValue = Vero; Bool Premuto = Vero; fare { Per (Int Ho = 0; Ho < Striscia.numPixel(); Ho++) { Hue = Mappa(Ho + Colore arcobaleno, angleMin, 60, tonalitàRedLow, hueRedHigh); HSBToRGB(Hue, Saturazione, Luminosità, &R, &G, &B); Striscia.setPixelColor(Ho, R, G, B); } Striscia.Visualizza(); Mostra :) risultati Se (Modalità Funzione) { Ritardo(tempo di ritardo); } Altro { fare { shockValue = digitalRead (Lettura digitale)(SHOCK_SENSOR); Premuto = digitalRead (Lettura digitale)(BUTTON_CHANGEANIMATION); Modalità Funzione = digitalRead (Lettura digitale)(MODE_SWITCH); } Mentre ((shockValue) && (!Modalità Funzione) && ( Premuto)) ; } Colore arcobaleno++ ; } Mentre (Colore arcobaleno < 61); } Vuoto Ani_Two_Color () { Bool shockValue = Vero; Bool Premuto = Vero; byte Divisore = Casuale (1, 10); Bool Colore; Int X = 1; B = 0; Per (Int s = 0; s > -1; s = s + X) { Colore = False; Per ( Int Ho = 0; Ho < Striscia.numPixel(); Ho++) { Un = Ho / Divisore; Se (!(Un == B)) { B = Un; Colore = !Colore; } Se (Colore) { Striscia.setPixelColor(Ho, 0, s, 0); Grün } Se (!(Colore)) { Striscia.setPixelColor(Ho, s, 0, 0); Rot } } Striscia.Visualizza(); Se (s == 255) { Se (Modalità Funzione) { X = -1; Ritardo(200); } Altro { fare { shockValue = digitalRead (Lettura digitale)(SHOCK_SENSOR); Premuto = digitalRead (Lettura digitale)(BUTTON_CHANGEANIMATION); Modalità Funzione = digitalRead (Lettura digitale)(MODE_SWITCH); } Mentre ((shockValue) && (!Modalità Funzione) && ( Premuto)) ; X = -1; } } Ritardo(10); } Striscia.Visualizza(); } Vuoto Ani_Halloween() { Bool shockValue = Vero; Bool Premuto = Vero; Un = -10; Per (Int Ho = 0; Ho < Striscia.numPixel(); Ho++) { Striscia.setPixelColor(Ho, Casuale(1, 254), Casuale(1, 204), Casuale(1, 254)); e = e + Un; F = F + Un; Se (F <= 0) { Un = +10; } Se (F >= 60) { Un = -10; } } Striscia.Visualizza(); Mostra :) risultati Se (Modalità Funzione) { Ritardo(300); } Altro { fare { shockValue = digitalRead (Lettura digitale)(SHOCK_SENSOR); Premuto = digitalRead (Lettura digitale)(BUTTON_CHANGEANIMATION); Modalità Funzione = digitalRead (Lettura digitale)(MODE_SWITCH); } Mentre ((shockValue) && (!Modalità Funzione) && ( Premuto)) ; } } Vuoto Colore Dissolvenza () { byte Luminosità = 0; byte Saturazione = 0; Int Colori = 49 ; fare { Per (Int Ho = 0; Ho < Striscia.numPixel(); Ho++) { HSBToRGB(Colori, Saturazione, Luminosità, &R, &G, &B); Imposta colore Striscia.setPixelColor(Ho, R, G, B); Calulate Valori RGB per Pixel } Luminosità ++; Striscia.Visualizza(); Mostra :) risultati Ritardo(40); } Mentre (Luminosità < 50); } Vuoto Animazioni RunAnimations() { Se (!(ShouldAnimation == IsAnimation)) { PlayOutro = Vero; ModificaAnimazione = Vero; } Interruttore (IsAnimation) { Caso 0: tutti i LedOFF Se (PlayIntro) { PlayIntro = False; Runonce = Vero; } Se ((!(PlayIntro)) && (!(PlayOutro))) { Se (Runonce) { Ani_AllOff (); } Runonce = False; } Se (PlayOutro) { PlayOutro = False; PlayIntro = Vero; Runonce = Vero; IsAnimation = ShouldAnimation; } Pausa; Caso 1: Se (PlayIntro) { Intro_CountUp (0, 0, 15, 100, Vero); PlayIntro = False; } Se ((!(PlayIntro)) && (!(PlayOutro))) { Ani_Starshower(); } Se (PlayOutro) { Intro_CountUp (0, 0, 0, 100, False); PlayOutro = False; PlayIntro = Vero; IsAnimation = ShouldAnimation; } Pausa; Caso 2: Se (PlayIntro) { Intro_RaiseRainbow(Vero); PlayIntro = False; } Se ((!(PlayIntro)) && (!(PlayOutro))) { Ani_Rainbow(20); } Se (PlayOutro) { Intro_RaiseRainbow(False); PlayOutro = False; PlayIntro = Vero; IsAnimation = ShouldAnimation; } Pausa; Caso 3: Se (PlayIntro) { Ani_AllOff (); PlayIntro = False; } Se ((!(PlayIntro)) && (!(PlayOutro))) { Ani_Two_Color (); Ani_Two_Color (coda byte,coda byte,luminosità byte,byte delaytime) } Se (PlayOutro) { PlayOutro = False; PlayIntro = Vero; IsAnimation = ShouldAnimation; } Pausa; Caso 4: Se (PlayIntro) { Ani_AllOff (); PlayIntro = False; } Se ((!(PlayIntro)) && (!(PlayOutro))) { Ani_Halloween (); // } Se (PlayOutro) { PlayOutro = False; PlayIntro = Vero; IsAnimation = ShouldAnimation; } Pausa; } }
Premendo il pulsante, le animazioni possono ora essere richiamate una dopo l'altra. La novità è che ora può essere commutata tra le modalità autonome e le modalità di funzione di feedback semplicemente premendo l'interruttore.
Tutti reagiscono! delle quattro animazioni leggermente diverse sul sensore di vibrazione se è selezionata la modalità "Feedback".
Come un piccolo aiuto di prestazioni una volta ho fotografato tutte e 4 le diverse animazioni:
Doccia stellare:
arcobaleno:
Movimento di due colori:
Halloween:
Si prega di notare che in entrambi! Non passa immediatamente le animazioni all'animazione successiva, ma esce sempre dalla sequenza corrente prima dell'inizio dell'animazione successiva.
Vi auguro un sacco di divertimento ricreando gli occhiali da discoteca. Forse si desidera programmare più sequenze di animazione se i 4 esistenti non sono sufficienti per voi?
Provare altri sensori, ad esempio:
Oppure si può provare a utilizzare un sensore dei vari
Scrivi le tue idee o domande nei commenti.