Несколько независимых светодиодных моделей

8

У меня есть проблема, которая на первый взгляд (и, будучи новичком в Arduino), я, тем не менее, была идеальным приложением для Arduino. Однако, пытаясь и не в состоянии осуществить это, я сомневаюсь в себе!

Проще говоря, мне нужно независимо управлять многими светодиодами, многие из которых будут иметь свои собственные индивидуальные схемы - например, «5 секунд включено - 5 секунд выключено». «непрерывные вспышки» - или последовательности, такие как «2 вспышки, пауза, 1 вспышка». Очевидно, без роскоши нитей я становлюсь немного отклеенным. Приятно слышать, если а) Arduino лучший выбор и б) если это так - как я могу это сделать!

Заранее спасибо :)

Nickos
источник
1
Вы изучали протопотоки ? Существует несколько библиотек Arduino, которые позволяют легко включать протопотоки в ваш проект.
сахлин

Ответы:

9

Обработка нескольких паттернов одновременно возможна с такой платформой, как Arduino, и вы можете сделать это несколькими способами.

Одним из методов, который я бы рассмотрел, является написание функций, которые эффективно представляют каждый шаблон математически. Вы просто передали бы его общее время, которое прошло в вашей программе, и оно выполнит соответствующее действие для этого конкретного момента времени. Он вернется сразу после этого (без задержек или чего-либо).

Чтобы сделать это, вам сначала нужно узнать, как долго длится один цикл паттерна. Затем вы можете использовать оператор по модулю, чтобы выяснить, как далеко вы прошли текущий цикл. Оттуда все, что вам нужно сделать, это иметь некоторые ifусловия, чтобы определить, что делать в любой момент времени.

Вот как это может выглядеть для вашей схемы «5 секунд включено, 5 секунд выключено»:

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

По общему признанию, постоянно звонить, digitalWrite()когда вам технически не нужно, не очень эффективно. Это не должно причинить никакого вреда, и его довольно легко оптимизировать при необходимости.

Чтобы использовать приведенный выше пример в наброске, вам нужно просто позвонить loop()и передать номер, с которого вы получили millis(); например:

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

  pattern5on5off(totalTime);

  // call other patterns here...
}

Другие шаблоны будут более сложными, но будут следовать тому же принципу. Вы бы просто использовали соответствующие ifвыражения, чтобы выразить свою логику.

Важно помнить, что функция представляет определенный момент времени. Он никогда не должен приостанавливать или задерживать программу, иначе это предотвратит запуск других шаблонов.

Изменить: время в первом цикле
Как отметил jfpoilpret в комментариях, самый первый цикл начнется в случайной точке. Это происходит потому , что первый раз , когда вы звоните millis()в loop(), он не запустится при 0 (устройство уже работает в течение короткого времени , прежде чем loop()будет вызвана). Это легко решить, хотя, если это необходимо.

Вы бы сделали это, сместив totalTimeзначение на то значение, которое вы получили в самый первый раз loop(). Например:

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..
}
Питер Блумфилд
источник
Большое спасибо - имеет смысл! Я определенно бился головой о стену с неправильным подходом ... :)
Никос
1
Проблема с этим %подходом заключается в том, что время не будет правильным с самого начала, поскольку сначала оно будет случайным.
jfpoilpret
1
@jfpoilpret Это правда. Это легко исправить, поэтому я добавил его в свой ответ. :)
Питер Блумфилд
Другим вариантом было бы вместо того, чтобы запускаться millisодин раз в цикле и передавать свое значение в качестве параметра каждой светодиодной функции, чтобы каждая функция была безпараметрической, и запускать миллис внутри каждой. Это позволило бы каждой функции получить более точное значение, которое может или не может быть важным в зависимости от того, сколько времени занимает выполнение каждой функции в цикле, а также от требований к правильности синхронизации приложения.
Хелтонбайкер
4

Arduino - прекрасный выбор для этой задачи, с которой легко начать. Ключ заключается в написании неблокирующего кода. Вы можете взглянуть на пример BlinkWithoutDelay.

Я сделал предложение для вашей задачи:

// 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
источник
0

Я знаю, что пост старый, но я проверил пример с использованием массива и по моему мнению:

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

всегда будет давать выделенный размер (количество элементов) массива - в этом случае 10. Таким образом, синхронизация не будет перезапущена, пока вы не достигнете «конца» массива, используя неопределенные элементы. Для светодиода "0":

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

Привет Томми

TommyL
источник