【问题标题】:Interrupting loops中断循环
【发布时间】:2019-06-27 19:25:23
【问题描述】:

我正在开发一个 Arduino 照明项目,使用 rbg LED 来创建可自定义的颜色。我正在使用 IRremote 库来更改 LED 的“模式”。

这是我的程序:

#include <IRremote.h>

const int RECV_PIN = 7;
IRrecv irrecv(RECV_PIN);
decode_results results;
int redpin = 9;
int greenpin = 10;
int bluepin = 5;

void setup(){
  Serial.begin(9600);
  irrecv.enableIRIn();
  irrecv.blink13(true);
  pinMode(redpin, OUTPUT);
  pinMode(greenpin, OUTPUT);
  pinMode(bluepin, OUTPUT);
}

void loop(){
  if (irrecv.decode(&results)){
    Serial.println("Before it checks for signal");

    if (results.value == 0xFFE21D) { //'TITLE' button
      Serial.println("'TITLE' signal detected, before fade starts");

      //Fades through colors

      int i;

      //green to red
      for (i = 0; i < 255; i++) {
        analogWrite(redpin, i);
        analogWrite(greenpin, 255 - i);
        analogWrite(bluepin, 0);
        delay(1);
        Serial.println("Green to red");
      }

      //red to blue
      for (i = 0; i < 255; i++) {
        analogWrite(redpin, 255 - i);
        analogWrite(greenpin, 0);
        analogWrite(bluepin, i);
        delay(1);
        Serial.println("Red to blue");
      }

      //blue to green
      for (i = 0; i < 255; i++) {
        analogWrite(redpin, 0);
        analogWrite(greenpin, i);
        analogWrite(bluepin, 255 - i);
        delay(1);
        Serial.println("Blue to green");
      }
    }

    if (results.value == 0xFFD22D) { //'MENU' button
      Serial.println("'MENU' button detected");

      //LED red
      analogWrite(redpin, 255);
      analogWrite(greenpin, 0);
      analogWrite(bluepin, 0);
    }

    if (results.value == 0xFF52AD) { //'ON/OFF' button
      Serial.println("'STOP' button detected");

      //Stops
      analogWrite(redpin, 0);
      analogWrite(greenpin, 0);
      analogWrite(bluepin, 0);

      Serial.println("After LED stops");
    }

    Serial.println("After program");
    irrecv.resume();
  }
}

void loop() 中,我有三个if() 语句。第一个检查遥控器上的某个按钮按下,LED 从绿色变为红色,再变为蓝色变为绿色(这只执行一次,但对于另一个线程来说这是个问题)。

第二个if() 语句检查是否有不同的按钮按下,LED 变为红色。我计划有几个不同颜色的。

第三个if() 语句检查开/关按钮并关闭 LED。

我可以在这些之间切换。 问题是,一旦第一个 if() 语句执行并且 LED 淡出,我无法切换到其他任何一个语句,直到它结束。

我知道一旦第一个语句被执行,它在完成之前不会检查信号,但我想不出我是如何做到的。任何帮助表示赞赏!

【问题讨论】:

  • 我不确定你的问题到底是什么......但我怀疑答案可能是将你的代码拆分为subroutines。创建一个onOff() 函数。 doFade() 函数。等等。然后调用您需要响应特定response 值的任何函数(或函数组合)。
  • 我会将淡入/淡出代码放入非阻塞协同程序中。这些在 C 中很棘手,但可以完成。简而言之,您保留当前设置和目标设置的静态变量;在循环中检查按钮,根据需要更改目标值,然后调用协同程序执行单个淡入淡出步骤并返回循环。
  • @paulsm4 我来自 JS,这就是我所习惯的。我创建一个函数并在需要时调用它。 C对我来说有点学习,从来没有想到过。我会调查的。

标签: c arduino


【解决方案1】:

您似乎正在尝试实现一个简单的状态机。为此,您需要切换循环 / if 语句。在伪代码中:

int mode; // 0: green, 1: red and so on
while(true) {
    // check button presses
    if(buttonpress) {
        mode = mode+1;
    }
    if(mode==1)
        make_leds_more_green();
    else if(mode==2)
        make_leds_more_red();
    //...
    delay(1);
}

【讨论】:

  • 是的 - 正是我想说的那种事情:a)“动作”应该从“main()”中移出并放入单独的 C 函数中。 b) “while()”循环读取输入并调用适当的动作(或动作)。 c)我认为“response.value”几乎WAS“状态”......但你是对的,情况不一定如此。
  • 我以前不知道状态机是什么,这非常有帮助。谢谢!
【解决方案2】:

Tstenner 的状态机是一种方法。我将在下面概述另一个,但基本思想是,当您以单个步骤淡入/淡出 LED 时,您需要循环继续。这是我的协程方法:

int pins[3] = { redpin, greenpin, bluepin };
int current[3] = { 0, 0, 0 };
int target[3] = { 0, 0, 0 };

led_tick() {
  for (int i = 0; i < 3; i += 1) {
    if (current[i] == target[i]) continue;
    if (current[i] < target[i]) {
      current[i] += 1;
    } else {
      current[i] -= 1;
    }
    analogWrite(pins[i], current[i]);
  }
}

loop() {
  // handle buttons, change target values
  led_tick();
  delay(1);  // making this non-blocking would be even better

}

【讨论】:

  • 拥有一个处理褪色的函数肯定比我的方法更优雅。我更专注于在颜色变化期间处理按钮按下,但结合我们的答案应该可以回答这个问题。
  • 是的,我喜欢用于很多嵌入式内容的状态机。
【解决方案3】:

你可以试试手工制作的无阻塞

  1. 删除for
  2. 删除delay
  3. 使用millis() 和句点
#define DELAY  5000

int step;

void greenToRed() {
    // Non blocking, only check if the waiting period passed
    if(changeToRed && millis() > time_1 + DELAY){
        // Update the time
        time_1 = millis();
        // Update the step
        step -= 1;

        analogWrite(redpin, 255 - step);
        analogWrite(greenpin, step);
        analogWrite(bluepin, 0);
        Serial.println("Green to red");

        // Finish condition
        if(step =< 0) {
            changeToRed = 0;
        }
    }
}

void loop() {
    if (results.value == 0xFFE21D) {
        changeToRed = 1;
        step = 255;
    }
    greenToRed();
}

【讨论】:

  • 这对我来说似乎是最容易理解的解决方案,但changeToRed 是在哪里定义的?
  • @Joe Pigott 只需将 loop 方法替换为 greenToRed 或在 loop 之前添加方法声明 void greenToRed();。我已经编辑了帖子
猜你喜欢
  • 1970-01-01
  • 2011-08-30
  • 2013-08-13
  • 2013-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多