Più modelli di LED indipendenti


8

Ho un problema, che all'inizio (ed essendo nuovo ad Arduino) pensavo fosse un'applicazione perfetta per un Arduino. Tuttavia, dopo aver provato e non averlo implementato, dubito di me stesso!

Semplicemente: ho bisogno di controllare molti LED in modo indipendente, molti dei quali avranno i loro modelli individuali, ad esempio "5 secondi attivi - 5 secondi spenti". "lampeggi continui" - o sequenze come "2 lampeggi, pausa, 1 lampeggio". Ovviamente senza il lusso dei fili sto diventando un po 'staccato. Sii fantastico per sapere se a) Arduino è la scelta migliore eb) se lo è - come posso procedere!

Grazie in anticipo :)


1
Hai guardato le protothreads ? Esistono un paio di librerie di Arduino che ti consentono di incorporare facilmente i prototipi nel tuo progetto.
sachleen,

Risposte:


9

Gestire più pattern contemporaneamente è certamente possibile con una piattaforma come Arduino e ci sono diversi modi in cui puoi farlo.

Un metodo che prenderei in considerazione è la scrittura di funzioni che rappresentano efficacemente ogni modello matematicamente. Lo passeresti solo per il tempo totale trascorso finora nel tuo programma e farà l'azione appropriata per quel momento specifico. Tornerà immediatamente dopo (senza ritardi o altro).

Per fare ciò, devi prima sapere quanto dura un singolo ciclo del modello. È quindi possibile utilizzare l'operatore modulo per capire fino a che punto del ciclo corrente ci si trova. Da lì, tutto ciò che devi fare è avere alcune ifcondizioni per determinare cosa fare in un dato momento.

Ecco come potrebbe apparire il tuo modello "5 secondi acceso, 5 secondi spento":

function pattern5on5off(unsigned long totalTime)
{
  // Calculate how far through the current cycle we are
  const unsigned long cycleTime = totalTime % 10000;

  // If we're in the first 5 seconds of the cycle then turn the light on.
  // Otherwise, turn it off.
  if (cycleTime < 5000)
    digitalWrite(3, HIGH);
  else
    digitalWrite(3, LOW);
}

Certo, chiamare costantemente digitalWrite()quando tecnicamente non è necessario non è molto efficiente. Tuttavia, non dovrebbe causare alcun danno ed è abbastanza facile da ottimizzare se necessario.

Per usare l'esempio sopra in uno schizzo, devi solo chiamarlo loop()e passare il numero da cui ottieni millis(); per esempio:

void loop()
{
  const unsigned long totalTime = millis();

  pattern5on5off(totalTime);

  // call other patterns here...
}

Altri schemi saranno più complessi, ma seguiranno lo stesso principio. Dovresti semplicemente usare le ifdichiarazioni appropriate per esprimere la tua logica.

La cosa vitale da ricordare è che la funzione rappresenta un momento specifico nel tempo. Non dovrebbe mai mettere in pausa o ritardare il programma, altrimenti impedirà l'esecuzione degli altri pattern.

Modifica: temporizzazione sul primo ciclo
Come notato da jfpoilpret nei commenti, il primo ciclo inizierà in un punto casuale. Questo perché la prima volta che si chiama millis()in loop(), non si avvia a 0 (il dispositivo sarà già stato in esecuzione per un breve periodo prima loop()viene chiamato). È facile da risolvere, se necessario.

Lo faresti compensando il totalTimevalore di qualunque valore tu abbia ottenuto la prima volta loop(). Per esempio:

unsigned long g_startTime = 0;

void loop()
{
  unsigned long totalTime = 0;

  if (g_startTime == 0) {
    // This is the first cycle.
    // Store the start time so we can compensate later.
    g_startTime = millis();

  } else {
    // This is not the first cycle.
    // Compensate for the start time.
    totalTime = millis() - g_startTime;
  }

  pattern5on5off(totalTime);
  // etc..
}

Grazie mille - ha perfettamente senso! Ho sicuramente sbattuto la testa contro un muro con l'approccio sbagliato ... :)
Nickos,

1
Il problema con l' %approccio è che i tempi non saranno corretti la prima volta, poiché all'inizio saranno solo casuali.
jfpoilpret l'

1
@jfpoilpret È vero. È facile da risolvere, quindi l'ho aggiunto alla mia risposta. :)
Peter Bloomfield l'

Un'altra opzione sarebbe, invece di eseguire millisuna volta nel loop e passare il suo valore come parametro a ogni funzione led, avere ciascuna funzione come senza parametri ed eseguire millis all'interno di ciascuna. Ciò consentirebbe a ciascuna funzione di ottenere un valore più preciso, che potrebbe essere o non essere importante in base al tempo impiegato da ciascuna funzione nel ciclo e ai requisiti di correttezza temporale dell'applicazione.
heltonbiker,

4

Arduino è un'ottima scelta per l'attività: è facile iniziare. La chiave è scrivere codice non bloccante. Puoi dare un'occhiata all'esempio BlinkWithoutDelay.

Ho fatto un suggerimento per il tuo compito:

// Timing suquences for the LED's in milliseconds
// First value is on time, second value is off time,
// third value on time and so on (up to 10 values)
// One row for each LED
unsigned int led_timing[][10] = {
  {5000, 5000},
  {100, 1000},
  {100, 100, 100, 1500, 100, 1500}
};

// The pins the LED's are connected to
byte led_pins[] = {11, 12, 13};

// Keep track of timing sequence
// Array size taken from led_pins
unsigned long last_change[sizeof(led_pins)/sizeof(led_pins[0])];
byte timing_i[sizeof(led_pins)/sizeof(led_pins[0])];

void setup()
{
  // Initialize LED's as output
  for (byte i = 0; i < sizeof(led_pins)/sizeof(led_pins[0]); i++)
  {
    pinMode(led_pins[i], OUTPUT);
    digitalWrite(led_pins[i], HIGH);
  }
}


void loop()
{
  // Current timestamp
  unsigned long now = millis();

  // Keep track of sequence for each LED
  for (byte i = 0; i < sizeof(led_pins)/sizeof(led_pins[0]); i++)
  {
    if (now - last_change[i] >= led_timing[i][timing_i[i]])
    {
      digitalWrite(led_pins[i], !digitalRead(led_pins[i]));
      timing_i[i]++;

      // Start over at the end of timing sequence
      timing_i[i] %= sizeof(led_timing[i])/sizeof(led_timing[i][0]);

      last_change[i] = now;
    }
  }
}

0

So che il post è vecchio, ma ho controllato l'esempio con l'approccio basato su array e secondo me:

sizeof(led_timing[i])/sizeof(led_timing[i][0])

restituirà sempre la dimensione allocata (numero di elementi) dell'array - in questo caso 10. Quindi il timing non verrà riavviato fino a quando non si raggiunge la "fine" dell'array, utilizzando elementi non definiti. Per LED "0":

int led_timing[0][10]:
5000,5000, <undefined>, <undefined>, <undefined>, <undefined>, <undefined>, <undefined>, <undefined>, <undefined>

Saluti Tommy

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.