Arduino 在使用 FastLED 时忽略串行中断

Arduino ignoring serial interrupts when using FastLED

我尝试了在 Internet 上找到的几种不同方法,但其中 none 似乎有效。此代码适用于情况 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);
  }
}

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

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

// 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 清理的工作代码。 (请注意,那里还有一些串行调试代码,因为我有更多的工作要做亮度等)

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

此外 - 您不能允许中断 AVR,或者我应该说它什么都不做。当发生这种情况时,我应该发出警告消息 - AVR/arduino 的 ISR 处理速度太慢,即使是时钟节拍 ISR 也足以中断写出 WS2812 数据(导致 FastLED 切断帧)所以我猛拉该代码来自 avr WS2812 asm 实现。 FastLED 支持的大多数 arm 和 esp 平台确实允许在写出每个 led 数据之间的小 window 期间发生中断处理——这得益于它们更高的时钟速度。

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