Go Down

Topic: Boucle interrompue par une commande (Read 920 times) previous topic - next topic

Cr0w

Bonjour,

Je viens juste de recevoir mon Arduino Uno nue je ne peux donc que "jouer" avec une LED. En partant du programme de base j'ai commencé à envoyer des commandes pour allumer et éteindre la LED via Serial. Le problème c'est que je n'arrive pas a interrompre une 3° fonction qui est le clignotement de ma diode par une autre commande. Je m'explique:

Si j'envoie "+" via le terminal de commandes j'allume ma diode.
Si j'envoie "-" via le terminal de commandes j'éteins ma diode.
Si j'envoie "=" je la fais clignoter.
Cependant si je renvoie "+" la diode continue a clignoter car la carte est restée dans la boucle de clignotement de la diode (j'allume et j'éteins avec un delay de 1000).

HELP!

J'ai vu qu'il existait une procédure "interrupt" mais j'ai l'impression que cela ne sert qu'aux interrupteur matériels et pas à faire des "fork"/"threads".

Voici mon code :
Code: [Select]
const int ledPin = 13;  
int ledState = LOW;
boolean interrupt = true;

void setup()  
{  
 Serial.begin(9600);  
 pinMode(ledPin, OUTPUT);  
}  
 
void loop()  
{  
 while (Serial.available())  
 {  
   char key = Serial.read();  
   switch (key)  
   {  
   case '+':  
     interrupt = true;
     ledState = HIGH;
     break;  
   case '-':
     interrupt = true;
     ledState = LOW;
     break;
   case '=':
     interrupt = false;
     loopLed();
     break;
   default:  
     Serial.print("commande ");  
     Serial.print(key);  
     Serial.println(" non reconnue.");  
     break;  
   }  
   digitalWrite(ledPin, ledState);
 }  
}  

void loopLed()
{
 if (ledState == LOW)
   ledState = HIGH;
 else
   ledState = LOW;
 digitalWrite(ledPin, ledState);
 delay(1000);
 if(!interrupt)
   loopLed();
}

Korman

#1
Dec 02, 2010, 11:51 am Last Edit: Dec 03, 2010, 01:16 am by Korman Reason: 1
J'ai vraiment besoin d'un touche qui me rajoute le liens vers l'exemple BlinkWithoutDelay.

Ton problème vient du fait que dés que ton programme commence à clignoter, il ne fait rien d'autre, ce qui inclus lire des commandes. De plus, ta fonction loopLed() fait une récursion à la fin, ce qui n'est pas forcement faux, mais te bouffe les 2 kB de mémoire dans l'ATmega328 rapidement.

Donc vire la fonction loopLed, delay() et toutes les boucles de ls fonction loop() et travaille avec millis(). Pour ce que tu veux faire, la boucle externe qui démarre loop() en perpétuité suffit, tu n'as pas besoin d'autres boucles.

Korman

Cr0w

Merciiiiiiiiiiii ^^

Voici mon code final si ça intéresse un autre Noob comme moi :
Code: [Select]
const int ledPin = 13;  
int ledState = LOW;
boolean interrupt = true;
long interval = 1000;
long previousMillis = 0;

void setup()  
{  
 Serial.begin(9600);  
 pinMode(ledPin, OUTPUT);  
}  
 
void loop()  
{  
 
 if(!interrupt)
 {
   unsigned long currentMillis = millis();

   if(currentMillis - previousMillis > interval) {
     // save the last time you blinked the LED
     previousMillis = currentMillis;  
 
     // if the LED is off turn it on and vice-versa:
     if (ledState == LOW)
       ledState = HIGH;
     else
       ledState = LOW;
 
     // set the LED with the ledState of the variable:
     digitalWrite(ledPin, ledState);
     Serial.print("(=) ");
     Serial.print("Etat Diode :");
     Serial.println(ledState);
   }
 }
 
 while (Serial.available())  
 {  
   char key = Serial.read();  
   switch (key)  
   {  
   case '+':  
     interrupt = true;
     ledState = HIGH;
     break;  
   case '-':
     interrupt = true;
     ledState = LOW;
     break;
   case '=':
     interrupt = false;
     break;
   default:  
     Serial.print("commande ");  
     Serial.print(key);  
     Serial.println(" non reconnue.");  
     break;  
   }  
   digitalWrite(ledPin, ledState);
   Serial.print("(");
   Serial.print(key);
   Serial.print(") ");
   Serial.print("Etat Diode :");
   Serial.println(ledState);
 }  
}  


Guyt

#3
Dec 02, 2010, 07:36 pm Last Edit: Dec 02, 2010, 07:39 pm by Guyt54 Reason: 1
Et si tu veux une solution compliqué, utilise le "TaskManager" de ma librairie (ok, c'est pas encore disponible, mais ça s'en vient  ;) )

ça ressemblerais à ça:

Code: [Select]


#include <TaskManager.h>

boolean ledState ;

void SetLedState(boolean val)
{
   ledState = val ;
   digitalWrite(13,val) ;
}

void ToggleLed(void)
// va être appelé au 250 millisec
{
   SetState(!ledState) ;
}

void setup()
{
 Serial.begin(9600) ;
 pinMode(13,OUTPUT) ;
 SetLedState(false) ;
 TaskManager.Setup(TM_50MS) ; // base de temps 50 milli
 TaskManager.Add(ToggleLed,5)  ; // appel de ToggleLed au 250 ms (50 ms* 5)
}

void loop()
{
 char car ;
 bool led,cligne ;

 if (Serial.available())
    {
       switch  (Serial.Read())  // scuzez l'indentation approximative
          {
             case '+' : SetLedState(true) ;
                           TaskManager.Enable(ToogleLed,false) ;
                           break ;
             case '-' : SetLedState(false) ;
                           TaskManager.Enable(ToogleLed,false) ;
                          break ;
             case '=' : TaskManager.Enable(ToogleLed,true) ;
                           break ;
             default :  Serial.Print("erreur") ;
     }
   }

         

Au Québec, on appelle ça une plogue publicitaire.  ;) ;)  

Go Up