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

Olá Amigos.

Iniciei a poucos dias o estudo de programação e eletrônica em Arduino, até o momento considero que já progredi bastante.
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.

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.

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


Utilizo Arduino Uno R3
Pin 2 = Led Digital

Pin 7 = 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:
LedRun(80);
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 LedRun(uint8_t wait) {

boolean UsingBar = false;

for(uint16_t i=0; i< (strip.numPixels()+ 3); i++) {
if(!UsingBar) { strip.setPixelColor(i+2, 255,0,0); }
strip.setPixelColor(i+1, 150,0,0);
strip.setPixelColor(i, 100,0,0);
strip.setPixelColor(i-1, 50,0,0);
if(!UsingBar) { strip.setPixelColor(i-2, 25,0,0); }

if(!UsingBar) {
strip.setPixelColor(i-3, strip.Color(0,0,0));
} else {
strip.setPixelColor(i-2, strip.Color(0,0,0));
}
strip.show();
delay(wait);
}
}


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

Acredito que o problema esteja no único Delay que não consegui remover (Ultimas linhas do código), e também não consegui o substituir por millis;

Porem esse delay se eu o removo, 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. 

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

Exibições: 1019

Responder esta

Respostas a este tópico

Da uma pesquisada na seguinte função:

yield()

Description

Passes control to other tasks when called. Ideally yield() should be used in functions that will take awhile to complete.

Antoneli

   Essa seria a função ideal que procuro, mas ela só funciona com a Library Scheduler e infelizmente esta somente é compatível com o Arduino Due.

   Nem compila e já da erro;

AVISO: a biblioteca Scheduler alega rodar em arquitetura(s) [sam] e pode ser incompatível com sua placa atual, que roda em arquitetura(s) [avr].

Tente compilar sem a biblioteca,

somente com a chamada da funcao yield();

compilando aqui no UNO pela ide 1.6.5 deu certo

Agora entendi, não adicionei a biblioteca nem o chamado "startLoop" porem acabei de testar mais mesmo compilando e passando para o Arduino continua no mesmo, não muda de efeito até o termino do "ciclo". =(

Se realmente não houver solução terei que comprar o Due.

Espere sempre tem uma solução.....

qual ponto exatamente do código vc quer interromper o loop?

Durante a execução do "void LedRun"

Pois quando chamo ele, ele inicia o efeito, porem quando pressiono o botão ele não muda, só muda quando eu acerto a apertada de botão exatamente no final do efeito.

Essa rotina esta demorando dentro do "for", nao sei o valor de numPixels() nao da pra saber com esse pedaço do código que vc colou.

Mas de qualquer forma tem o delay na jogada, é aí que o processador para e só retorna após o delay.

Desse ponto até o retorno do loop é o tempo e momento que vc tem que apertar o botão e  o processador poder ler o button, enviável dessa forma. O negócio é tentar substituir o delay. Eu tive um problema semelhante, vou dar uma olhada no código e te passo! 

Pq vc nao conseguiu substituir por millis?????

Deveria funcionar!!!!!

Analisando melhor, percebi que não da pra substituir o delay por millis pq o mesmo esta dentro do for, tem que mudar a logica! vou dar uma pensada e te retorno!

Seguinte, tente mudar a condição do for por está!

for(uint16_t i=0; ((i< (strip.numPixels()+ 3))&&( digitalRead(buttonPin)==LOW)); i++) 

Isso faz com que se o botão for apertado ele vai sair do FOR, mas tem um detalhe quando apertar o botão fora do for la na rotina loop o processo pode ser tão rapido que antes de vc soltar ele nao entre no FOR, se isso acontecer então tem que mudar o rotina do debounce para entender que vc clicou no botão somente apos soltar o botão!

Ou seja atualmente se voce segurar o botão por um determinado tempo mínimo o codigo entende que vc realmente apertou o botão (essa é a razão do debounce).

Teria que mudar para quando voce segurar o botão por um determinado tempo mínimo e somente após soltar o botão o codigo entender que vc pressionou o botão. 

É meio chato de fazer isso pq tem que mudar a logica mas é perfeitamente possível, tenta sem essa implementação primeiro....

Outra alternativa:

Crie essa função:

uint8_t meudelay(int wait)
{
   for(int i=0; i<wait; i++)
   {
     if (digitalRead(buttonPin)==LOW) return 1;
     delay(1);
    }
    return 0;
}

Deixa o for como estava originalmente, e coloque a condição abaixo  na primeira linha dentro do for

 if (digitalRead(buttonPin)==LOW) break;

Agora troque o delay(wait); pela chamada da função criada anteriormente, mas dessa forma:

if (meudelay(wait)) break; 

A idéia é se vc pressionar o botão ele interrompe o "for" se estiver na condição do contador de i

A função meudelay foi criada para fragmentar o delay, dessa forma o delay tmb. pode ser interrompido, pressionando o botão

Obs,: A função  meudelay vai ficar um pouco mais lenta que o delay normal, portanto diminua o tempo passado no parametro.

Fiz um teste aqui, segue exemplo:

int buttonPin = 7 ;

void setup ( )
{
Serial.begin(9600);
pinMode ( buttonPin , INPUT_PULLUP ) ;
}

uint8_t meudelay(int wait)
{
for(int i=0; i<wait; i++)
{
if (digitalRead(buttonPin)==LOW)
return 1;
delay(1);
Serial.print(".");
}
return 0;
}

void loop ( )
{
int i;
for (i=0; (i<=1000); i++)
{
if (digitalRead(buttonPin)==LOW) break;
if (meudelay(180)) break;
Serial.println("dentro do for");
}
Serial.println(i);
}

Atenção, veja que dentro do for ainda tem a chamada da rotina strip.setPixelColor, se o processo dentro dessa rotina for lento vc ainda vai ter problema, nessa caso teria que mexer nessa rotina, que acredito que faz parte da biblioteca!

Outra coisa, no seu esboço o botão ta sendo lido em Alta e na modificação que eu sugeri tá em BAIXA, portanto onde eu coloquei "==LOW" tem que ser "==HIGH".

É que no meu exemplo eu inicializei o botão com INPUT_PULLUP para facilitar :)

RSS

© 2024   Criado por Marcelo Rodrigues.   Ativado por

Badges  |  Relatar um incidente  |  Termos de serviço