Interromper Sketch antes do termino de uma função.

Olá Amigos.

Iniciei a poucos dias o estudo de programação e eletrônica em Arduino, até o momento considero que já progredi bastante. :smiley:
Estou trabalhando em uma fita de Led Digital endereçavel, usando a biblioteca “Adafruit_NeoPixel” que ajuda em muito em efeitos para a fita digital e controlando-a por app no celular por Bluetooth.

Porem estou com problemas em fazer a mudança de efeito, onde só muda após o termino total do ciclo do efeito em execução.

Exemplo: Mando o comando para “efeito 1”, logo inicia a execução do “efeito 1”, porem se eu mandar o comando para “efeito 2”, ele só inicia após terminar o ciclo do “efeito 1”.

Gostaria de poder interromper o “efeito 1”, assim que eu mandar o pedido para “efeito 2”, e não ter que aguardar todo o ciclo terminar.

Já tentei utilizar, while, break, digitalWrite(para desligar o pin 2), millis, attachInterrupt, Blink Without Delay, e não consegui, não sei se fiz de forma errada ou se realmente essas opções não se encaixam para a minha necessidade. :confused:

Alguém teriam alguma ideia ou solução ?

Utilizo Arduino Uno R3
Pin 0 = TX do modulo Bluetooth HC-06
Pin 1 = RX do modulo Bluetooth HC-06
Pin 2 = Led Digital

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif

#define PIN 2


char buf;


// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(30, PIN, NEO_GRB + NEO_KHZ800);

// IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across
// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input
// and minimize distance between Arduino and first pixel.  Avoid connecting
// on a live circuit...if you must, connect GND first.

void setup() {

  strip.begin();
  strip.show(); // Initialize all pixels to 'off'

  Serial.begin(9600);
  
}

void loop() {

  while(Serial.available() > 0)
  {
    buf = Serial.read();
    if (buf == '1')
    {
      rainbow(50);
      Serial.println("Rainbow !");
    }
    if (buf == '2')
    {
      rainbowCycle(20);
      Serial.println("Rainbow Cycle !");
    }
    if (buf == '3')
    {
      colorWipe(strip.Color(255, 0, 0), 50);
      Serial.println("Full Color Red !");
    }

  }
}



void rainbow(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256*2; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
    delay(wait);
  }
}


void rainbowCycle(uint8_t wait) {
  uint16_t i, j;

  for(j=0; j<256*2; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
    delay(wait);
  }
}


void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    strip.show();
    delay(wait);
  }
}


// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

O problema é que está a utilizar a função delay. Dê uma olhadela ao exemplo "Blink Without Delay", nele pode aprender como pode fazer uma espera sem recorrer à função delay.

Ola Luis

Eu li sobre “Blink Without Delay”, tentei algumas opções usando millis, porem com ou sem delay ou millis acontece o mesmo problema, só muda de efeito assim que termina todo o ciclo,

Veja o código abaixo, esta sem nenhum delay ou millis, porem aumentei de 2 ciclos para 200 nos efeitos “rainbow” e “rainbowCycle”, para poder dar tempo de mudar antes do termino.
““for(j=0; j<256*200; j++)””

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif

#define PIN 2


char buf;


// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(30, PIN, NEO_GRB + NEO_KHZ800);

// IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across
// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input
// and minimize distance between Arduino and first pixel.  Avoid connecting
// on a live circuit...if you must, connect GND first.

void setup() {

  strip.begin();
  strip.show(); // Initialize all pixels to 'off'

  Serial.begin(9600);
  
}

void loop() {

  while(Serial.available() > 0)
  {
    buf = Serial.read();
    if (buf == '1')
    {
      rainbow();
      Serial.println("Rainbow !");
    }
    if (buf == '2')
    {
      rainbowCycle();
      Serial.println("Rainbow Cycle !");
    }
    if (buf == '3')
    {
      colorWipe(strip.Color(255, 0, 0));
      Serial.println("Full Color Red !");
    }

  }
}



void rainbow() {
  uint16_t i, j;

  for(j=0; j<256*200; j++) {
    for(i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
  }
}


void rainbowCycle() {
  uint16_t i, j;

  for(j=0; j<256*200; j++) { // 5 cycles of all colors on wheel
    for(i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
  }
}


void colorWipe(uint32_t c) {
  for(uint16_t i=0; i<strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    strip.show();
  }
}


// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

Assim acredito que o problema esteja nessa função em si. :confused:

Desde já agradeço a atenção.

Isso é o mesmo que ter delays. Deve utilizar a função millis para fazer as paragens.

Esse ciclo deve demorar algum tempo a correr, não?

Podes sempre trocar os for(;;) por uma lógica em que o loop executa a vez do ciclo for. Desta forma o código corre todo num bloco central em vez de saltar para funções que dificultam a passagem do estado do sistema.

Luis

Troquei todo os delays do código para usar millis, porem um dos delays se eu tiro o efeito fica muito rápido que não da pra ver as corres passando, fica tão rápido que todos leds piscam ao invés do efeito desejado.
A questão de controlar pelo app do celular, removi para facilitar nos testes (ficar desligando o Bluetooth toda hora para passar o codigo é muito ruim), coloquei para a mudança/passagem de efeitos por Botão.

   #include <Adafruit_NeoPixel.h>
   #define PIN 2
   Adafruit_NeoPixel strip = Adafruit_NeoPixel(10, PIN, NEO_GRB + NEO_KHZ800);
   const int buttonPin = 7;
       
   // Variables will change:
   int buttonState;
   int lastButtonState = LOW;
   long lastDebounceTime = 0;
   long debounceDelay = 50;
   long previousMillis;
   
   int neoPixel_j = 0;
   
   int nPatterns = 4;
   int lightPattern = 1;
   
//----------------------------------------------------------------------------------------------

   void setup() {
   strip.begin();
   strip.show();                // initialize all pixels to 'off'  
   pinMode(buttonPin, INPUT);
   
}

//=============================================================================================

 void loop() {
 
 int reading = digitalRead(buttonPin);
 if (reading != lastButtonState) {
   lastDebounceTime = millis();
 } 
 
 if ((millis() - lastDebounceTime) > debounceDelay) {
   if (reading != buttonState) {
     buttonState = reading;
     if (buttonState == HIGH) {        
       lightPattern = (lightPattern + 1) % (nPatterns + 1); //include numOfPrograms + 1, since there is an off state
     }
   }
 }

 lastButtonState = reading;
 
//======================================

 switch(lightPattern) {
   case 1:
     softBlink(strip.Color(50,0,0), 1);
     break;
   case 2:
     softBlink(strip.Color(0,50,0), 1);
     break;
   case 3:
     rainbowCycle(10);
     break;
   case 4:
     softBlink(strip.Color(0,0,50), 1);
     break;
 }
}

//======================================
// Fill all the dots with one color
void allColor(uint32_t c) {
 for(uint16_t i=0; i<strip.numPixels(); i++) {
     strip.setPixelColor(i, c);
     strip.show();
 }
}

//======================================
//fades in, then shuts off
void softBlink(uint32_t c, uint8_t wait) {
 
 unsigned long currentMillis = millis();

 if(currentMillis - previousMillis > wait) {
 
   //set the color of all pixels
   allColor(c);
   
   // save the last time you changed a NeoPixel 
   previousMillis = currentMillis; 
   
   uint16_t i;
   int b = neoPixel_j;
   strip.show(); 
   neoPixel_j = (neoPixel_j + 1);
 }
}

//======================================

void rainbowCycle(uint8_t wait) {

  unsigned long currentMillis = millis();
  if(currentMillis - previousMillis > wait) {
    previousMillis = currentMillis; 

  uint16_t i, j;
  for(j=0; j<256; j++) {
        for(i=0; i< strip.numPixels(); i++) {
         strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
    delay(wait);
  }
 }
}

//======================================

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

No código acima veja que existe apenas um delay “delay(wait);” se eu removo este o efeito “rainbowCycle” fica rapido demais, que chega a não dar para ver as cores, apenas piscam na cor branca. E não consegui de nenhuma forma usar o millis para substituir este delay. :confused:

Olá bubulindo

Este ciclo que digo, é a “Wheel” roda que cria o efeito iniciando da cor vermelha e voltando a vermelha. Quando chega no final dese ciclo, ai sim consigo mudar, mas seria necessário ele mudar ao pressionar o botão (ou receber o comando pelo Serial).

Realmente, agora que passei tudo para millis e o problema persiste, acredito que tenha que mudar essa parte do código:

  uint16_t i, j;
  for(j=0; j<256; j++) {
        for(i=0; i< strip.numPixels(); i++) {
         strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
    delay(wait);
  }

Pois é justamente nela que o botão trava, e só passa pra outra função quando acaba o ciclio deste efeito, vou tentar aqui mudar remover esses for para outra coisa e tentar. :wink:

Achei este vídeo que demostra o efeito “rainbowCycle” acima;

Desde já agradeço a atenção.

O maior dos seus problemas nem é o delay em si, mas as vezes que ele é repetido, como o bubulindo, já tinha escrito. Se fizer as contas 256x3x10 = 7,68 segundos. Então só consegue ler teclas de 8 em 8 segundos. (admitindo que o número de pixels é 3, porque não sei qual é esse valor). Sendo assim o que precisa é de um ciclo que continuem a correr as cores mas que o permita também ler as teclas, entretanto.
Tente isto (atenção que não foi testado, porque não tenho nenhuma fita de LED’s nem nenhum Arduino, por isso é normal que não funcione, mas fica aqui a ideia):

#include <Adafruit_NeoPixel.h>
#define PIN 2
Adafruit_NeoPixel strip = Adafruit_NeoPixel(10, PIN, NEO_GRB + NEO_KHZ800);
const int buttonPin = 7;

// Variables will change:
int buttonState;
int lastButtonState = LOW;
long lastDebounceTime = 0;
long debounceDelay = 50;
long previousMillis;

int neoPixel_j = 0;

int nPatterns = 4;
int lightPattern = 1;

uint16_t color;

//----------------------------------------------------------------------------------------------

void setup() {
  strip.begin();
  strip.show();                // initialize all pixels to 'off' 
  pinMode(buttonPin, INPUT);

}

//=============================================================================================

void loop() {

  int reading = digitalRead(buttonPin);
  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;
      color = 0;
      if (buttonState == HIGH) {       
        lightPattern = (lightPattern + 1) % (nPatterns + 1); //include numOfPrograms + 1, since there is an off state
      }
    }
  }

  lastButtonState = reading;

  //======================================

  switch(lightPattern) {
  case 1:
    softBlink(strip.Color(50,0,0), 1);
    break;
  case 2:
    softBlink(strip.Color(0,50,0), 1);
    break;
  case 3:
    rainbowCycle(10);
    break;
  case 4:
    softBlink(strip.Color(0,0,50), 1);
    break;
  }


}

//======================================
// Fill all the dots with one color
void allColor(uint32_t c) {
  for(uint16_t i=0; i<strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    strip.show();
  }
}

//======================================
//fades in, then shuts off
void softBlink(uint32_t c, uint8_t wait) {

  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis > wait) {

    //set the color of all pixels
    allColor(c);

    // save the last time you changed a NeoPixel
    previousMillis = currentMillis;

    uint16_t i;
    int b = neoPixel_j;
    strip.show();
    neoPixel_j = (neoPixel_j + 1);
  }
}

//======================================

void rainbowCycle(uint8_t wait) {

  uint16_t i;
  //for(j=0; j<256; j++) {
  if ( color < 256 ) { 

    for(i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + color) & 255));
    }
    strip.show();
    delay(wait);
    color++;
  }

}

//======================================

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

Luis

Realmente agora entendi a lógica, isso mesmo seria um tempo de 8 em 8 segundos que não iria ler a tecla para mudar. :disappointed_relieved:

Não só me ajudou com a ideia e explicação mais o seu código funcionou sim perfeitamente, a troca acontece no pressionar de botão, mesmo antes do termino do ciclo de cores, já comparei os 2 códigos para entender melhor a lógica aplicada.

Acrescentei apenas uma multiplicação, pois no seu código o ciclo executava apenas uma vez e ficava estática as cores, agora ele executa até 50 vezes ou até o pressionar do botão.

__ if ( color < 256 * 50) {__

Ficou ótimo. :slight_smile:

Fico muito agradecido, muito obrigado.

Eu faria essa alteração de forma diferente. É melhor, fazer reset (igualar a zero) a variável color quando não é premida outra tecla.

Uma coisa ainda melhor é fazer uma coisa como esta:

  switch(lightPattern) {
  case 1:
    softBlink(strip.Color(50,0,0), 1);
    break;
  case 2:
    softBlink(strip.Color(0,50,0), 1);
    break;
  case 3:
    if (color >= 256) { 
        color = 0;
    }
    rainbowCycle(10);
    break;
  case 4:
    softBlink(strip.Color(0,0,50), 1);
    break;
  }

Traduzindo para português, seria qualquer coisa como: - se ainda está a executar o ciclo "arco-íris" e já chegou ao fim ( color >= 256 ) volta ao início (color = 0).

Boa tarde, estou tendo um problema, qndo ligo o USB do Arduíno em um computador linux ele ascende normalmente o led TX e td funciona normalmente e qndo ligo no windons7 o led TX não ascende e não funciona os resultados q aparecem são todos 0.