Plusieurs modèles de LED indépendants

8

J'ai un problème qui, à première vue (et étant nouveau sur Arduino), je pensais que c'était une application parfaite pour un Arduino. Cependant, après avoir essayé et échoué à le mettre en œuvre, je doute de moi-même!

Simplement - j'ai besoin de contrôler de nombreuses LED indépendamment, dont beaucoup auront leurs propres modèles individuels - par exemple "5 secondes allumées - 5 secondes éteintes". "flashs continus" - ou séquences telles que "2 flashs, pause, 1 flash". Évidemment, sans le luxe des fils, je deviens un peu décollé. Soyez génial d'entendre si a) Arduino est le meilleur choix et b) si c'est le cas - comment puis-je m'y prendre!

Merci d'avance :)

Nickos
la source
1
Avez-vous étudié les protothreads ? Il existe quelques bibliothèques Arduino qui vous permettent d'incorporer facilement des protothreads dans votre projet.
sachleen

Réponses:

9

La gestion de plusieurs modèles en même temps est certainement possible avec une plate-forme comme Arduino, et il existe plusieurs façons de procéder.

Une méthode que je considérerais est d'écrire des fonctions qui représentent efficacement chaque modèle mathématiquement. Vous devez simplement lui transmettre le temps total écoulé dans votre programme jusqu'à présent, et il fera l'action appropriée pour ce moment précis. Il reviendra immédiatement après (pas de retard ou quoi que ce soit).

Pour ce faire, vous devez d'abord savoir combien de temps dure un seul cycle du motif. Vous pouvez ensuite utiliser l'opérateur modulo pour déterminer dans quelle mesure vous êtes dans le cycle actuel. À partir de là, tout ce que vous devez faire est de disposer de certaines ifconditions pour déterminer quoi faire à un moment donné.

Voici à quoi cela pourrait ressembler pour votre modèle "5 secondes allumées, 5 secondes éteintes":

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

Certes, appeler constamment digitalWrite()lorsque vous n'en avez pas besoin techniquement n'est pas très efficace. Cependant, cela ne devrait pas causer de dommages et est assez facile à optimiser si nécessaire.

Pour utiliser l'exemple ci-dessus dans un croquis, il vous suffit de l'appeler loop()et de passer le numéro que vous obtenez millis(); par exemple:

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

  pattern5on5off(totalTime);

  // call other patterns here...
}

D'autres modèles seront plus complexes, mais suivront le même principe. Vous devez simplement utiliser des ifdéclarations appropriées pour exprimer votre logique.

La chose vitale à retenir est que la fonction représente un moment précis dans le temps. Il ne doit jamais interrompre ou retarder le programme, sinon il empêchera les autres modèles de s'exécuter.

Edit: Timing sur le premier cycle
Comme jfpoilpret l'a noté dans les commentaires, le tout premier cycle commencera à un point aléatoire. En effet , la première fois que vous appelez millis()dans loop(), il ne démarre pas à 0 (l'appareil aura déjà été en cours d' exécution pour un court laps de temps avant loop()est appelé). Il est cependant facile à résoudre si nécessaire.

Vous le feriez en compensant la totalTimevaleur par la valeur que vous avez obtenue la toute première fois loop(). Par exemple:

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
la source
Merci beaucoup - c'est parfaitement logique! Je me suis vraiment cogné la tête contre un mur avec une mauvaise approche ... :)
Nickos
1
Le problème avec l' %approche est que le timing ne sera pas correct la première fois, car il sera juste aléatoire au début.
jfpoilpret
1
@jfpoilpret C'est vrai. Il est cependant facile à corriger, donc je l'ai ajouté à ma réponse. :)
Peter Bloomfield
Une autre option serait, au lieu de s'exécuter millisune fois dans la boucle et de transmettre sa valeur en tant que paramètre à chaque fonction led, d'avoir chaque fonction sans paramètre et d'exécuter des millis à l'intérieur de chacune. Cela permettrait à chaque fonction d'obtenir une valeur plus précise, ce qui pourrait ou non être important en fonction du temps nécessaire à l'exécution de chaque fonction dans la boucle, ainsi que des exigences de correction de synchronisation de l'application.
heltonbiker du
4

Arduino est un bon choix pour la tâche - facile à démarrer. La clé est d'écrire du code non bloquant. Vous pouvez jeter un œil à l'exemple BlinkWithoutDelay.

J'ai fait une suggestion pour votre tâche:

// 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
la source
0

Je sais que le message est ancien, mais j'ai vérifié l'exemple avec l'approche basée sur les tableaux et à mon avis:

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

donnera toujours la taille allouée (nombre d'éléments) du tableau - dans ce cas 10. Ainsi, le chronométrage ne redémarrera pas jusqu'à ce que vous ayez atteint la "fin" du tableau, en utilisant des éléments non définis. Pour la LED "0":

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

Salutations Tommy

TommyL
la source