【问题标题】:Arduino ignoring serial interrupts when using FastLEDArduino 在使用 FastLED 时忽略串行中断
【发布时间】:2018-07-10 16:03:12
【问题描述】:

我尝试了几种在互联网上找到的不同方法,但似乎都不起作用。此代码适用于案例 0-2,但当它进入彩虹追逐循环的案例 3 时,按下按钮不会中断循环并向前移动计数器。我假设,像往常一样,我错过了一些愚蠢的东西,非常感谢。

#define FASTLED_ALLOW_INTERRUPTS 1
#define FASTLED_INTERRUPT_RETRY_COUNT 1
#include <FastLED.h>

#define AnalogIn A0
#define SwIn 2
#define LED_Out 12
#define NUM_LEDS 5
int pushCounterz = 0;
volatile int buttonState;  // Set volatile for interrupt DO NOT SHAKE!
int lastButtonState;

CRGB leds[NUM_LEDS];

void setup() {
  // put your setup code here, to run once:
  FastLED.setMaxRefreshRate(250);
  FastLED.addLeds<WS2812, LED_Out, GRB>(leds, NUM_LEDS);
  pinMode(SwIn, INPUT);
  pinMode(LED_Out, OUTPUT);

  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CRGB ( 255, 0, 255 );  
  }
  FastLED.show();
  delay(120);
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CRGB ( 0, 0, 0 );  
  }

  FastLED.show();
  Serial.begin(115200);
  Serial.println(pushCounterz);
  lastButtonState = digitalRead(SwIn); // Set the button state to the startup state 

  attachInterrupt((SwIn-2), button_ISR, CHANGE);  // Set SwIn button as an interrupt pin  // Change to Low???

}

void loop() {
  if (pushCounterz != 3) {
    FastLED.show();
  }
Serial.println(pushCounterz);
delay(120);
}

void button_ISR () {
    buttonState = digitalRead(SwIn);
    digitalWrite(13, buttonState);
  if (buttonState == LOW && buttonState != lastButtonState) {
    if (pushCounterz > 3) {
      //Serial.println("Reset to 0: ");
      pushCounterz = 0;
    } else {
      pushCounterz = pushCounterz + 1;
      //Serial.println("Incerment");
    }
    //Serial.println(pushCounterz);

      switch (pushCounterz) {
      case 0:
        for (int i = 0; i < NUM_LEDS; i++) {
          leds[i] = CRGB (255, 0, 0);
        }
        break;
      case 1:
        for (int i = 0; i < NUM_LEDS; i++) {
          leds[i] = CRGB ( 0, 255, 0);
         }
         break;
      case 2:
        for (int i = 0; i < NUM_LEDS; i++) {
           leds[i] = CRGB ( 0, 0, 255);
         }
        break;
      case 3:
        theaterChaseRainbow(1,50);
        break;
      default:
       for (int i = 0; i < NUM_LEDS; i++) {
         leds[i] = CRGB ( 0, 0, 0);
       }
       break;
      }
  }

lastButtonState = buttonState;
}

// Theater-style crawling lights with rainbow effect
void theaterChaseRainbow(int cycles, int speed) { // TODO direction, duration
  for (int j = 0; j < 256 * cycles; j++) {   // cycle all 256 colors in the wheel
    for (int q = 0; q < 3; q++) {
      for (int i = 0; i < NUM_LEDS; i = i + 3) {
        int pos = i + q;
        leds[pos] = Wheel( (i + j) % 255);  //turn every third pixel on
      }
      FastLED.show();

      delay(speed);

      for (int i = 0; i < NUM_LEDS; i = i + 3) {
        leds[i + q] = CRGB::Black; //turn every third pixel off
      }
    }
  }
}

CRGB Wheel(byte WheelPos) {
  if (WheelPos < 85) {
    return CRGB(WheelPos * 3, 255 - WheelPos * 3, 0);
  }
  else if (WheelPos < 170) {
    WheelPos -= 85;
    return CRGB(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  else {
    WheelPos -= 170;
    return CRGB(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}

【问题讨论】:

    标签: arduino irq neopixel fastled


    【解决方案1】:

    你的问题不是按钮没有改变值,而是你的代码没有退出点,如果它改变了;该按钮将更改值,但theaterChaseRainbow 中没有任何内容告诉它停止。

    如果按钮状态发生变化,只需在方法中添加一个检查即可返回:

    // Theater-style crawling lights with rainbow effect
    void theaterChaseRainbow(int cycles, int speed) { // TODO direction, duration
      for (int j = 0; j < 256 * cycles; j++) {   // cycle all 256 colors in the wheel
        for (int q = 0; q < 3; q++) {
          for (int i = 0; i < NUM_LEDS; i = i + 3) {
            int pos = i + q;
            leds[pos] = Wheel( (i + j) % 255);  //turn every third pixel on
          }
          FastLED.show();
          if (pushCounterz != 3) return; //ADDED THIS HERE*****    
    
          delay(speed);
    
          for (int i = 0; i < NUM_LEDS; i = i + 3) {
            leds[i + q] = CRGB::Black; //turn every third pixel off
          }
        }
      }
    }
    

    此外,我建议简化您的 ISR,只增加按钮而不让它处理程序的逻辑。这应该包含在loop 方法中或从loop 方法中调用。这应该使代码更清晰,更少混乱,因为 ISR 的工作只是调整按钮计数器的值,而循环的工作是处理程序当前所处的状态。

    【讨论】:

    • 你是一个绅士和一个学者。现在我必须回去修复我的去抖(或找到我该死的去抖开关)。
    • 确实,最小化 ISR 是这里最重要的部分。如果我没记错的话,在 ISR 中不能调用其他 ISR,这可能会导致串行、延迟、计时器等问题。
    • 很好的建议。它目前行为不端(以某种方式在增量上崩溃)所以我会尝试。我也有我称之为超支的情况,不确定正确的术语,因为我对此很陌生,某处抬高了我的计数器,使其不是 0-4。用于智能内存管理或显式(我开始使用机器码 int、jmp、mov 等对微控制器进行编程)
    【解决方案2】:

    另外——你不能在 AVR 上允许中断,或者我应该说它什么都不做。发生这种情况时我应该输入一条警告消息 - AVR/arduino 的 ISR 处理速度非常慢,以至于即使时钟滴答 ISR 也足以中断写出 WS2812 数据(导致 FastLED 切断帧)所以我把那个代码拉出来了avr WS2812 asm 实现。 FastLED 支持的大多数 arm 和 esp 平台确实允许在写出每个 LED 数据之间的小窗口期间发生中断处理 - 这得益于它们更高的时钟速度。

    如果您使用的是基于 ARM 或 ESP 的平台,请随意忽略此评论(主要是把它放在这里,以便在良好搜索中偶然发现这个问题的人知道发生了什么)。

    【讨论】:

    • 所以我定义的允许中断没有注意到 Arduino duo?
    • 我有一个 FastLED 分支,它允许在 AVR 上中断而不会弄乱像素数据。权衡是每个像素需要额外的 48 个时钟 - 但在 16MHz 时这仅需要 3 微秒(因此,将像素推出需要 10% 的时间 - 100 个像素需要 3.3 毫秒而不是 3 毫秒)。大多数人不需要能够快速响应的中断——但我确实需要。 github.com/ben-xo/FastLED
    • 这个fork解决了我的问题,非常感谢您的分享。
    【解决方案3】:

    作为参考,带有 ISR 清理的工作代码。 (请注意,其中还有一些串行调试代码,因为我还有更多的工作要做亮度等)

    #define FASTLED_ALLOW_INTERRUPTS 1
    #define FASTLED_INTERRUPT_RETRY_COUNT 1
    #include <FastLED.h>
    
    #define AnalogIn A0
    #define SwIn 2
    #define LED_Out 12
    #define NUM_LEDS 5
    int pushCounterz = 4; // 4 = off
    volatile int buttonState;  // Set volatile for interrupt DO NOT SHAKE!
    int lastButtonState;
    
    CRGB leds[NUM_LEDS];
    
    void setup() {
      // put your setup code here, to run once:
      FastLED.setMaxRefreshRate(250);
      FastLED.addLeds<WS2812, LED_Out, GRB>(leds, NUM_LEDS);
      pinMode(SwIn, INPUT);
      pinMode(LED_Out, OUTPUT);
    
      for (int i = 0; i < NUM_LEDS; i++) {
        leds[i] = CRGB ( 255, 0, 255 );  
      }
      FastLED.show();
      delay(120);
      for (int i = 0; i < NUM_LEDS; i++) {
        leds[i] = CRGB ( 0, 0, 0 );  
      }
    
      FastLED.show();
      Serial.begin(19200);
      Serial.println(pushCounterz);
      lastButtonState = digitalRead(SwIn); // Set the button state to the startup state 
    
      attachInterrupt((SwIn-2), button_ISR, LOW);  // Set SwIn button as an interrupt pin  // Change to Low???
    
    }
    
    void loop() {
    //  if (pushCounterz != 3) {
        //FastLED.show();
        //Serial.println(pushCounterz);
    //  }
    
    //delay(20);
    switch (pushCounterz) {
      case 0:
        for (int i = 0; i < NUM_LEDS; i++) {
          leds[i] = CRGB (255, 0, 0);
        }
        FastLED.show();
        break;
      case 1:
        for (int i = 0; i < NUM_LEDS; i++) {
          leds[i] = CRGB ( 0, 255, 0);
        }
        FastLED.show();
        break;
      case 2:
        for (int i = 0; i < NUM_LEDS; i++) {
          leds[i] = CRGB ( 0, 0, 255);
        }
        FastLED.show();
        break;
      case 3:
        theaterChaseRainbow(1,50);
        break;
      default:
        for (int i = 0; i < NUM_LEDS; i++) {
          leds[i] = CRGB ( 0, 0, 0);
        }
        FastLED.show();
        break;
        }
    }
    
    void button_ISR () {
        buttonState = digitalRead(SwIn);
        //digitalWrite(13, buttonState);
      if (buttonState == LOW && buttonState != lastButtonState) {
        if (pushCounterz > 3 || pushCounterz < 0) {
          Serial.println("Reset to 0: ");
          pushCounterz = 0;
        } else {
          pushCounterz = pushCounterz + 1;
          Serial.println("Incerment");
        }
        Serial.println(pushCounterz);
      }
    lastButtonState = buttonState;
    }
    
    // Theater-style crawling lights with rainbow effect
    void theaterChaseRainbow(int cycles, int speed) { // TODO direction, duration
      for (int j = 0; j < 256 * cycles; j++) {   // cycle all 256 colors in the wheel
        for (int q = 0; q < 3; q++) {
          for (int i = 0; i < NUM_LEDS; i = i + 3) {
            int pos = i + q;
            leds[pos] = Wheel( (i + j) % 255);  //turn every third pixel on
          }
          FastLED.show();
          if (pushCounterz != 3) return;
    
          delay(speed);
    
          for (int i = 0; i < NUM_LEDS; i = i + 3) {
            leds[i + q] = CRGB::Black; //turn every third pixel off
          }
        }
      }
    }
    
    CRGB Wheel(byte WheelPos) {
      if (WheelPos < 85) {
        return CRGB(WheelPos * 3, 255 - WheelPos * 3, 0);
      }
      else if (WheelPos < 170) {
        WheelPos -= 85;
        return CRGB(255 - WheelPos * 3, 0, WheelPos * 3);
      }
      else {
        WheelPos -= 170;
        return CRGB(0, WheelPos * 3, 255 - WheelPos * 3);
      }
    }
    

    【讨论】:

    • 那么,现在一切正常吗,还是中断问题仍然存在? (见 rDg 的回答)。
    • 这段代码运行良好。从那以后,我添加了 2 个用于(现在褪色)速度和亮度的类似物,调整了其他一些东西,并且将开始构建我的激光水晶展示架。我在上面询问了他,看看我定义的那些常量是否对我的 uno 有任何作用
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多