RGB strip commander: generazione interrupt fittizio

Buongiorno ragazzi!
Dopo aver realizzato una piccola lampada led RGB comandat via blueetooth ( con android, ma questa è un alta storia), mi sto un po incartando "teoricamente" col suo controller ( che nel mio caso è un atmega328 standalone) .

Vi spiego un po come è strutturato il software:
1.Controllo dati su seriale.
2.salvataggio dato seriale in variabile numerica
3.switch-case sul dato ricevuto
4.chiamata funzione corrispondente al dato ricevuto

Problema: le funzioni che generano gli effetti visivi, contengono dei delay, che servono ad esempio a determinare quanto velocemente si deve passare da un colore all'altro nell'effetto "Arcobaleno" , o semplicemente ad alleggerire il carico al chip quando invece il colore deve rimanere stabile su un valore impostato. Questo cosa comporta? che se imposto un delay(3000) alla transizione "Arcobaleno", in modo che questa avvenga a una velocità non psichedelica, ovviamente il sistema non risponderà ad altri comandi fino a quando quella transizione non è terminata,e si parla di minuti. ( finita quella transizione, ricomincia il loop e rilegge finalmente la seriale).

Cosi pensavo a un qualche modo per interrompere questa attesa e rendere tutto più " real time".
La prima cosa che mi è balzata in mente è stata: quando il bluetooth ( un hc-06 classico) riceve un dato ( e quindi il pin di arduino riceve un segnale sulla linea Rx), genera un interrupt, che fa ripartire il loop dall'inizio. In questo modo rileggerei subito il valore sulla seriale e la mia transizione avverrebbe con un ritardo minimo.

Secondo voi è realizzabile una cosa del genere? ad esempio mandando il pin TX dell'hc-06 in ingresso anche al pin di interrupt oltre che a quello di Rx di arduino? Esistono soluzioni alternative? VI è capitato di dover affrontare un problema del genere?

La ricezione sulla seriale è gestita da interrupt onde evitare che sian persi dei byte mentre il processore è impegnato a fare altro.

Ovviamente il tutto è limitato dalle dimensione del buffer (se non sbaglio 64 byte) che è sufficiente per normali utilizzi.

Quindi, il tuo problema non è ricevere i dati (a quello ci pensa l'interrupt) ma leggerli ed interpretarli.

Potresti usare SerialEvent():

Cyber, intanto grazie per la risposta.

Purtroppo temo di non seguirti ( o molto più probabilmente , mi sono spiegato male io )
Il mio problema non è interpretare il dato, ma quando riesco a leggerlo, poichè in quel loop ci sono dei delay dovuti a funzioni esterne. Quindi con Serial.Event() io riesco a fare esattamente quello che faccio ora solo che , essendo questa funzione eseguita tra un loop e l'altro, prima che venga eseguita subisco comunque il delay.

Scrivo un pezzettino di codice di esempio per spiegarmi meglio:

 void loop(){
if(Serial.avalable()){
code=Serial.read();
emptySerial(); // funzione che ho creato per svuotare la seriale da eventuli valori non voluti /accavallati
}
Switch(code){
case 1:
 digitalWrite(Led1, HIGH);
delay(5000);
break;
case 2:
digitalWrite(Led2,HIGH)
delay(3000);
break;
default:
digitalWrite(Led1,LOW);
digitlWrite(led2,LOW);
break;
}

Il mio problema sta in quei delay li, che non riesco a evitare. La mia situazione ideale, sarebbe poter leggere costantemente la seriale e, nel momento in cui ricevo un dato, come fosse un interrupt, interrompere quei 2 case,ritornare all'inizio del loop e andare a leggere il dato che ho ricevuto.

Devi cambiare tutti i tuoi delay con millis.
La cosa non è facile da farsi ora che hai strutturato il programma in una certa maniera, ma è l'unico modo per poter leggere la seriale E cambiare le animazioni in corso d'opera.

Ti passo questo link:
http://www.leonardomiliani.com/2012/lampada-da-tavolo-con-led-rgb/
Troverai il progetto di una lampada RGB che ho realizzato un paio d'anni fa. Nel codice ci sono diverse animazioni, tutte gestite con millis, e la lettura del sensore capacitativo per cambiare le animazioni anche mentre il codice ne sta eseguendo una.
Penso possa esserti d'aiuto.

@leo72

Per certi versi i nostri codici sono molto simili, escluso il fatto delle millis() e che non uso un TLC5940 per alimentare dei led ma dei semplici bc337 per pilotare una led strip.
Temo si, che dovro lavorare pesantemente sulla gestione del cambio stato tramite millis(), oppure trovare una " toppa"che mi consenta di eseguire il check su seriale piu frequentemente, anche durante la transizione dei colori et similari,in modo da abbattere i ritardi in modo drastico fino a qualche secondo al massimo.
Poi darò la colpa al bluetooth, un po come quando su internet si giustifica la lentezza di java con " eh ma tanto la rete ha dei ritardi di propagazione, dovrei aspettare comunque " :smiley: :smiley: :smiley:
Comunque il tuo progetto è veramente bello e ben strutturato, dovrò farmi una cultura su quel TLC che non ho mai usato :slight_smile:

Scusa leo72, stavo dimenticando di chiederti la cosa che più mi ha colpito del tuo progetto!
Come hai realizzato il sensore di prossimità con lo spezzone di filo?
Sarebbe una feature che aggingerei volentieri al mio progetto( per ora c'è un normalissimo e antiestetico pulsante)

  1. la "toppa" potrebbe essere di usare serialEvent, è una funzione che viene richiamata quando dei dati sono disponibili nel buffer seriale:
    serialEvent() - Arduino Reference

  2. il sensore capacitimetro è un semplice pezzo di filo "letto" tramite un pin analogico:
    Arduino Playground - CapacitiveSensor

SerialEvent mi resta abbastanza criptica. La reference dice che viene chiamata ogni volta che ci sono dati disponibili in seriale( e qui penso a una cosa tipo interrupt), ma il tutorial dice che viene chiamata solo alla fine del loop ( e se fosse cosi, nel mio caso è quasi completamente inutile, perche i delay li ho prima e me li becco comunque)

Per quanto riguarda il pulsante capacitivo, sto facendo qualche test con l'esempio standard della libreria....ma devo dire che non mi garba tantissimo quest'ultima ( che purtroppo non è piu quella utilizzata nel progetto di leo72, ma credo sia la versione aggiornata) . in quanto stampando su seriale leggo sempre valori un pochino random e non molto costanti ( anche se devo ammettere che comunque un discriminante tocco/non tocco , si riesce a trovare) . Navigherò sul web alla ricerca di una libreria alternativa magari :slight_smile:
Inoltre adesso vorrei sostituire questo pulsante capacitivo a quello fisico,ma devo trovare il modo di sfruttarlo come interrupt...
Si insomma, il progetto di leo72 mi ha dato davvero molti spunti!!!
Una volta imparato a padroneggiare questa "tecnica" penserò a qualcosa di piu complesso , tipo sfruttare una serie di questi pulsanti per differenziare i comandi a seconda del tipo di swishata :smiley:
Mi si è aperto un mondo!

nicostak:
SerialEvent mi resta abbastanza criptica. La reference dice che viene chiamata ogni volta che ci sono dati disponibili in seriale( e qui penso a una cosa tipo interrupt), ma il tutorial dice che viene chiamata solo alla fine del loop ( e se fosse cosi, nel mio caso è quasi completamente inutile, perche i delay li ho prima e me li becco comunque)

SerialEvent viene chiamata dopo ogni loop ma non è una routine pilotata da interrupt bensì un semplice "if" che controlla se ci sono dati nella seriale (if Serial.available()) e nel caso esegue il codice che tu hai inserito in SerialEvent.
Se vuoi fare qualcosa di tuo, devi metter mano al core della seriale e modificare le ISR di gestione. Ma diventa complesso e non so se ne vale la pena. Alla fine potresti anche ovviare con un timer che ti genera un interrupt ad intervalli regolari e verificare se ci sono dati nella seriale, usando cioè un approccio tipo scheduler di cui ti avevo già accennato.

Per quanto riguarda il pulsante capacitivo, sto facendo qualche test con l'esempio standard della libreria....ma devo dire che non mi garba tantissimo quest'ultima ( che purtroppo non è piu quella utilizzata nel progetto di leo72, ma credo sia la versione aggiornata) . in quanto stampando su seriale leggo sempre valori un pochino random e non molto costanti ( anche se devo ammettere che comunque un discriminante tocco/non tocco , si riesce a trovare) . Navigherò sul web alla ricerca di una libreria alternativa magari :slight_smile:

Quel progetto è di 2 anni fa e può essere che la lib sia stata cambiata, nel frattempo.
Tieni però conto che anch'io all'epoca incontrai non poche difficoltà. Il primo scoglio è capire se ti serve o meno il C che loro dicono di mettere:

Research has shown that a small capacitor (100 pF) or so from sensor pin to ground improves stability and repeatability

La mia "research" dimostrò invece che col C non c'era verso di far funzionare il dispositivo!
Altro punto su cui ho sbattuto la testa è stato il valore della R usata per collegare i 2 pin, se non trovi il valore esatto (che dipende anche da che tipo di "sensore" userai, io ho usato una dozzina di cm di filo inguainato per collegamenti leggermente attorcigliato a formare una specie di girella) poi il sensore non funziona. prova con qualcosa tipo 8M2, 10M.

Inoltre adesso vorrei sostituire questo pulsante capacitivo a quello fisico,ma devo trovare il modo di sfruttarlo come interrupt...
Si insomma, il progetto di leo72 mi ha dato davvero molti spunti!!!
Una volta imparato a padroneggiare questa "tecnica" penserò a qualcosa di piu complesso , tipo sfruttare una serie di questi pulsanti per differenziare i comandi a seconda del tipo di swishata :smiley:
Mi si è aperto un mondo!

C'è comunque anche di più specifico, ci sono sensori capacitivi veri e propri, tipo:

ecc..

@leo72

Alla fine ho piazzato la toppa, sono andato a modificare le animazioni, non con millis() ( avrei dovuto riscrivere tutto da capo) ma inserendo un check sulla seriale ad ogni "transizione" di colore , in questo modo riesco ad ottenere ritardi decisamente accettabili. Sto valutando anche l'ipotesi timer, non penso di inserirla in questo progetto, ma sicuramente mi tornerà utile, e sarà utile anche farmi una cultura a riguardo :slight_smile:

Per quanto riguarda il pulsante touch , saranno anche passati 2 anni ma sto sperimentando tutti i problemi che hai citato.
Con le resistenze è un terno al lotto, ho provato resistenze da 100K fino a 40M , a 100K più che touch bisogna tirargli un cazzotto, a 40M io le 2-4 inches di sensibilità che ho letto su internet me le sogno, ottengo minime variazioni solo stando a non piu di mezzo cm dal filo .
(Per la cronaca ho usato del normalissimo cavo elettrico,quello con la guaina gialla e verde per intenderci, anch'io di una decina di centimetri). Ho anche notato che il filo è molto piu sensibile nel punto di collegamento con i pin di arduino rispetto all'estremità che dovrebbe essere il pulsante vero e proprio.
Il Cap non l'ho provato ma è questione di minuti e mi gioco anche quella carta.:slight_smile:
Ho cercato degli integrati che potessero farmi la conversione capacità-Voltaggio per generare l'interrupt, tipo il QT113 , o QT1011, e tutta quella famiglia....ovviamente sono quasi tutti fuori produzione, di package DIP non se ne parla, e anche sul sito atmel non mandano campioni.
Avevo trovato un interessante ADM660 della AnalogDevices ma costa un po troppo per le mie tasche da universitario, e ovviamente , samples neanche a parlarne.
SIccome anche Sparkfun fa roba bellissima , ma devo rinunciare a una rata della macchina per acquistare li , ho virato su qualcosa di piu economico, nello specifico questo :

Ordinato ieri, arriverà tra 2 mesi, ma sono fiducioso.

Per quanto riguarda altre librerie, ho trovato poco altro, ma soprattutto non sono riuscito a trovare materiale su questa qui proposta nella playground. Ne un readme, ne un tutorial, e cosi sto andando un po a tentoni :smiley:

La lib nel playground è documentata non proprio benissimo, però se apri lo sketch della mia lampada trovi l'inizializzazione del sensore e la lettura. Non è difficile usarla, alla fine.

Nono , usarla non è sicuramente difficile, invece usarla BENE cosi è abbastanza complicato....ma la notte è lunga...e porterà consiglio :slight_smile:

Update: Anche secondo la mia "Research" di oggi , quel cap tra sensore e gnd non rende stabile un bel niente, anzi, ha l'effetto contrario, ( Sia sul circuito, sia su chi ci lavora :smiley: )

Update2: Ho trovato una " toppa" anche al sensore touch. Brutta, poco pratica, sconveniente, ecc ecc ecc , ma funziona e per questa volta mi posso accontentare, non essendo un progetto definitivo.

Ho programmato un attiny45 per gestire il sensore touch ( non molto piu dell'esempio contenuto nella libreria) , e gli faccio alzare un uscita digitale quando rileva il tocco. Questa uscita l'ho mandata in ingresso all'Atmega328 della lampada vera e propria su un pin di interrupt attraverso una resistenza da 10K , e ho settato l'interrupt come HIGH.
Efficace : Si
Conveniente: NO
Intelligente : dipende dai punti di vista.

La scrivo giusto per i posteri, nel caso qualcuno avesse una problematica simile.
Tuttavia esistono soluzioni sicuramente piu convenienti e "smart" , questa è uno schiacciasassi che va bene quando si è alle strette.