Problèmes interférence entre i2C et programme d'interruption

Bonjour à tous,

Après avoir cherché des solutions sur ce forum pendant plusieurs jours, j’ai fini par décider de demander de l’aide. (Je précise que je suis plus ou moins novice en Arduino).

MISE EN CONTEXTE :
Je travaille sur la fabrication d’une machine emballeuse de barres de céréales, utilisant des moteurs CC (qui devront être synchronisés) et plusieurs capteurs.
Aujourd’hui, je suis encore bien loin de la fin, je m’intéresse pour l’instant à la communication I2C entre deux cartes MEGA et à la gestion d’interruption.
La carte maitre accueillera une interface homme/machine (un écran tactile TFT) qui enverra les ordres de l’opérateur. De son côté, la carte esclave accueillera les shields moteurs et les différents capteurs.
L’opérateur doit pouvoir, à tout moment, mettre en pause la machine si besoin (pour sa pause-café par exemple !).

EXPLICATION DE LA DEMARCHE :
Pour mettre en œuvre ceci, nous avons utilisé la bibliothèque Wire qui permet la communication, et la bibliothèque sleep_n0m1 pour la mise en veille du système.

PROBLEME :
Lorsque l’on fait fonctionner le système avec seulement la méthode I2C, tout fonctionne parfaitement. De même, le code de mise fonctionne bien lorsqu’il est testé sur une carte. Cependant, si on l’intègre au code, la mise en veille ne fonctionne plus (mise en veille suivi du réveil instantané).
Il y a donc clairement des interférences entre les méthodes d’I2C et d’interruptions.
Auriez-vous une solution ? Merci d’avance

Ci-joint respectivement les codes maître et esclave.

#include <Wire.h>

#define I2C_MASTER_ADRESS 0
#define I2C_SLAVE_ADDRESS 1

const int MAX_LENGTH = 10;
const int length = 7;
 
/* ordre */ 

char MPT1[10]="PT1:000";

const int BP1 = 2;
const int PT1 = 3;
const int BPINTERRUPT = 4;
const int INTERRUPT = 7;

boolean isRunning = true;

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

void setup(){

  Serial.begin(9600);
  Wire.begin(I2C_MASTER_ADRESS);
  Serial.println(" - Je suis le maitre - ");
  pinMode(BP1, INPUT);
  pinMode(PT1, INPUT);
  pinMode(BPINTERRUPT, INPUT_PULLUP);
  pinMode(INTERRUPT, OUTPUT);
  delay(1000);
}

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

/* Cette fonction se lance pour récupérer une information envoyé par une slave */
   
void RequestFromSlave() {

  Wire.requestFrom(I2C_SLAVE_ADDRESS, length);
  char message[MAX_LENGTH];
  for(int j=0 ; j < length ; j++){
  message[j] = Wire.read();
  }
  delay(500);
 
  switch(message[0] + message[1]+ message[2]){

    case 'T' + 'H' + '1': 
      TH1Function(message[4], message[5], message[6]);
      break;
    default:
      Serial.println("Commande inconnue");
      break;
  }
}
//------------------------------------------------------------------------------------

void BPINTERRUPTFunction(){

  if (digitalRead(BPINTERRUPT) == LOW){
    if(isRunning){
      digitalWrite(INTERRUPT, HIGH);
      Serial.println("HIGH");
    }else{
      digitalWrite(INTERRUPT, LOW);
      Serial.println("LOW");
    }
    delay(100);
    isRunning = !isRunning;
  }
}

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

/* Cette fonction se lance pour analyser l'information du capteur de température */

void TH1Function(char centaine, char dizaine, char unite){

  int number = ((unite - 48) + ((dizaine - 48) * 10) + ((centaine - 48) * 100));
  Serial.print("Température des résistances : ");
  Serial.print(number);
  Serial.print("°C");
  Serial.println();
  }

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

/* Cette fonction se lance dès que nous modifions la valeur du PT1 */

void PT1Function(){

  int PreviousValPT1 = 0;
  int ValPT1 = analogRead(PT1);
  ValPT1 = map(ValPT1, 0, 1023, 0, 255);  
  if (PreviousValPT1 != ValPT1) {
    PreviousValPT1 = ValPT1;
    Serial.println(PreviousValPT1);

    //48 <=> code ascii de '0'
    MPT1[6] = (PreviousValPT1 % 10) + 48;
    PreviousValPT1 /= 10;
    MPT1[5] = (PreviousValPT1 % 10) + 48;
    PreviousValPT1 /= 10;
    MPT1[4] = (PreviousValPT1 % 10) + 48;
    PreviousValPT1 = ValPT1;

    Serial.println(MPT1);
    Wire.beginTransmission(I2C_SLAVE_ADDRESS);
    Wire.write(MPT1);
    Wire.endTransmission();
    delay(50);
    }
  }

//------------------------------------------------------------------------------------
   
void loop(){

  RequestFromSlave();
  PT1Function();
  BPINTERRUPTFunction();
  delay(100);
}
#include <Wire.h>
#include <AFMotor.h>
#include <Sleep_n0m1.h>

Sleep sleep;

#define I2C_MASTER_ADRESS 0
#define I2C_SLAVE_ADDRESS 1
const int MAX_LENGTH = 10;
const int PinTemperature = A10;
const int PinLED = 34;
const int PinInterrupt = 19; 

AF_DCMotor MCC1(1);

/*ordre*/ 
char TH1[10]="TH1:000";
char CP1[10]="CP1:000";

boolean isRunning = true;

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

void setup() {

  Serial.begin(9600);
  Wire.begin(I2C_SLAVE_ADDRESS);
  Serial.println(" - Je suis l'esclave - ");
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvents);


  pinMode(PinInterrupt, INPUT);
  attachInterrupt(4, onRelease, RISING);

  pinMode(PinLED, OUTPUT);
  MCC1.setSpeed(0);
  MCC1.run(RELEASE);

  delay(1000);
 }

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

/* Cette fonction se lance dès que nous recevons un message de la carte maitre */

void receiveEvent(int length){

    char message[MAX_LENGTH];
    for(int j = 0 ; j < length ; j++){
        message[j] = Wire.read();
    }
    Serial.print("Ordre reçu : ");
    Serial.println(message);
    
    switch(message[0] + message[1]+ message[2]){

        case 'P' + 'T' + '1':
            Serial.println("Modification de la vitesse du MCC\n");
            PT1Function(message[4], message[5], message[6]);
            break;
        default:
            Serial.println("Commande inconnue\n");
            break;
  } 
}

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

/* Cette fonction se lance pour envoyer une information au maitre */

void requestEvents(){

  Serial.print("envoi de TH1 = ");
  Serial.println(TH1);
  Wire.write(TH1);
  delay(100);
}
//------------------------------------------------------------------------------------

/* Cette fonction se lance dès que nous appuyons sur le bouton d'interruption */

void onRelease(){
  
  Serial.println("SLEEP zzzz");
  digitalWrite(PinLED, HIGH);
  sleep.pwrDownMode();
  sleep.sleepInterrupt(4, RISING);
  attachInterrupt(4, onRelease, RISING);
  digitalWrite(PinLED, LOW);
Serial.println("WAKE UP");
}

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

/* Cette fonction se lance pour récupérer la valeur de la température */

void TH1Function(){

 int PreviousValTH1 = 0;
 int sensorVal = analogRead(PinTemperature);
 float voltage = (sensorVal/1024.0)* 5.0;
 float ValTH1 = (voltage - 0.5)*100;
 
 if (PreviousValTH1 != ValTH1){

  PreviousValTH1 = ValTH1;
  
  TH1[6] = (PreviousValTH1 % 10) + 48;
  PreviousValTH1 /= 10;
  TH1[5] = (PreviousValTH1 % 10) + 48;
  PreviousValTH1 /= 10;
  TH1[4] = (PreviousValTH1 % 10) + 48;

  PreviousValTH1 = ValTH1;
  Serial.println(ValTH1);
 }
}

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

/* Cette fonction se lance dès que nous recevons un ordre PT1 */

void PT1Function(char centaine, char dizaine, char unite){

  int number = (unite - 48) + ((dizaine - 48) * 10) + ((centaine - 48) * 100);
    Serial.print("vitesse du MCC1 : ");
    Serial.println(number);
    MCC1.setSpeed(number);
    MCC1.run(FORWARD);
}

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

 void loop() {
   TH1Function();
   delay(100);
 }

Bonjour,
lors de l'envoi (ou la réception) de trames i2c, il y a "plein" d'interruptions, qui en l'occurence provoquent l'arrêt de la mise en veille

Bonsoir,

Effectivement je me doutais de ce problème, sauriez-vous s'il existe des solutions pour y palier ?

en fait, la question, c'est pourquoi veux tu mettre la cpu en veille quand elle a du travail ?

Bonjour,

J'ai besoin de mettre en place une veille du système mais uniquement sur la carte esclave. Puisque si nous réalisons une interruption sur le système global nous éteignons l'écran tactile qui permettrais de réveiller la carte. Il faut donc continuer d'alimenter la carte maître (et donc l'I2C) tout en mettant en place une veille sur la carte esclave.

Le coeur du problème est là et je ne vois pas comment le résoudre.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.