Ecco il secondo articolo dedicato a Spectrum, se non hai letto il primo ecco il link
Dopo aver scoperto l’esistenza di alcuni led “intelligenti” abbiamo deciso di semplificare in modo radicale il nostro progettino. Infatti viene praticamente eliminata tutta l’elettronica di controllo dei led costituita dai TLC5940.
WS2812B
Questo è il nome di questi particolari led RGB. Ma cosa hanno di speciale? Dall’esterno sembrano dei normali led smd 5050, in realtà all’interno integrano un controller in grado di ricevere dati in forma seriale e pilotare il led. Ogni led oltre all’alimentazione (5V) presenta due pin per i dati, un ingresso e un’uscita. In questo modo è possibile concatenare molti led e pilotarli tutti con un singolo pin di Arduino! In pratica è possibile controllare il colore di ogni singolo led presente nella catena.
Il funzionamento è molto semplice, il microcontrollore (nel nostro caso Arduino) invia una sequenza di bit in forma seriale asincrona sbilanciata con protocollo NRZ. Per definire il colore di un led sono necessari 24 bit (8bit per colore, ovvero 16777216 combinazioni di colore). Quindi vengono inviati dei “pacchetti” da 24bit in modo sequenziale. Il primo led “legge” la sequenza in ingresso, cancella i primi 24 bit (a lui dedicati) e invia la sequenza al led succesivo che farà lo stesso. Inoltre il circuito interno “rigenera” il segnale, in questo modo la catena di led non è limitata dalla lunghezza della linea ma solo dal ritardo del segnale.
Ecco qua sopra uno schemino tratto dal datasheet.
Montaggio
I led in questione vengono venduti in striscie adesive come i comuni led per decoro. Il montaggio è risultato quindi molto semplice, ecco uno schemino che illustra la disposizione:
Software
Il software non è complesso. Per semplicità è stata utilizzata una libreria per la gestione dei led che si chiama FastLed. Quindi basta installare questa libreria nel proprio ambiente di sviluppo (Arduino IDE) e si è pronti.
Il codice di Spectrum è molto semplice:
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*/
#include
// numero totale di led
#define NUM_LEDS 56
#define COLONNE 7
#define RIGHE 8
// definizione dei pin
#define DATA_PIN 6 //pin per il collegamento della striscia led
#define STROBE_PIN 4 //pin strobe msgeq7
#define RESET_PIN 5 //pin reset msgeq7
//ALTRO
#define BRIGHTNESS 255 //luminosità
#define RUMORE 15 //soglia rumore
// definizione della matrice di led
CRGB leds[NUM_LEDS];
typedef struct ledrgb //struct contenenti i parametri relativi ad un led
{
int r;
int g;
int b;
int hue;
int sat;
int val;
int nled;
boolean attivo;
}
led;
led colori[COLONNE][RIGHE]; //matrice contenente il numero progressivo di ogni singolo led
//variabili globali
int destra[7]; //array contenente i dati relativi al canale destro
int sinistra[7]; //array contenente i dati relativi al canale sinistro
int medio[7]; //array contenente la media dei dati contenuti nei due array precedenti
int nlivello; //indice del livello
int delta=130; //valore che corrisponde ad un livello 128
int hue_arcobaleno=0; //variabile globale per l'hue variabile dell'arcobaleno
int long time_arcobaleno=0;
int long time_cambio=0;
int effetto=0;
//prototipi di funzione
void leggiMSGEQ7(void); //riceve i dati dall'integrato MSGEQ7
void colonna_piena(void); //visualizza i dati in colonne piene
void aggiornaRGB(void); //funzione che trasmette i valori degli array agli integrati
void aggiornaHSV(void); //funzione che trasmette i valori degli array agli integrati
void arcobaleno_a_colonne(void); //colora le colonne di colori diversi
void arcobaleno_a_punti(void); //colora i led di colori diversi
void colore_totale_hsv(int, int, int); //colora tutti i led dello stesso colore hsv
void colore_totale_rgb(int, int, int); //colora tutti i led dello stesso colore rgb
//////SETUP//////
void setup() {
Serial.begin (9600); //inizializza la seriale
pinMode (DATA_PIN, OUTPUT); //settaggio dei pin
pinMode (STROBE_PIN, OUTPUT);
pinMode (RESET_PIN, OUTPUT);
int n=0;
for(int i=0; i<7; i++){ //numera i led (dipende da come sono collegati)
for(int j=0; j<8; j++){
colori[i][j].nled=n;
n++;
}
}
FastLED.addLeds<WS2812B,DATA_PIN, RGB>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
FastLED.setBrightness( BRIGHTNESS );
time_arcobaleno=millis();
time_cambio=millis();
}
//////LOOP//////
void loop() {
leggiMSGEQ7();
if(millis()-time_cambio > 5000){ //codice che stabilisce ogni quanto cambiare effetto
effetto++;
if(effetto>3){
effetto=0;
}
time_cambio=millis();
}
switch(effetto){
case 0:
arcobaleno_a_punti();
colonna_piena();
aggiornaHSV();
break;
case 1:
if(millis()-time_arcobaleno > 15){
arcobaleno_dinamico();
time_arcobaleno=millis();
}
colonna_piena();
aggiornaHSV();
break;
case 2:
if(millis()-time_arcobaleno > 15){
arcobaleno_dinamico();
time_arcobaleno=millis();
}
colonna_piena();
if(destra[1]/delta > 5){
colore_totale_rgb(255, 255, 255);
aggiornaRGB();
}else{
aggiornaHSV();
}
break;
case 3:
colore_totale_hsv(255, 255, 255);
colonna_piena();
aggiornaHSV();
break;
}
////esempio settaggio colore:
//leds[i] = CRGB( 50, 100, 150);
//leds[i] = CRGB::Red;
// La conversio a RGB è automatica.
//leds[i] = CHSV( 160, 255, 255);
//leds[i] = CRGB::Red;
//FastLED.show();
//FastLED.delay(1000 / FRAMES_PER_SECOND);
delay(30);
}
/////FUNZIONI
// Funzione che legge le 7 bande del canale destro e sinistro.
void leggiMSGEQ7(void){
digitalWrite(RESET_PIN, HIGH);
digitalWrite(RESET_PIN, LOW);
for(int banda=0; banda <COLONNE; banda++){
digitalWrite(STROBE_PIN,LOW); // strobe, passa alla banda sucessiva
delayMicroseconds(30); //ritardo per rispettare le tempistiche dell'integrato (vedere datasheet)
destra[banda] = analogRead(0)-RUMORE; // salva la lettura della banda destra
sinistra[banda] = analogRead(1)-RUMORE; // ... e di quella sinistra
digitalWrite(STROBE_PIN,HIGH);
medio[banda]= (destra[banda] + sinistra[banda])/2;
Serial.println (destra [banda], DEC);
}
}
void aggiornaRGB(void){
for(int i=0; i<7; i++){
for(int j=0; j<8; j++){
if(colori [i][j].attivo==1){
leds[colori[i][j].nled] = CRGB(colori[i][j].r, colori[i][j].g, colori[i][j].b);
}else{
leds[colori[i][j].nled] = CRGB::Black;
}
FastLED.show(); // è qui che i led effettivamente vengono aggiornati
}
}
}
void aggiornaHSV(void){
for(int i=0; i<COLONNE; i++){
for(int j=0; j<RIGHE; j++){
if(colori[i][j].attivo==1){
leds[colori[i][j].nled] = CHSV(colori[i][j].hue, colori[i][j].sat, colori[i][j].val);
}else{
leds[colori[i][j].nled] = CRGB::Black;
}
}
}
FastLED.show(); // è qui che i led effettivamente vengono aggiornati
}
void colonna_piena(void){
nlivello=0;
for(int i=0; i<COLONNE; i++){
nlivello=destra[i]/delta;
for(int j=0; j<RIGHE; j++){
if(j <= nlivello){
colori[i][j].attivo=1;}
else{
colori[i][j].attivo=0;}
}
//colori[i][picchi[i]].attivo=1;
}
}
void colore_totale_hsv(int h, int s, int v){
for(int i=0; i<7; i++){
for(int j=0; j<8; j++){
colori[i][j].hue=h;
colori[i][j].sat=s;
colori[i][j].val=v;
}
}
}
void colore_totale_rgb(int r, int g, int b){
for(int i=0; i<7; i++){
for(int j=0; j<8; j++){
colori[i][j].r=r;
colori[i][j].g=g;
colori[i][j].b=b;
}
}
}
void arcobaleno_a_colonne(void){
int n=36;
for(int i=0; i<7; i++){
for(int j=0; j<8; j++){
colori[i][j].hue=n;
colori[i][j].sat=230;
colori[i][j].val=240;
}
n+=36;
}
}
void arcobaleno_a_punti(void){
int n=36;
for(int i=0; i<7; i++){
for(int j=0; j<8; j++){
colori[i][j].hue=n;
colori[i][j].sat=230;
colori[i][j].val=240;
n+=5;
}
}
}
void arcobaleno_dinamico(void){
for(int i=0; i<7; i++){
for(int j=0; j<8; j++){
colori[i][j].hue=hue_arcobaleno;
colori[i][j].sat=230;
colori[i][j].val=240;
}
}
hue_arcobaleno++;
}
jose 21 Luglio 2018
hi denis,,,, please send me the schemetic to conect spectrum shield … thanks
Denis Lanfrit 22 Luglio 2018 — Post Author
Hi Jose, the connections are very simple: the led strip is connected to a 5v power supply and the data pin to Arduino digital pin n°6. The shield is simply inserted on Arduino Uno and pin n° 4 and 5 are used to select data from the shield, analog pin 0 and 1 are used to read data.
This is an helpful link
Amir 19 Ottobre 2018
Hi Denis,
thanx for sharing your idea and your code. I have a question. Do I have to copy both codes in a single Arduino file or are they two separate files? I can’t figure out how to use them.
cheers
Denis Lanfrit 19 Ottobre 2018 — Post Author
Hi Amir, It is indifferent, you can do it in both ways, for example you can copy the code in the same order as above into a single file and compile
wensen 26 Novembre 2018
hi…friend…
how to make this Spectrum Analyzer with peak…?
Mark 19 Maggio 2019
Hi Denis
Thanks for sharing this, I look forward to trying it out. Is this the most recent version?
Denis Lanfrit 5 Giugno 2019 — Post Author
Hi,
Thanks, yes this is the most recent version
Aranng 30 Marzo 2020
Appreciate all your work..thanks
Maybe,more row colum looks better..