(Risolto) Problemi con Striscia led RGB lpd8806

Ciao a tutti, possiedo una striscia led da 1 metro con 32 led, con integrato lpd8806,
ho scaricato la libreria dal sito adafruit e l'esempio funziona correttamente.
Quel che vorrei fare, è accendere o spegnere la barra led da monitor seriale e in parte ci son riuscito solo che quando invio il dato, la striscia accende per qualche secondo e poi si blocca al contrario se lascio il codice per accendere i led dentro il void loop senza usare la serial read,funziona tutto .
Quindi a livello hardware dovrebbe essere tutto ok.
Penso di fare qualche errore nello sketch che allego:

#include "LPD8806.h"
#include "SPI.h"

String a;
int nLEDs = 32;
int dataPin = 2;
int clockPin = 3;
LPD8806 strip = LPD8806(nLEDs, dataPin, clockPin);

void setup() {
strip.begin();
strip.show();
Serial.begin(9600);
delay(1000); 
Serial.println("Leggo i dati ricevuti");
}

void scanner (uint8_t r, uint8_t g, uint8_t b, uint8_t wait);

void loop() {
 
while (Serial.available()>0){
a = Serial.readString ();

Serial.print ( "ho ricevuto:");
Serial.println(a);
if(a.indexOf("off") >=0)
    {
      scanner(0,0,0, 0);
    }
    if(a.indexOf("on") >=0)
    {
      scanner(127,0,0, 30);
       
    }}}
  

void scanner(uint8_t r, uint8_t g, uint8_t b, uint8_t wait) {
 int i, j, pos, dir;

  pos = 0;
  dir = 1;

  for(i=0; i<((strip.numPixels()-1) * 8); i++) {
    strip.setPixelColor(pos - 2, strip.Color(r/4, g/4, b/4));
    strip.setPixelColor(pos - 1, strip.Color(r/2, g/2, b/2));
    strip.setPixelColor(pos, strip.Color(r, g, b));
    strip.setPixelColor(pos + 1, strip.Color(r/2, g/2, b/2));
    strip.setPixelColor(pos + 2, strip.Color(r/4, g/4, b/4));

    strip.show();
    delay(wait);
    for(j=-2; j<= 2; j++) 
    strip.setPixelColor(pos+j, strip.Color(0,0,0));
    pos += dir;
    if(pos < 0) {
    pos = 1;
    dir = -dir;
    }
    else if(pos >= strip.numPixels()) {
    pos = strip.numPixels() - 2;
    dir = -dir;
    }
  }
}

uint32_t Wheel(uint16_t WheelPos)
{
  byte r, g, b;
  switch(WheelPos / 128)
  {
    case 0:
      r = 127 - WheelPos % 128; // red down
      g = WheelPos % 128;       // green up
      b = 0;                    // blue off
      break;
    case 1:
      g = 127 - WheelPos % 128; // green down
      b = WheelPos % 128;       // blue up
      r = 0;                    // red off
      break;
    case 2:
      b = 127 - WheelPos % 128; // blue down
      r = WheelPos % 128;       // red up
      g = 0;                    // green off
      break;
  }
  return(strip.Color(r,g,b));
}

Ringrazio anticipatamente tutti coloro che mi daranno una mano.
Saluti
Enzo

Ho dimenticato di specificare che sto usando arduino uno

Up

Con Arduino UNO, se accedi alla seriale si resetta.
Dovresti prendere una Arduino Leonardo o Arduino Micro che non hanno questo problema oppure disabilitare l'autoreset tagliando la pista e aggiungendo un ponticello.

PaoloP:
Con Arduino UNO, se accedi alla seriale si resetta.
Dovresti prendere una Arduino Leonardo o Arduino Micro che non hanno questo problema oppure disabilitare l'autoreset tagliando la pista e aggiungendo un ponticello.

Ti ringrazio per la risposta.
Quindi lo sketch non presenta nessun errore?
Perché principalmente pensavo ci fosse qualche errore che mi sfuggiva e aspettavo conferma da più esperti di me.
Proverò a caricare lo sketch su arduino nano e vi farò sapere se ho risolto.
Per adesso grazie mille.

Ho provato a caricare lo sketch su arduino nano e il problema persiste.
Scusate la mia ignoranza,ma arduino micro e il nano sono la stessa cosa giusto?

NO, le MCU sono diverse ...
... se a bordo c'è l'ATMega328P e un chip adattatore seriale <-> USB, allora all'apertura della seriale la scheda si resetta, se a bordo che un ATmega32U4 che gestisce lui la USB, allora all'apertura della seriale NON si resetta.

La Nano monta l'ATMega328P (o ATmega168P) e un adattatore seriale FTDI.

Ci sono dei metodi per disabilitare la cosa ... prova a fare una ricerca con Google per "disable arduino autoreset"

Guglielmo

Potresti sostituire il while con un if. Alla fine non ti serve che manga dentro il while ma basta che entri una sola volta, legge il comando e lo esegue.

Ciao a tutti,
e grazie per le risposte,
ho provato a disabilitare l'autoreset mettendo un condensatore da 10μF tra reset e gnd e il problema persiste,
ho provato a sostituire il while con if e anche in questo caso non và.
La cosa strana è che quando scrivo on nel monitor seriale, il comando viene eseguito correttamente per 5 secondi dopodichè i led rimangono accesi, mentre invece dovrebbe continuare il loop ad accendere i led in modalità scanner finchè sul monitor non invio il comando off.
E' la prima volta che mi si presenta un problema simile :o

Ma quindi tu NON hai un problema di reset ... perché tu, una volta aperto il monitor seriale, non è che continui ad aprirlo e chiuderlo, semplicemente scrivi "on" e poi resti li in attesa ...

Questo NON chiude il monitor seriale e NON provoca il reset, quindi ... è evidentemente un errore di codice. ::slight_smile:

Guglielmo

gpb01:
Ma quindi tu NON hai un problema di reset ... perché tu, una volta aperto il monitor seriale, non è che continui ad aprirlo e chiuderlo, semplicemente scrivi "on" e poi resti li in attesa ...

Questo NON chiude il monitor seriale e NON provoca il reset, quindi ... è evidentemente un errore di codice. ::slight_smile:

Guglielmo

Mi scuso se nel primo post non sono stato abbastanza dettagliato.
Ma il problema è proprio quello , io non apro e chiudo il monitor seriale di continuo ma semplicemente vorrei che quando scrivo on nel monitor seriale, esegua la voce scanner.
Cosa che avviene correttamente ma solo per 5 secondi , purtroppo poi si blocca facendo rimanere i led accesi e inviando il dato off li spengo quindi la seriale è ok.
Il codice fa parte della libreria adafruit lpd8806 che ho modificato, inserendo soltanto la serial read e eliminando gli altri effetti luci che per il momento non mi interessano, preciso che la voce scanner inserita nel void loop senza altro codice, mi fa funzionare correttamente la striscia led senza bloccarsi. Non riesco a capire dove possa essere l'errore.

Ho semplificato lo sketch in modo tale da farlo il più chiaro possibile:

#include "LPD8806.h"
#include "SPI.h"

String a;
int nLEDs = 32;
int dataPin  = 2;
int clockPin = 3;
LPD8806 strip = LPD8806(nLEDs, dataPin, clockPin);

void setup() {
// Start up the LED strip
strip.begin();

// Update the strip, to start they are all 'off'
strip.show();
Serial.begin(9600);
delay(1000); 
Serial.println("Leggo i dati ricevuti");
}

void loop() {
if (Serial.available()>0){
a = Serial.readString ();
Serial.print ("ho ricevuto:");
Serial.println(a);
if(a.indexOf("off") >=0)
{
colorChase(strip.Color(0,  0,  0), 100); 
}
if(a.indexOf("on") >=0)
{
colorChase(strip.Color(127,  0,  0), 100); // Red
}
}}

// Chase one dot down the full strip.  Good for testing purposes.
void colorChase(uint32_t c, uint8_t wait) {
  int i;
  
  // Start by turning all pixels off:
  for(i=0; i<strip.numPixels(); i++) strip.setPixelColor(i, 0);

  // Then display one pixel at a time:
  for(i=0; i<strip.numPixels(); i++) {
    strip.setPixelColor(i, c); // Set new pixel 'on'
    strip.show();              // Refresh LED states
    //strip.setPixelColor(i, 0); // Erase pixel, but don't refresh!
    delay(wait);
}
  
  strip.show(); // Refresh to turn off last pixel
}

Premendo on sul monitor seriale la striscia accende ma poi i led rimangono tutti accesi.
Mi chiedo se arduino sia in grado di eseguire dei loop diversi l'uno dall'altro in base al comando che si invia via seriale?
esempio sul monitor seriale scrivo luce1 e nello sketch imposto che al ricevimento del dato luce1, deve eseguire senza interruzione un loop di gioco luci da stabilire e solo quando scrivo off la striscia si spegnerà.
via dicendo se scrivo luce2 dovrà eseguire un altra modalità di gioco luci ecc ecc.
Qualcuno puo' confermarmi che cio' sia possibile?
Grazie a tutti.
Enzo

Enzo--:
...
Mi chiedo se arduino sia in grado di eseguire dei loop diversi l'uno dall'altro in base al comando che si invia via seriale?
...

Emmm ... dedicare del tempo a studiare un po meglio "le basi" del 'C' no ? ... perché si chiamano "funzioni" ... ::slight_smile:

Prova a dare una letta a QUESTO proseguire con QUESTO e puoi, ad esempio, comprarti un bel libro come QUESTO :wink:

Guglielmo

gpb01:
Emmm ... dedicare del tempo a studiare un po meglio "le basi" del 'C' no ? ... perché si chiamano "funzioni" ... ::slight_smile:

Prova a dare una letta a QUESTO proseguire con QUESTO e puoi, ad esempio, comprarti un bel libro come QUESTO :wink:

Guglielmo

Ieri sera mi sono espresso male,
hai perfettamente ragione basta usare le funzioni,
ascolterò i tuoi consigli e darò una ripassata ai link che mi hai postato.
Non ho mai avuto grossi problemi con arduino ma probabilmente non mi era mai capitato di usare delle funzioni da far eseguire in più loop.
Grazie
Enzo

Una possibilità potrebbe essere avere una funzione che interroga la seriale e che mette in una variabile "globale" un "codiceAttivita", esempio:

0 = non si è ricevuto nulla
1 = si è ricevuto il comando di accendere i LED rossi
2 = si è ricevuto il comando di accendere i LED verdi
3 = si è ricevuto il comando di accendere i LED blue
4 = si è ricevuto il comando per il gioco di luci numero 1
5 = si è ricevuto il comando per il gioco di luci numero 2
....
....
99 = si è ricevuto il comando per spegnere tutto

In questo modo, in qualsiasi punto del porgramma sei, potrai sempre chiamarla e sapere se l'utente ha trasmesso un comando.

Dopo di che potrai avere N funzioni, ciascuna dedicata a fare una specifica cosa (esempio, un singolo gioco di luci), che gira in continuazione (esempio con un while()) e che interroga la funzione della seriale per vedere se è arrivato un nuovo comando diverso da quello che sta facendo. Se SI, esce e dal loop() tu puoi chiamare la funzione relativa al nuovo comando che ... ripete esattamente lo stesso ciclo.

Più complesso a dirsi che a farsi ... :slight_smile:

Naturalmente è solo un suggerimento su una delle tantissime possibli strade da seguire ... probabilmente NON la più efficiente, ma magari la più semplice per dividere le varie "attività".

Guglielmo

Ciao Enzo,
mi sono soffermato a guardare la seconda versione di firmware che hai postato.
non mi convince il fatto che tu, ad ogni carattere ricevuto sovrascrivi la stringa "a". Di fatto, ad ogni ciclo la stringa conterrà solo un carattere.
Dovrebbe essere:

a += Serial.readString ();

e poi appena ricevi il messaggio che volevi:

a = "";

Poi un'altra cosa: nel loop() non fai niente oltre che controllare la seriale? Mi sembra strano..
Magari la libreria usa degli interrupt?

gpb01:
Una possibilità potrebbe essere avere una funzione che interroga la seriale e che mette in una variabile "globale" un "codiceAttivita", esempio:

0 = non si è ricevuto nulla
1 = si è ricevuto il comando di accendere i LED rossi
2 = si è ricevuto il comando di accendere i LED verdi
3 = si è ricevuto il comando di accendere i LED blue
4 = si è ricevuto il comando per il gioco di luci numero 1
5 = si è ricevuto il comando per il gioco di luci numero 2
....
....
99 = si è ricevuto il comando per spegnere tutto

In questo modo, in qualsiasi punto del porgramma sei, potrai sempre chiamarla e sapere se l'utente ha trasmesso un comando.

Dopo di che potrai avere N funzioni, ciascuna dedicata a fare una specifica cosa (esempio, un singolo gioco di luci), che gira in continuazione (esempio con un while()) e che interroga la funzione della seriale per vedere se è arrivato un nuovo comando diverso da quello che sta facendo. Se SI, esce e dal loop() tu puoi chiamare la funzione relativa al nuovo comando che ... ripete esattamente lo stesso ciclo.

Più complesso a dirsi che a farsi ... :slight_smile:

Naturalmente è solo un suggerimento su una delle tantissime possibli strade da seguire ... probabilmente NON la più efficiente, ma magari la più semplice per dividere le varie "attività".

Guglielmo

Ti ringrazio,
provero' anche questa soluzione.
Grazie

enable24:
Poi un'altra cosa: nel loop() non fai niente oltre che controllare la seriale? Mi sembra strano..
Magari la libreria usa degli interrupt?

Nel loop non interrogo solo la seriale ma eseguo anche i comandi on/off :

void loop() {
 
while (Serial.available()>0){
a = Serial.readString ();

Serial.print ( "ho ricevuto:");
Serial.println(a);
if(a.indexOf("off") >=0)
    {
      scanner(0,0,0, 0);   // spegne la striscia led
    }
    if(a.indexOf("on") >=0)
    {
      scanner(127,0,0, 30); // accende la striscia led in modalità kit (telefilm)
       
    }}}

faro' le prove e vi tengo aggiornati, sperando che non siano interrupt nella libreria a dar fastidio.

Ho effettuato le prove suggerite ma senza risultato.
Posto lo sketch originale d'esempio della libreria adafruit lpd8806:

#include "LPD8806.h"
#include "SPI.h" // Comment out this line if using Trinket or Gemma
#ifdef __AVR_ATtiny85__
 #include <avr/power.h>
#endif

// Example to control LPD8806-based RGB LED Modules in a strip

/*****************************************************************************/

// Number of RGB LEDs in strand:
int nLEDs = 32;

// Chose 2 pins for output; can be any valid output pins:
int dataPin  = 2;
int clockPin = 3;

// First parameter is the number of LEDs in the strand.  The LED strips
// are 32 LEDs per meter but you can extend or cut the strip.  Next two
// parameters are SPI data and clock pins:
LPD8806 strip = LPD8806(nLEDs, dataPin, clockPin);

// You can optionally use hardware SPI for faster writes, just leave out
// the data and clock pin parameters.  But this does limit use to very
// specific pins on the Arduino.  For "classic" Arduinos (Uno, Duemilanove,
// etc.), data = pin 11, clock = pin 13.  For Arduino Mega, data = pin 51,
// clock = pin 52.  For 32u4 Breakout Board+ and Teensy, data = pin B2,
// clock = pin B1.  For Leonardo, this can ONLY be done on the ICSP pins.
//LPD8806 strip = LPD8806(nLEDs);

void setup() {
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000L)
  clock_prescale_set(clock_div_1); // Enable 16 MHz on Trinket
#endif

  // Start up the LED strip
  strip.begin();

  // Update the strip, to start they are all 'off'
  strip.show();
}


void loop() {

  // Send a simple pixel chase in...
  colorChase(strip.Color(127, 127, 127), 50); // White
  colorChase(strip.Color(127,   0,   0), 50); // Red
  colorChase(strip.Color(127, 127,   0), 50); // Yellow
  colorChase(strip.Color(  0, 127,   0), 50); // Green
  colorChase(strip.Color(  0, 127, 127), 50); // Cyan
  colorChase(strip.Color(  0,   0, 127), 50); // Blue
  colorChase(strip.Color(127,   0, 127), 50); // Violet

  // Send a theater pixel chase in...
  theaterChase(strip.Color(127, 127, 127), 50); // White
  theaterChase(strip.Color(127,   0,   0), 50); // Red
  theaterChase(strip.Color(127, 127,   0), 50); // Yellow
  theaterChase(strip.Color(  0, 127,   0), 50); // Green
  theaterChase(strip.Color(  0, 127, 127), 50); // Cyan
  theaterChase(strip.Color(  0,   0, 127), 50); // Blue
  theaterChase(strip.Color(127,   0, 127), 50); // Violet

  // Fill the entire strip with...
  colorWipe(strip.Color(127,   0,   0), 50);  // Red
  colorWipe(strip.Color(  0, 127,   0), 50);  // Green
  colorWipe(strip.Color(  0,   0, 127), 50);  // Blue

  rainbow(10);
  rainbowCycle(0);  // make it go through the cycle fairly fast
  theaterChaseRainbow(50);
  scanner(127,0,0, 30);
}

void scanner(uint8_t r, uint8_t g, uint8_t b, uint8_t wait){
 int i, j, pos, dir;

  pos = 0;
  dir = 1;

  for(i=0; i<((strip.numPixels()-1) * 8); i++) {
    strip.setPixelColor(pos - 2, strip.Color(r/4, g/4, b/4));
    strip.setPixelColor(pos - 1, strip.Color(r/2, g/2, b/2));
    strip.setPixelColor(pos, strip.Color(r, g, b));
    strip.setPixelColor(pos + 1, strip.Color(r/2, g/2, b/2));
    strip.setPixelColor(pos + 2, strip.Color(r/4, g/4, b/4));

    strip.show();
    delay(wait);
    for(j=-2; j<= 2; j++) 
    strip.setPixelColor(pos+j, strip.Color(0,0,0));
    pos += dir;
    if(pos < 0) {
    pos = 1;
    dir = -dir;
    }
    else if(pos >= strip.numPixels()) {
    pos = strip.numPixels() - 2;
    dir = -dir;
    }
  }
}

void rainbow(uint8_t wait) {
  int i, j;
   
  for (j=0; j < 384; j++) {     // 3 cycles of all 384 colors in the wheel
    for (i=0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel( (i + j) % 384));
    }  
    strip.show();   // write all the pixels out
    delay(wait);
  }
}

// Slightly different, this one makes the rainbow wheel equally distributed 
// along the chain
void rainbowCycle(uint8_t wait) {
  uint16_t i, j;
  
  for (j=0; j < 384 * 5; j++) {     // 5 cycles of all 384 colors in the wheel
    for (i=0; i < strip.numPixels(); i++) {
      // tricky math! we use each pixel as a fraction of the full 384-color wheel
      // (thats the i / strip.numPixels() part)
      // Then add in j which makes the colors go around per pixel
      // the % 384 is to make the wheel cycle around
      strip.setPixelColor(i, Wheel( ((i * 384 / strip.numPixels()) + j) % 384) );
    }  
    strip.show();   // write all the pixels out
    delay(wait);
  }
}

// Fill the dots progressively along the strip.
void colorWipe(uint32_t c, uint8_t wait) {
  int i;

  for (i=0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, c);
      strip.show();
      delay(wait);
  }
}

// Chase one dot down the full strip.
void colorChase(uint32_t c, uint8_t wait) {
  int i;

  // Start by turning all pixels off:
  for(i=0; i<strip.numPixels(); i++) strip.setPixelColor(i, 0);

  // Then display one pixel at a time:
  for(i=0; i<strip.numPixels(); i++) {
    strip.setPixelColor(i, c); // Set new pixel 'on'
    strip.show();              // Refresh LED states
    strip.setPixelColor(i, 0); // Erase pixel, but don't refresh!
    delay(wait);
  }

  strip.show(); // Refresh to turn off last pixel
}

//Theatre-style crawling lights.
void theaterChase(uint32_t c, uint8_t wait) {
  for (int j=0; j<10; j++) {  //do 10 cycles of chasing
    for (int q=0; q < 3; q++) {
      for (int i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, c);    //turn every third pixel on
      }
      strip.show();
     
      delay(wait);
     
      for (int i=0; i < strip.numPixels(); i=i+3) {
        strip.setPixelColor(i+q, 0);        //turn every third pixel off
      }
    }
  }
}

//Theatre-style crawling lights with rainbow effect
void theaterChaseRainbow(uint8_t wait) {
  for (int j=0; j < 384; j++) {     // cycle all 384 colors in the wheel
    for (int q=0; q < 3; q++) {
        for (int i=0; i < strip.numPixels(); i=i+3) {
          strip.setPixelColor(i+q, Wheel( (i+j) % 384));    //turn every third pixel on
        }
        strip.show();
       
        delay(wait);
       
        for (int i=0; i < strip.numPixels(); i=i+3) {
          strip.setPixelColor(i+q, 0);        //turn every third pixel off
        }
    }
  }
}
/* Helper functions */

//Input a value 0 to 384 to get a color value.
//The colours are a transition r - g -b - back to r

uint32_t Wheel(uint16_t WheelPos)
{
  byte r, g, b;
  switch(WheelPos / 128)
  {
    case 0:
      r = 127 - WheelPos % 128;   //Red down
      g = WheelPos % 128;      // Green up
      b = 0;                  //blue off
      break; 
    case 1:
      g = 127 - WheelPos % 128;  //green down
      b = WheelPos % 128;      //blue up
      r = 0;                  //red off
      break; 
    case 2:
      b = 127 - WheelPos % 128;  //blue down 
      r = WheelPos % 128;      //red up
      g = 0;                  //green off
      break; 
  }
  return(strip.Color(r,g,b));
}

nel void loop vengono ripetute a ciclo infinito diverse combinazioni di gioco luci se non sbaglio una ventina,
quello che volevo fare io, era di assegnare alle 20 possibilità di gioco luci, un dato per poter scegliere quale delle 20 possibilità eseguire separatamente.
Notando che le funzioni sono già state create, pensavo che bastasse inserire :

void loop() {
 
while (Serial.available()>0){
a = Serial.readString ();

Serial.print ( "ho ricevuto:");
Serial.println(a);
if(a.indexOf("off") >=0)
    {
      scanner(0,0,0, 0);  //spegne striscia led
    }
    if(a.indexOf("on") >=0){ 
    scanner(127,0,0, 30); // accende striscia led in modalità kit (telefilm)
}
}}

non riesco davvero a capire come mai quando scrivo on nel monitor seriale la striscia accende per 5 secondi e poi si blocca.
In teoria dovrebbe eseguire la funzione scanner fino a quando non do' altri ordini dal monitor seriale ma nulla da fare.
:o

Hai collegato qualcosa ai pin 0 e 1 di Arduino?