Vários padrões de LED independentes

8

Eu tenho um problema que, a princípio, (e sendo novo no Arduino), eu era um aplicativo perfeito para um Arduino. No entanto, depois de tentar e deixar de implementá-lo, estou duvidando de mim mesmo!

Simplesmente - preciso controlar muitos LEDs de forma independente, muitos dos quais terão seus próprios padrões individuais - por exemplo, "5 segundos ligado - 5 segundos desligado". "flashes contínuos" - ou sequências como "2 flashes, pausa, 1 flash". Obviamente, sem o luxo dos fios, estou me tornando um pouco desconectada. Seja ótimo em saber se a) o Arduino é a melhor escolha eb) se é - como posso fazer isso!

Desde já, obrigado :)

Nickos
fonte
11
Você já olhou para protothreads ? Existem algumas bibliotecas do Arduino que permitem incorporar facilmente protothreads em seu projeto.
sachleen

Respostas:

9

O manuseio de vários padrões ao mesmo tempo é certamente possível com uma plataforma como o Arduino, e há várias maneiras de você fazer isso.

Um método que eu consideraria é escrever funções que efetivamente representam cada padrão matematicamente. Você passaria o tempo total decorrido no seu programa até agora e executará a ação apropriada para esse momento específico. Ele retornará imediatamente depois (sem atrasos ou qualquer coisa).

Para fazer isso, primeiro você precisa saber quanto tempo dura um único ciclo do padrão. Você pode usar o operador módulo para descobrir até que ponto você está no ciclo atual. A partir daí, tudo o que você precisa fazer é ter algumas ifcondições para determinar o que fazer a qualquer momento.

Veja como pode ser o seu padrão "5 segundos ligado e 5 segundos desligado":

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

É verdade que telefonar constantemente digitalWrite()quando você não precisa tecnicamente não é muito eficiente. Porém, não deve causar nenhum dano e é bastante fácil de otimizar, se necessário.

Para usar o exemplo acima em um esboço, você só precisa chamá-lo loop()e passar o número do qual obtém millis(); por exemplo:

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

  pattern5on5off(totalTime);

  // call other patterns here...
}

Outros padrões serão mais complexos, mas seguem o mesmo princípio. Você apenas usaria ifdeclarações apropriadas para expressar sua lógica.

O essencial é lembrar que a função representa um momento específico no tempo. Ele nunca deve pausar ou atrasar o programa, caso contrário, impedirá a execução de outros padrões.

Edit: Tempo no primeiro ciclo
Como jfpoilpret observou nos comentários, o primeiro ciclo começará em um ponto aleatório. Isso ocorre porque a primeira vez que você chamar millis()em loop(), ele não vai começar em 0 (o dispositivo já terá sido executado por um curto período de tempo antes loop()é chamado). É fácil resolver, se necessário.

Você faria isso deslocando o totalTimevalor pelo valor que você obteve na primeira vez loop(). Por exemplo:

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
fonte
Muito obrigado - faz todo o sentido! Ive definitivamente sido batendo a cabeça contra uma parede com a abordagem errada ... :)
Nickos
11
O problema com a %abordagem é que o momento não será correto na primeira vez, pois será apenas aleatório no início.
Jfpoilpret 11/07/2014
11
@jfpoilpret Isso é verdade. É fácil de corrigir, então eu adicionei à minha resposta. :)
Peter Bloomfield
Outra opção seria, em vez de executar millisuma vez no loop e passar seu valor como parâmetro para todas as funções de led, ter cada função como uma sem parâmetro e executar millis dentro de cada uma. Isso permitiria que cada função obtivesse um valor mais preciso, que pode ou não ser importante, dependendo de quanto tempo cada função no loop leva para ser executada e também dos requisitos de correção de tempo do aplicativo.
Heltonbiker 05/07/2015
4

O Arduino é uma ótima opção para a tarefa - fácil de começar. A chave é escrever código sem bloqueio. Você pode dar uma olhada no exemplo BlinkWithoutDelay.

Fiz uma sugestão para sua tarefa:

// 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
fonte
0

Eu sei que o post é antigo, mas verifiquei o exemplo com a abordagem baseada em array e, na minha opinião:

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

sempre produzirá o tamanho alocado (número de elementos) da matriz - neste caso, 10. Portanto, o tempo não será reiniciado até que você atinja o "final" da matriz, usando elementos indefinidos. Para o LED "0":

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

Saudações Tommy

TommyL
fonte