Inhiber les interruptions fait planter le programme

Bonjour à tous !

Suite à mon problème sur ce topic, j'ai commandé un lcd pas encore reçu à ce jour, donc j'ai trouvé un autre moyen afin de "grossièrement" debugger le plus vite possible (oui j'ai malheureusement une date limite pour ce projet).

Bienvenue à tous sur ce nouveau topic tout propre ! ^^

Premièrement j'ai repassé le programme en C au lieu du C++. Et j'utilise une led intégrée à ma carte pour voir où plante le programme.
La fonction problème :

void radiocommandInitialisation(void)
{
    unsigned long pTime;
    boolean initialisationOn = true;
    noInterrupts(); // pas d'interruption afin de ne pas perturber l'init
    
    while(initialisationOn)
    {
  	if (!(RX_PIN0 || RX_PIN1 || RX_PIN2 || RX_PIN3 || RX_PIN4 || RX_PIN5 || RX_PIN6 || RX_PIN7))
        {
            pTime = micros();
	    while ((!(RX_PIN0 || RX_PIN1 || RX_PIN2 || RX_PIN3 || RX_PIN4 || RX_PIN5 || RX_PIN6 || RX_PIN7)))
	    {
                digitalWrite(Q_LED_RED, HIGH);
		if ((micros() - pTime) >= 5000)
		{digitalWrite(Q_LED_YELLOW, HIGH);
		    initialisationOn = false;
		    break;
		}
                
	    }
        }
    }
    interrupts();
    digitalWrite(Q_LED_RED, HIGH);
    Q_INIT_RX;
    Q_INIT_RX_INT;
}

Cette ligne :

digitalWrite(Q_LED_RED, HIGH);

indique l'endroit ou le programme reste bloqué quand les interruptions sont inhibées.

digitalWrite(Q_LED_YELLOW, HIGH);

Et celle là indique que le programme s'exécute complètement quand les interruptions sont actives.

Est-ce que quelqu'un peut me dire ce que j'ai fait de mal ? Je ne comprend pas =(

Merci d'avance,

Je met le projet Arduino en pièces jointes, le code est trop long pour être incorporé directement ici.

Quadricopter.rar (4.83 KB)

Le compteur de temps micros() ne tourne pas pendant les interruptions.

Inside the attached function, delay() won't work and the value returned by millis() will not increment.

http://arduino.cc/en/Reference/AttachInterrupt

Bonsoir,

Je suis d'accord, mais ça n'explique pas pourquoi en désactivant les interruptions ça ne fonctionne plus =/

Parce que micros() fonctionne avec les IT timer. Si tu masques les IT tu ne compte plus les débordements du timer et micros retourne toujours la même valeur.

Bonjour,

Faire une boucle d'attente dans une interruption est une trés mauvaise idée !
Non seulement les fonctions Delay(), Millis(), .. ne fonctionnent pas sous interruptions, mais en plus une interruption ce doit d'être la plus rapide possible pour ne pas bloquer le reste du programme.

Je crois qu'on s'est mal compris ^^ La fonction ici présente n'est pas une routine interruption, c'est juste une fonction qui a besoin que les interruptions soient désactivées pour remplir sa tâche.

Reynosa:
Je crois qu'on s'est mal compris ^^ La fonction ici présente n'est pas une routine interruption, c'est juste une fonction qui a besoin que les interruptions soient désactivées pour remplir sa tâche.

J'avais mal compris effectivement.

Du coup je pense que ta fonction est mal construite.
Que doit elle faire exactement ? (-> le code complet)
Pourquoi doit elle être obligatoirement exécuté sans interruptions ?

Ps: RX_PIN0 c'est un define d'un port/broche ou une variable globale ?

J'ai mis le programme en pièces jointes =)
Mais pour plus de simplicité je poste la page correspondante.

Il y a eu du changement depuis mon premier post. Cette fonction qui pose problème me sert à attendre la fin d'un cycle de réception en provenance de mon recepteur RC. Cet à dire que j'attend que toutes les impulsions soient passées pour activer les interruptions, qui elles, se chargeront de récupérer en continue tous les cycles et de les mettre de côté en mémoire pour la suite du programme.

J'ai lu je ne sais plus où que la fin d'une trame sur le récepteur devait obligatoirement se terminer par un niveau bas sur toutes les sorties pendant 8ms.
De ce fait, mon ancien programme attendait que toutes les sorties soient à 0 et que au moins 5ms se soient écoulées.
C'est là dessus que je lutte depuis près d'un moins maintenant =(

Après un peu de cogite et de problème, j'ai trouvé une version nettement plus pertinente et performante de repérer cette fin de cycle: il suffit d'attendre que l'impulsion soie passée sur la dernière sortie du récepteur (toutes les impulsions arrivent une à la fois et l'une après l'autre)

Du coup je n'ai plus le problème liée aux interruptions (mais j'aimerais quand même comprendre pourquoi ça ne fonctionne pas) et je suis encore et toujours bloqué sur un nouveau problème (on s'en serait presque douté)
Le nouveau problème est : le programme rentre dans la première boucle et en ressors bien comme prévu, ça rentre dans la deuxième boucle MAIS on en ressors jamais.
J'ai essayé toutes les écritures possible et imaginable et rien n'y fait. Je tiens à préciser que le signal d'entré passe bien par 0 périodiquement (50Hz).

Petit résumé : Pourquoi mon ancien programme marche pas ? ^^ et pourquoi le nouveau reste bloqué dans sa boucle ?

Merci pour vos réponses et merci d'avance pour les prochaines !

// label de simplification d'écriture
#define RX_PIN0 PORTK&ROLL_PIN
#define RX_PIN1 PORTK&PITCH_PIN
#define RX_PIN2 PORTK&THROTTLE_PIN
#define RX_PIN3 PORTK&YAW_PIN
#define RX_PIN4 PORTK&AUX1_PIN
#define RX_PIN5 PORTK&AUX2_PIN
#define RX_PIN6 PORTK&AUX3_PIN
#define RX_PIN7 PORTK&AUX4_PIN

/* Déclaration des variables */
uint8_t throttle;
uint8_t yaw;
uint8_t pitch;
uint8_t roll;
uint8_t aux1;
uint8_t aux2;
uint8_t aux3;
uint8_t aux4;
boolean motorLock;

/* Déclaration des fonctions */
boolean MotorLock(void);
boolean isRTF(void);

/********************************************/
/*         Définition des fonctions         */
/********************************************/

void radiocommandInitialisation(void)
{
    Q_INIT_RX;
    
    noInterrupts(); // pas d'interruption afin de ne pas perturber l'init
    
    while(!(PORTK & 1)); // on attend un passage à 1 de la derniere pulse
    
    while(PORTK & 1)
    {
      if (PORTK & 1)
          digitalWrite(Q_LED_RED, HIGH);
      else
          digitalWrite(Q_LED_YELLOW, HIGH);
    };    // on attend une retombé à 0 de la derniere pulse
    
    interrupts(); // rétablissement des interruptions
    
    Q_INIT_RX_INT;
}

/********************************************/
/* Définition de la fonction d'interruption */
/********************************************/

ISR(PCINT2_vect)
{
    volatile static unsigned long previousTime;
    volatile static uint8_t currentInterruption = 0;
    volatile uint16_t largeurImpulsion = 0;
	
    switch(currentInterruption)
    {
	// ROLL
	case 0: previousTime = micros(); currentInterruption++; break;
	case 1: largeurImpulsion = micros() - previousTime; //temps d'une pulse
                // protection dépassements de temps d'impulsion
	        largeurImpulsion = (largeurImpulsion < 1000) ? 1000 : largeurImpulsion;
	        largeurImpulsion = (largeurImpulsion > 2000) ? 2000 : largeurImpulsion;
	        // conversion microseconde / byte
		roll = ((255.0/1000.0)*(largeurImpulsion) - 255);
		currentInterruption++;
	break;
		
	// PITCH
	case 2: previousTime = micros(); currentInterruption++; break;
	case 3: largeurImpulsion = micros() - previousTime; //temps d'une pulse
		// protection dépassements de temps d'impulsion
		largeurImpulsion = (largeurImpulsion < 1000) ? 1000 : largeurImpulsion;
		largeurImpulsion = (largeurImpulsion > 2000) ? 2000 : largeurImpulsion;
		// conversion microseconde / byte
		pitch = ((255.0/1000.0)*(largeurImpulsion) - 255);
		currentInterruption++;
	break;
		
	// THROTTLE
	case 4: previousTime = micros(); currentInterruption++; break;
	case 5: largeurImpulsion = micros() - previousTime; //temps d'une pulse
		// protection dépassements de temps d'impulsion
		largeurImpulsion = (largeurImpulsion < 1000) ? 1000 : largeurImpulsion;
		largeurImpulsion = (largeurImpulsion > 2000) ? 2000 : largeurImpulsion;
		// conversion microseconde / byte
		throttle = ((255.0/1000.0)*(largeurImpulsion) - 255);
		currentInterruption++;
	break;
		
	// YAW
	case 6: previousTime = micros(); currentInterruption++; break;
	case 7: largeurImpulsion = micros() - previousTime; //temps d'une pulse
		// protection dépassements de temps d'impulsion
		largeurImpulsion = (largeurImpulsion < 1000) ? 1000 : largeurImpulsion;
		largeurImpulsion = (largeurImpulsion > 2000) ? 2000 : largeurImpulsion;
		// conversion microseconde / byte
		yaw = ((255.0/1000.0)*(largeurImpulsion) - 255);
		currentInterruption++;
	break;
		
	//AUX1
	case 8: previousTime = micros(); currentInterruption++; break;
	case 9: largeurImpulsion = micros() - previousTime; //temps d'une pulse
		// protection dépassements de temps d'impulsion
		largeurImpulsion = (largeurImpulsion < 1000) ? 1000 : largeurImpulsion;
		largeurImpulsion = (largeurImpulsion > 2000) ? 2000 : largeurImpulsion;
		// conversion microseconde / byte
	        aux1 = ((255.0/1000.0)*(largeurImpulsion) - 255);
		currentInterruption++;
		break;
		
	//AUX2
	case 10: previousTime = micros(); currentInterruption++; break;
	case 11: largeurImpulsion = micros() - previousTime; //temps d'une pulse
		 // protection dépassements de temps d'impulsion
		 largeurImpulsion = (largeurImpulsion < 1000) ? 1000 : largeurImpulsion;
		 largeurImpulsion = (largeurImpulsion > 2000) ? 2000 : largeurImpulsion;
		 // conversion microseconde / byte
		 aux2 = ((255.0/1000.0)*(largeurImpulsion) - 255);
		 currentInterruption++;
	break;
	
	//AUX3
	case 12: previousTime = micros(); currentInterruption++; break;
	case 13: largeurImpulsion = micros() - previousTime; //temps d'une pulse
		 // protection dépassements de temps d'impulsion
		 largeurImpulsion = (largeurImpulsion < 1000) ? 1000 : largeurImpulsion;
		 largeurImpulsion = (largeurImpulsion > 2000) ? 2000 : largeurImpulsion;
		 // conversion microseconde / byte
		 aux3 = ((255.0/1000.0)*(largeurImpulsion) - 255);
		 currentInterruption++;
	break;
	
	//AUX4
	case 14: previousTime = micros(); currentInterruption++; break;
	case 15: largeurImpulsion = micros() - previousTime; //temps d'une pulse
		 // protection dépassements de temps d'impulsion
		 largeurImpulsion = (largeurImpulsion < 1000) ? 1000 : largeurImpulsion;
		 largeurImpulsion = (largeurImpulsion > 2000) ? 2000 : largeurImpulsion;
		 // conversion microseconde / byte
		 aux4 = ((255.0/1000.0)*(largeurImpulsion) - 255);
		 currentInterruption = 0;
	break;
	}
}

et la page principale :

#include <I2C.h>
#include <Servo.h>
#include "config.h"
#include "def.h"

// Déclaration des fonctions d'initialisation
void motorInitialisation(void);
void gyroscopeInitialisation(void);
void radiocommandInitialisation(void);


void setup()
{
  Serial.begin(9600);
  I2c.begin();
  I2c.setSpeed(1);
  
  pinMode(Q_LED_GREEN, OUTPUT);
  pinMode(Q_LED_YELLOW, OUTPUT);
  pinMode(Q_LED_RED, OUTPUT);
  
  motorInitialisation();
  gyroscopeInitialisation();
  radiocommandInitialisation();
}

void loop()
{
  // Petit Check batterie
  //if (Quadri.etatBatterie() == Q_BAT_HS)
   // Quadri.LED_etatBatterie(Q_BLINK);
  
  // Condition de mise route
 // if (Quadri.areMotorsRotating() == false) // si tous les moteurs sont arrêtés
   // while (Radio.isRTF() == Q_NOT_READY_TO_FLY);// et que l'inter est actif : on attend
  
  /***************************/
  /* PHASE DE CONTROL DE VOL */
  /***************************/
  //Quadri.setConsignesDeVol(/*quelque chose*/);
  //Quadri.CorrectionsDeVol(/* éventuellement quelques chose *unknown 4 the moment* */);
  
  /*delay(200);
  digitalWrite(Q_LED_RED, HIGH);
  delay(200);
  digitalWrite(Q_LED_RED, LOW);*/
}

Je viens de faire un test :

void setup()
{
  Serial.begin(115200);
  
  DDRK = 0;
  PORTK = 255;
  
    DDRB = DDRB | 0x80;  // led rouge
    PORTB = PORTB | 0x80;
    //DDRC = DDRC | 0x40;  //led jaune
    //PORTC = PORTC | 0x40;
    DDRC = DDRC | 0x80;  //led verte
    PORTC = PORTC | 0x80;
}

void loop()
{ Serial.println(PORTK&1);
  /*
    if (PORTK & 1)
    {
        PORTC &= 0x7F;
        delay(200);
    }
    else
    {
        PORTC |= 0x80;
        delay(200);
    }*/
}

Au départ je n'avais pas la connexion série. La led rouge était bien allumée, mais la verte toujours éteinte. J'ai tout bazardé en commentaire et mis le Serial. Résultat ma console est pleine à craquer de "1" . J'en ai donc conclu que le microcontroleur ne détectait jamais un niveau bas. Ce qui n'est pas normal, j'ai regardé le signal d'entré à l'oscilloscope pour vérifier, j'ai bien un niveau haut pendant 1.5ms et un niveau bas pendant 18.5ms. Je ne comprend plus rien, Quelqu'un saurait ce que j'ai fait de mal pour que ça fasse ça ?

Merci d'avance,