2

我尝试了在互联网上找到的几种不同的方法,但它们似乎都不起作用。此代码适用于案例 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);
  }
}
4

3 回答 3

2

您的问题不是按钮没有更改值,而是您的代码没有退出点;该按钮将更改值,但没有任何内容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 的工作只是调整按钮计数器的值,而循环的工作是处理程序当前所处的状态。

于 2018-07-10T16:12:24.293 回答
1

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

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

于 2018-07-10T19:57:41.720 回答
0

作为参考,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);
  }
}
于 2018-07-10T18:00:57.943 回答