Mehrere unabhängige LED-Muster

8

Ich habe ein Problem, das ich auf den ersten Blick (und als Neuling bei Arduino) eine perfekte Anwendung für ein Arduino war. Nachdem ich versucht habe und es nicht implementiert habe, bezweifle ich mich selbst!

Einfach - ich muss viele LEDs unabhängig voneinander steuern, von denen viele ihre eigenen individuellen Muster haben - zum Beispiel "5 Sekunden ein - 5 Sekunden aus". "Dauerblitze" - oder Sequenzen wie "2 Blitze, Pause, 1 Blitz". Ohne den Luxus von Fäden stecke ich natürlich ein wenig fest. Seien Sie schön zu hören, ob a) Arduino die beste Wahl ist und b) wenn ja - wie kann ich das machen!

Danke im Voraus :)

Nickos
quelle
1
Haben Sie sich Protothreads angesehen ? Es gibt einige Arduino-Bibliotheken, mit denen Sie Protothreads problemlos in Ihr Projekt integrieren können.
Sachleen

Antworten:

9

Mit einer Plattform wie Arduino ist es sicherlich möglich, mehrere Muster gleichzeitig zu verarbeiten, und es gibt eine Reihe von Möglichkeiten, wie Sie dies tun können.

Eine Methode, die ich in Betracht ziehen würde, ist das Schreiben von Funktionen, die jedes Muster effektiv mathematisch darstellen. Sie würden nur die Gesamtzeit übergeben, die bisher in Ihrem Programm vergangen ist, und es wird die entsprechende Aktion für diesen bestimmten Zeitpunkt ausführen. Es wird sofort danach zurückkehren (keine Verzögerungen oder irgendetwas).

Dazu müssen Sie zunächst wissen, wie lange ein einzelner Zyklus des Musters dauert. Sie können dann den Modulo-Operator verwenden, um herauszufinden, wie weit Sie durch den aktuellen Zyklus sind. Von dort aus müssen Sie lediglich einige ifBedingungen festlegen, um zu bestimmen, was zu einem bestimmten Zeitpunkt zu tun ist .

So könnte es für Ihr Muster "5 Sekunden ein, 5 Sekunden aus" aussehen:

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);
}

Zugegeben, ständig anzurufen, digitalWrite()wenn Sie es technisch nicht brauchen, ist nicht sehr effizient. Es sollte jedoch keinen Schaden anrichten und ist bei Bedarf recht einfach zu optimieren.

Um das obige Beispiel in einer Skizze zu verwenden, müssen Sie es nur aufrufen loop()und die Nummer übergeben, von der Sie erhalten millis(). z.B:

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

  pattern5on5off(totalTime);

  // call other patterns here...
}

Andere Muster sind komplexer, folgen jedoch demselben Prinzip. Sie müssten nur geeignete ifAnweisungen verwenden, um Ihre Logik auszudrücken.

Das Wichtigste ist, dass die Funktion einen bestimmten Zeitpunkt darstellt. Das Programm sollte niemals angehalten oder verzögert werden, da sonst die anderen Muster nicht ausgeführt werden können.

Bearbeiten: Timing im ersten Zyklus
Wie in den Kommentaren erwähnt, beginnt der allererste Zyklus an einem zufälligen Punkt. Dies liegt daran , das erste Mal , Sie rufen millis()in loop(), wird es nicht bei 0 beginnen (das Gerät bereits für kurze Zeit in Betrieb gewesen sein, bevor loop()wird aufgerufen). Bei Bedarf ist es jedoch leicht zu lösen.

Sie würden dies tun, indem Sie den totalTimeWert um den Wert versetzen, den Sie beim ersten Mal erhalten haben loop(). Zum Beispiel:

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..
}
Peter Bloomfield
quelle
Vielen Dank - macht vollkommen Sinn! Ive definitiv worden meinen Kopf gegen eine Wand mit dem falschen Ansatz hämmert ... :)
Nickos
1
Das Problem bei diesem %Ansatz ist, dass das Timing beim ersten Mal nicht korrekt ist, da es zunächst nur zufällig ist.
jfpoilpret
1
@jfpoilpret Das stimmt. Es ist jedoch leicht zu beheben, daher habe ich es meiner Antwort hinzugefügt. :)
Peter Bloomfield
Eine andere Möglichkeit wäre, anstatt milliseinmal in der Schleife zu laufen und ihren Wert als Parameter an jede LED-Funktion zu übergeben, jede Funktion als parameterlose zu haben und Millis in jeder auszuführen. Dies würde es jeder Funktion ermöglichen, einen genaueren Wert zu erhalten, der abhängig von der Zeit, die jede Funktion in der Schleife für die Ausführung benötigt, und den Anforderungen an die Timing-Korrektheit der Anwendung wichtig sein kann oder nicht.
Heltonbiker
4

Arduino ist eine gute Wahl für diese Aufgabe - einfach zu beginnen. Der Schlüssel ist, nicht blockierenden Code zu schreiben. Sie können sich das Beispiel von BlinkWithoutDelay ansehen.

Ich habe einen Vorschlag für Ihre Aufgabe gemacht:

// 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;
    }
  }
}
user2973
quelle
0

Ich weiß, dass der Beitrag alt ist, aber ich habe das Beispiel mit dem Array-basierten Ansatz überprüft und meiner Meinung nach:

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

ergibt immer die zugewiesene Größe (Anzahl der Elemente) des Arrays - in diesem Fall 10. Das Timing wird also erst neu gestartet, wenn Sie das "Ende" des Arrays mit undefinierten Elementen erreicht haben. Für LED "0":

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

Grüße Tommy

TommyL
quelle