communication i2c entre 2 arduino

Bonjour

J'ai un projet qui utilise un servomoteur AC piloté par un arduino uno ce code fonctionne parfaitement

Mais je voudrais utilisé 2 arduino connecté par i2c:

-pour l'esclave son rôle est d'envoyé les signaux de pas au servo (il contient le code qui pilote le moteur) en prenant compte de 3 paramètre (3 octet envoyé par le maitre)

(les paramètres sont le nombre de tour a effectué, la vitesse de rotation et l'accélération)

-le maître lui envoie les 3 paramétré et n'attend rien en retour

(cela me permet de pouvoir lire des capteurs pendant que le moteur tourne)

mon code fonctionne mais quand je mesure la fréquence des signaux sur la pin d2 avec un oscilloscope je constate que la fréquence est trop faible

Pourtant les octet réceptionné sont les bons (vérifié avec le moniteur serie)
la valeur de la variable pause est bonne aussi

Par contre si a la place de Wire.read() je rentre directement la valeur cela fonctionne, la frequence est bonne

si au lieu d'envoyé 3 paramètres j'envoie juste le premier (celui qui gère la fréquence) et que je code directement les 2 autres a la place de Wire.read() sa fonctionne également.

Je ne comprend vraiment pas!!

Normalement que la valeur soit affecté avec la fonction Wire.read() ou manuellement je suis sensé avoir le même résultat non ?

code du maitre

#include <Wire.h>

void setup()
{
  Serial.begin(128000);   
  Wire.begin(); 
}



void loop()
{

   
  Wire.beginTransmission(0b1001001); // Commencer transmission vers l'esclave  
  Wire.write(100);      
  Wire.write(30);
  Wire.write(5);                
  Wire.endTransmission();    // fin transmission

}

code de l'esclave (la fonction start_vitesse_constante() est simplifié pour mieux cerné le probléme)

#include <Wire.h>

#define NB_PAS_PAR_TOUR 200
#define FREQ_MIN  1

#define PAS 2 // affection pin digital du pas
#define DIR 3// affection pin digital de la direction

void setup()
{
  Wire.begin(0b1001001);                
  Wire.onReceive(receiveEvent); 

  pinMode(PAS,OUTPUT);
  pinMode(DIR,OUTPUT);
}

void loop()
{
  delay(100);
}

// Fonction qui est exécutée lorsque des données sont envoyées par le Maître.

void receiveEvent(int howMany)
{
  long vitesse_max;
  long course;
  long distance_acc;

  while(3!=Wire.available())
  {
    delay(100);
  }
  
  vitesse_max = Wire.read()*6;// conversion mm/s en tr/min 
  course = Wire.read()*(NB_PAS_PAR_TOUR/10) ;//conversion mm en nombre de pas
  distance_acc= Wire.read()*(NB_PAS_PAR_TOUR/10) ;//conversion mm en nombre de pas
  
  start_vitesse_constante(vitesse_max,course,distance_acc);
}


//fonction qui execute un cycle (une acceleration + vitesse constante + deceleration)
//la frequence est en tour/minute

void start_vitesse_constante(long tour_min_max,long nb_pas_total,long nb_pas_acc) //fonction qui execute un cycle (une acceleration + vitesse constante + deceleration)
{
    
   int nb_pas_envoye=0L;
   long f_actuel;
   long pause;

   
    
    // vitesse constante
    for(nb_pas_envoye=nb_pas_acc ; nb_pas_envoye < (nb_pas_total-nb_pas_acc) ; nb_pas_envoye++)
    {
      
      pause=60000000/(NB_PAS_PAR_TOUR*tour_min_max);
      
      digitalWrite(PAS,HIGH);//envoie du pas
      digitalWrite(PAS,LOW);

     
      
       do // pause
      {
         if( pause <= 10000 ) 
         { 
          delayMicroseconds(pause);
          pause=0;
         }
         else
         {
           delayMicroseconds(10000);
           pause -= 10000;
         }
      } while( pause > 0);   
       
    }
    
    
   }

Bonjour,
Essayez avec ((long) wire.read()) * ( etc...)
Je ne suis pas certain que la constante numérique suffise à produire une conversion automatique en (int)...
Benoit

Bonsoir

Merci de votre réponse je vais essayer sa.

Mais le soucis ne provient pas de la transmission i2c ...

J'ai essayé avec une transmission série entre les 2 carte le problème est le même

J'ai l'impression que c'est le temps que la boucle for recharge ses paramètres

Et si je rentre les valeurs directement à la place des variables c'est plus rapide

Se que j'observe c'est que cela prend environ 50 us pour calculer la valeur de la variable pause

Si vous avez une idée d'optimisation je suis preneur

Il y a un truc qui me choque dans ça

void start_vitesse_constante(long tour_min_max,long nb_pas_total,[color=red]long nb_pas_acc[/color])
{
   [color=red]int[/color] nb_pas_envoye=0[color=red]L[/color];
...
   for([color=red]nb_pas_envoye=nb_pas_acc[/color] ; nb_pas_envoye < (nb_pas_total-nb_pas_acc) ; nb_pas_envoye++)
    {

Prenez l’habitude de donner un type à vos constantes surtout quand elles sont grandes (et en cohérence avec vos variables). ça vous évitera d’avoir de sous doutes sur ce que fait le compilateur (qui calcule en int (donc 16 bits signés) sans infos complémentaires et si le reste des variables sont des int ou moins grand. par exemple pourcourse = Wire.read()*(NB_PAS_PAR_TOUR/10) ;le calcul est effectué en int puis affecté dans votre variable long. En mettant un L sur un des éléments du calcul (le define devrait aussi l’avoir)course = Wire.read()*(NB_PAS_PAR_TOUR/10L) ;vous forcez le calcul en long.

pause=60000000/(NB_PAS_PAR_TOUR*tour_min_max);serait donc mieux (de manière générale - ici ça marche pour vous car tour_min_max est un long ) en pause=60000000L/(NB_PAS_PAR_TOUR*tour_min_max);

Sinon faire des delay() dans votre code c’est pas top...

while(3!=Wire.available())
  {
    delay(100);
  }

mais vous devriez toujours avoir vos 3 octets donc pas trop grave.

Bonjour

En complément, j'insisterais sur un point très important relatif au coding de la réception des messages côté esclave : la fonction receiveEvent() est déclenchée par une interruption.

Le bon réflexe général pour éviter les problèmes dans les routines d'interruption, c'est de leur faire réaliser le moins de choses possibles, pour limiter leur temps d'exécution au strict minimum.

Donc typiquement ici : se contenter de mettre à jour des variables globales (déclarées en volatile, rien à voir avec le poulet) = transferer les Wire.read() dans un buffer.
Et laisser à la fonction loop le soin de traiter le contenu du buffer.

Ainsi par exemple, en aucun cas on ne devrait trouver de Serial.print dans une routine d'interruption. Et encore moins un delay().

A ma connaissance la routine receiveEvent() est déclenchée APRES la fin de transmission de tout le message sur le bus I2C.
Pendant qu'on est dans receiveEvent(), de son côté le maître considère que la communication est terminée et poursuit l'exécution de son code.
Ce qui peut inclure l'envoi d'un autre message, et là des problèmes vont commencer à arriver si côté esclave on est toujours à l'intérieur du receiveEvent() du message précédent.

D'où l'intérêt de passer par un buffer entre receiveEvent() et loop().
Et selon les besoins, ce buffer peut servir de tampon capable d'empiler plusieurs messages reçus en attente de traitement par la fonction loop().