Answers:
在像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..
}
%
方法的问题在于,计时不会在第一次就正确,因为起初只是随机的。
millis
在循环中运行一次并将其值作为参数传递给每个led函数,而是使每个函数成为无参数函数,并在每个函数内部运行millis。这将允许每个函数获得更精确的值,这取决于循环中每个函数运行所花费的时间以及应用程序的时序正确性要求,这可能重要也可能不重要。
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;
}
}
}
我知道帖子很旧,但是我使用基于数组的方法检查了示例,并认为:
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>
汤米的问候