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 的平台,请随意忽略此评论(主要是将其放在此处,以便在良好搜索中偶然发现此问题的人知道发生了什么)。
我尝试了在 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 的平台,请随意忽略此评论(主要是将其放在此处,以便在良好搜索中偶然发现此问题的人知道发生了什么)。