Pages: [1]   Go Down
Author Topic: Inhiber les interruptions fait planter le programme  (Read 538 times)
0 Members and 1 Guest are viewing this topic.
Behind you
Offline Offline
Jr. Member
**
Karma: 0
Posts: 91
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 :

Code:
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 :
Code:
digitalWrite(Q_LED_RED, HIGH);
indique l'endroit ou le programme reste bloqué quand les interruptions sont inhibées.
Code:
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  smiley-cry

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 - downloaded 3 times.)
« Last Edit: February 17, 2013, 12:15:42 pm by Reynosa » Logged

france
Offline Offline
God Member
*****
Karma: 8
Posts: 708
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Le compteur de temps micros() ne tourne pas pendant les interruptions.
Quote
Inside the attached function, delay() won't work and the value returned by millis() will not increment.
http://arduino.cc/en/Reference/AttachInterrupt
Logged

Christian

Behind you
Offline Offline
Jr. Member
**
Karma: 0
Posts: 91
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bonsoir,

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

France
Offline Offline
Faraday Member
**
Karma: 23
Posts: 3018
There is an Arduino for that
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

France
Offline Offline
Faraday Member
**
Karma: 52
Posts: 5341
Arduino Hacker
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

Des news, des tuto et plein de bonne chose sur http://skyduino.wordpress.com !

Behind you
Offline Offline
Jr. Member
**
Karma: 0
Posts: 91
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

France
Offline Offline
Faraday Member
**
Karma: 52
Posts: 5341
Arduino Hacker
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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 ?
Logged

Des news, des tuto et plein de bonne chose sur http://skyduino.wordpress.com !

Behind you
Offline Offline
Jr. Member
**
Karma: 0
Posts: 91
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 smiley-cry

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 !

Code:
// 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 :
Code:
#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);*/
}
Logged

Behind you
Offline Offline
Jr. Member
**
Karma: 0
Posts: 91
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Je viens de faire un test :
Code:
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,
Logged

Pages: [1]   Go Up
Jump to: