Domanda:
Come posso eseguire due loop contemporaneamente su un Arduino Uno?
Daniel T.
2014-09-29 02:54:06 UTC
view on stackexchange narkive permalink

Sono nuovo su Arduino e ho due dispositivi che sto cercando di controllare:

  1. Una striscia luminosa a LED RGB che può cambiare i colori
  2. Una luce sensore in grado di rilevare il livello di luce ambientale

Quello che vorrei fare è che la striscia LED scorra continuamente attraverso un arcobaleno di colori e il sensore di luce regolerà la luminosità del LED striscia in base al livello di luce ambientale. Ecco i due pezzi di codice da soli, che ho testato isolatamente e ho confermato che funzionano correttamente:

Striscia LED:

  j = (j + 1 )% 256; // iterazione corrente del ciclo di luce // imposta il colore della striscia per (int i = 0; i< strip.numPixels (); i ++) {strip.setPixelColor (i, Wheel (((i * 256 / strip.numPixels ()) + j) & 255));} // mostra i nuovi colori e aspetta 20 ms prima del prossimo cyclestrip.show (); delay (20);  

Sensore di luce:

  Sensor_event_t evento; tsl.getEvent (&event); // ottiene una misurazione della lucestrip.setBrightness (event.light); // imposta la luminosità della striscia LED  

Il problema è che il sensore di luce impiega da 100 ms a 600 ms per ottenere una lettura e tsl.getEvent (&event) è una chiamata di blocco, quindi il risultato finale è che la striscia LED si aggiorna troppo lentamente. Avrei bisogno di eseguire i due fianco a fianco in modo che il sensore di luce letto non blocchi l'aggiornamento della striscia LED. Qualche idea su come posso farlo?

da quale libreria proviene "tsl"?
Da 100 a 600 ms è eccessivo. È solo per un LDR collegato a un ingresso analogico?
@BrettM Penso che stia usando il sensore di luce I2C TSL2561.
Sei risposte:
#1
+6
Gerben
2014-09-29 18:02:07 UTC
view on stackexchange narkive permalink

Puoi fare in modo che il sensore restituisca i dati più velocemente abbassandone la precisione.

  tsl.setIntegrationTime (TSL2561_INTEGRATIONTIME_13MS); / * veloce ma a bassa risoluzione * /  

Puoi anche modificare la libreria per non spegnere il sensore dopo ogni lettura. Basta aprire TSL2561.cpp , trovare la funzione getFullLuminosity e commentare la riga che legge disable (); e le 12 righe che leggono switch (_integration) {...}

Un'altra soluzione è fare in modo che i pixel si aggiornino ogni 20 ms utilizzando un timer. Puoi avere il timer, interrompere il ciclo principale ogni 20 ms e aggiornare i valori dei pixel.

(Non posso davvero aiutarti con i timer, poiché io stesso ho impostato i registri per i miei timer e gli ISR ​​direttamente, il che non è per i principianti. Ma probabilmente ci sono librerie per farlo, per farlo più facile da usare.)

http://playground.arduino.cc/code/timer1 questa libreria dovrebbe aiutare a semplificare i timer
Vedere la mia modifica sopra per negare la necessità di qualsiasi ritardo, lasciando sempre acceso lo tsl2561.
#2
+3
Duncan C
2014-09-29 04:42:33 UTC
view on stackexchange narkive permalink

Arduino non è un dispositivo multithread o multi-tasking. Devi scrivere le tue diverse funzioni per "giocare bene" l'una con l'altra. Il codice di blocco è la morte per questo tipo di multitasking. Potrebbe essere necessario riscrivere il codice che legge il sensore di luce come non bloccante.

Se riesci a fare in modo che il codice non blocchi, il post di Visual Micro è la strada da percorrere.

#3
+1
Visual Micro
2014-09-29 04:30:45 UTC
view on stackexchange narkive permalink

Imposta un "server di stato" nel tuo loop (). In parole povere, questo significa tenere traccia del comando successivo per ogni attività, quindi fare una cosa in ciascuna attività per ciclo ().

Se un'attività deve essere eseguita a una velocità maggiore di un'altra, puoi usare un timer nel tuo ciclo per decidere cosa fare dopo.

Se un'attività necessita di una pausa, salva "Last Run" millis () in una variabile globale e ignora l'attività fino a quando non è trascorso il tempo corretto . Non usare delay (), lascia sempre che loop () venga eseguito.

L'idea è che loop () venga eseguito il più spesso possibile, ma fai una cosa ogni volta che viene eseguito.

Ci vuole un po 'per capire questo modo di lavorare, ma lascia il processore Arduino libero di elaborare tutti i lavori in modo uniforme.

  int task1Status = 0; int task2Status = 0; void loop () {doOneThingOfTask1 (); doOneThingOfTask2 ();} // 10 cose per accendere i led, ma esegui solo onevoid doOneThingOfTask1 () {if (task1Status == 10) task1Status = 0; switch (task1Status) {case 0: // inizia a fare un nuovo processo case 1: // fai qualcosa case 9: // fai l'ultima cosa}}  
Stavo per pubblicare qualcosa di simile, poi ho notato che l'OP ha detto che il codice per prendere le misurazioni della luce sta bloccando il codice.
@Duncan C Oh! Buon punto. Lascio la risposta perché penso che descriva un modo di lavorare che evita lo stesso problema altrove nel codice. Inoltre potrebbe essere che esaminando la chiamata della libreria a getEvent () la stessa soluzione possa essere applicata per ridurre il ritardo. Ovviamente questo significa cambiare il codice della libreria ma è possibile copiare la libreria nella cartella sketch e hackerarla come sorgente locale. un cambio di Lib sarebbe sicuramente d'aiuto, ma una fonte locale e un po 'di hacking potrebbero produrre una soluzione. Grazie :)
#4
+1
JRobert
2014-09-29 22:10:02 UTC
view on stackexchange narkive permalink

Il tuo primo, più grande problema è

il sensore di luce impiega da 100 ms a 600 ms per ottenere una lettura e tsl.getEvent (&event) è una chiamata bloccante,

È necessario un accesso non bloccante al sensore di luce. Guarda il codice della libreria per vedere cosa sta facendo quando si blocca. È probabile che attenda che il sensore imposti un bit di "completamento". In tal caso, dovrai modificare la libreria, sia

  1. aggiungendo una funzione booleana .isDone () che verifica il bit di fine, e non lasciare il programma principale richiede una lettura fino a quando isDone () == TRUE; oppure
  2. rendere .getEvent () un non bloccante in modo tale che restituisca immediatamente una lettura ovviamente non valida (come -1) invece di bloccare se il sensore non è ancora pronto.
  3. ol>

    Ciò lascia il tuo programma principale libero di eseguire qualsiasi operazione necessaria ed è pronto a fare a meno di dover sostenere tutto per il sensore lento.

#5
  0
ForestPhoenix
2014-10-24 18:46:08 UTC
view on stackexchange narkive permalink

Esistono librerie che consentono il multitasking, ad esempio la mia libreria arduOS.

Questo dovrebbe funzionare:

  #include <arduos16.h> # include <arduos_core.h> # include <roundscheduler.h>SYS_enable_preemptive; // NON dimenticarlo !!! void setup () {auto sched = new SYS :: RoundScheduler (2); sched->add (&loop1); // quelle 2 sono funzioni. sched->add (&loop2); SYS :: start ();}  

Ma tieni presente che il multitasking effettivo può essere piuttosto complicato, con bug molto oscuri. (ma puoi trovarli).

Questo sistema operativo sembra più facile da usare rispetto al tuo sistema operativo arduino medio
#6
  0
lxx
2015-01-01 13:34:27 UTC
view on stackexchange narkive permalink

1.Usa due arduino e falli parlare tra loro tramite seriale o i2c. Probabilmente l'opzione più semplice (ma non la più economica, anche se puoi ottenere arduino clone da US $ 4).

2. Trova un sensore di luce che si aggiorni più velocemente. Hai provato un ldr (resistenza dipendente dalla luce) / fotocellula? Quindi potrebbe usare la lettura analogica.

Potresti anche passare dall'uso di arduino a c, ma questo è molto più lavoro e continuerai a riscontrare problemi simili.

Il passaggio a C non farebbe nulla, davvero, per questo problema.


Questa domanda e risposta è stata tradotta automaticamente dalla lingua inglese. Il contenuto originale è disponibile su stackexchange, che ringraziamo per la licenza cc by-sa 3.0 con cui è distribuito.
Loading...