多个独立的LED模式


8

我有一个问题,乍一想(是Arduino的新手),我虽然是Arduino的完美应用程序。但是,在尝试并未能实施之后,我怀疑自己!

简而言之-我需要独立控制许多LED,其中许多LED都有自己的样式-例如“ 5秒钟打开-5秒钟关闭”。“连续闪烁”-或诸如“ 2次闪烁,暂停,1次闪烁”之类的序列。显然,如果没有线程的奢侈,我会变得有些困惑。非常高兴听到a)Arduino是最佳选择,b)如果是-我该怎么做!

提前致谢 :)


1
您是否研究过原型线程?有两个Arduino库,可让您轻松地在项目中合并原型线程。
sachleen 2014年

Answers:


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..
}

非常感谢-非常有道理!我肯定用错误的方法把我的头撞在墙上... :)
Nickos

1
这种%方法的问题在于,计时不会在第一次就正确,因为起初只是随机的。
jfpoilpret 2014年

1
@jfpoilpret是的。虽然很容易修复,所以我已将其添加到答案中。:)
彼得·布鲁姆菲尔德

另一种选择是,不是millis在循环中运行一次并将其值作为参数传递给每个led函数,而是使每个函数成为无参数函数,并在每个函数内部运行millis。这将允许每个函数获得更精确的值,这取决于循环中每个函数运行所花费的时间以及应用程序的时序正确性要求,这可能重要也可能不重要。
heltonbiker

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

0

我知道帖子很旧,但是我使用基于数组的方法检查了示例,并认为:

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

将始终产生分配的数组大小(元素数)-在这种情况下为10。因此,直到使用未定义的元素到达数组的“末尾”,计时才会重新开始。对于LED“ 0”:

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

汤米的问候

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.