Arduino et I²C

Bonjour, je me pose cette question concernant l’utilisation des cartes Aduino en I²C.
Pour faire dialoguer deux cartes en I²C, seul le branchement des signaux SDA et SCL sont nécessaires (alim et masses communes comprises) et sans résistances de rappel au +Vcc, il doit y en avoir à l’intérieur sur ces broches.
Mais alors je me pose la question à savoir si on rajoute un ou plusieurs périphériques connectés en I²C, faut-il mettre des résistances de rappel ou celles des arduinos suffisent, si tentés qu’ils en aient ?
Je dirais qu’il faut mieux faire comme sur le premier schéma

schema-i2c.png

emmett_brown: Bonjour, je me pose cette question concernant l'utilisation des cartes Aduino en I²C. Pour faire dialoguer deux cartes en I²C, seul le branchement des signaux SDA et SCL sont nécessaires (alim et masses communes comprises) et sans résistances de rappel au +Vcc, il doit y en avoir à l'intérieur sur ces broches. Mais alors je me pose la question à savoir si on rajoute un ou plusieurs périphériques connectés en I²C, faut-il mettre des résistances de rappel ou celles des arduinos suffisent, si tentés qu'ils en aient ? Je dirais qu'il faut mieux faire comme sur le premier schéma

Bonsoir Il faut une resistance de tirage "adaptée" sur chaque ligne SCL/SDA attention donc à la mise en // de resistances

D'accord, donc vu que je n'ai pas trop besoin de rapidité, une bonne 4.7 kohms sur chaque ligne pour tout le réseau I²C est adéquate. Mais par contre je me demande comment font mes deux arduino pour bien dialoguer entre elles qu'elles aient ou non les résistances de rappel (tirage) ?

emmett_brown: D'accord, donc vu que je n'ai pas trop besoin de rapidité, une bonne 4.7 kohms sur chaque ligne pour tout le réseau I²C est adéquate. Mais par contre je me demande comment font mes deux arduino pour bien dialoguer entre elles qu'elles aient ou non les résistances de rappel (tirage) ?

reponse sans verifier, mais la proba que le pull-up interne soit activé sur un des arduinos me semble importante.

Voir ce topic à partir de la dernière remarque du #5

Ok, très bonne explication et exhaustive je pense de la manière d’interconnexions des différents périphériques d'un bus I²C même si je n'en demandais pas tant, reste à ajouter le lien du topic à partir de la réponse #5 en favoris pour une lecture ultérieure ou un futur questionnement au sujet de ce bus que j'aurai.

"Que je trépasse si je faibli !" (comme çà)

En relisant le topic, je viens de me rendre compte que mon IP publique est vraiment publique (sur ce site) alors même que j'ai un arduino en webserveur domotique, allumé, qui peut allumer un hallogène via le module RF ou l'éteindre selon si l'on appuie sur "The Led 3 is ON/OFF" sur ce même site local qui peut être affranchie en passant par le port 4200...

p.s: pas de smartphone pour tester...

emmett_brown: En relisant le topic, je viens de me rendre compte que mon IP publique est vraiment publique (sur ce site) alors même que j'ai un arduino en webserveur domotique, allumé, qui peut allumer un hallogène via le module RF ou l'éteindre selon si l'on appuie sur "The Led 3 is ON/OFF" sur ce même site local qui peut être affranchie en passant par le port 4200...

p.s: pas de smartphone pour tester...

Tu parle de l'IP qui apparait sous ton avatar ? si oui , elle n'est visible que par toi (et les moderateurs)

Ah ok, j'me suis emporté, c'tait juste pour savoir si un d'jeuns aurait pû tester mon halogène extérieur avec son smartphone et forfait à 50 euros pour voir mon "domosite" et ainsi tester DEPUIS l'extérieur le système... ==> passer voir pour un smartphone/forfait

P.S: à ces phrases il pourrait que j'en suis mais non, je n'ai pas encore la quarantaine... via relecture.

emmett_brown:
Ah ok, j’me suis emporté

en fait voici ce que je vois

reponse sans verifier, mais la proba que le pull-up interne soit activé sur un des arduinos me semble importante.

Réponse avec vérification :grin: : oui elles sont activées par défaut et AMHA c’est une conner*e.

La norme en I2C est d’utiliser des collecteurs (ou drains) ouverts.

Fonctionnement de l’I2C
Un collecteur ou drain ouvert est assimilable à un transistor utilisé en montage émetteur (ou drain) commun.
L’impédance de sortie de ce montage est égal à la résistance de charge de collecteur (ou drain).

La résistance de charge de collecteur est celle dont on parle pour SDA et SCL.
Chaque entrée de circuit est légèrement capacitive, une longueur de connexion ajoute de la capacité.
Donc plus il y a de modules connectés et plus les fils sont longs, plus il y aura de capacité.

Origine du problème :
La capacité se charge et se décharge au rythme des 1 et des 0.
Elle se charge au travers de la résistance de charge de collecteur (ou drain). Le temps de charge est dépendant du produit Rcollecteur * C
Pour que cela fonctionne il faut que le temps de charge soit faible devant une demi période d’horloge de l’I2C.

Quels moyen d’action si la capacité est trop élevée :

  • Soit on baisse la fréquence de l’I2C. La fréquence courante est 100 kHz mais on peut utiliser des fréquences plus faibles.
  • Soit pour conserver la fréquence de 100 kHz on maintient un produit R*C identique et on diminue la valeur de résistance de collecteur.

Conclusion :
Le fonctionnement sur résistance de tirage interne du micro (pull-up) est complètement aléatoire, la valeur de ces résistances est trop élevée et pire elle peut varier de +/- 30 % d’un lot de fabrication à un autre.
C’est pour cette raison que je dis que leur activation par défaut est une conner*e : si on oublie de mettre une résistance de charge sur SDA et SCL ça à l’air de marcher mais compte tenu de la dispersion des résistances internes cela peut faire n’importe quoi.

Une valeur équivalente de 4,7 kohms est un bon compromis (sans prise la tête) entre courant raisonnable dans le transistor et temps de charge faible . J’appelle valeur équivalente la valeur résultant de toutes les résistance sur SDA ou SCL qui se retrouvent câblées en parallèle.

Si c’est pour relier deux cartes proches l’une de l’autre 10 k devraient aussi bien fonctionner.
Avec une seule résistance 4,7 k on devrait pouvoir faire fonctionner jusqu’à 4 ou 5 modules sans difficultés.
Au delà il faut simplement être attentif.

J’ai pu remarquer que beaucoup de modules sont équipés avec des 10 k, c’est assez équilibré : quand le nombre de modules augmente la capacité est multipliée et la résistance équivalente est diminuée.

68tjs: Réponse avec vérification :grin: : oui elles sont activées par défaut et [u]AMHA c'est une conner*e.[/u]

Bonsoir 68tjs Tu remarqueras que je n'ai jamais exposé que ce n’était pas une belle ........... :grin:

Bonsoir, je ne post pas de nouveau sujet puisqu’il s’agit toujours du I²C avec Arduino; j’ai un petit souci concernant la réception de données à un slave (NANO) envoyées par un master (Mega2560).
Le NANO reçoit bien les informations mais il écrit dessus celles envoyées juste avant une fois sur deux !!!

Le master :

// Wire Master Writer
// by Nicholas Zambetti <http://www.zambetti.com>

// Demonstrates use of the Wire library
// Writes data to an I2C/TWI slave device
// Refer to the "Wire Slave Receiver" example for use with this

// Created 29 March 2006

// This example code is in the public domain.

//////////////////////////////////////////////////////////////////
//                                                              //
//          Test en I²C d'émission du maître                    //
//                                                              //
//////////////////////////////////////////////////////////////////


#include <Wire.h>

void setup() {
  Wire.begin(); // join i2c bus (address optional for master)
}

byte x = 0;
char * entete = "Arduino";
char * identifiant = "Hangar";
char * commande = "Allume LED rouge";


void loop() {
  
  trame (1);        //  transmission trame en I²C vers 1

  
}

/////  Fonction d'envoi d'une trame complête en I²C
void  trame  (int i)  {
  
    master_write (i, entete);  //  maître écrit sur le bus I²C 
                               //  à l'esclave qui a l'adresse i
    //delay (1000);
                               
    master_write (i, identifiant);  //  maître écrit sur le bus I²C 
                               //  à l'esclave qui a l'adresse i
    //delay (1000);                           
                               
    master_write (i, commande);  //  maître écrit sur le bus I²C 
                               //  à l'esclave qui a l'adresse i
    //delay (1000);
 
                               
  
  
}


/////  Fonction d'envoi d'information du maître sur le bus I²C  /////
void  master_write  (int d, char * mess)  {
  
  Wire.beginTransmission(d); // transmit to device #d
  Wire.write(mess);        // sends 'd' bytes
  Wire.endTransmission();    // stop transmitting
  delay(500);
  
  
  
  
}

et l’esclave :

// Wire Slave Receiver
// by Nicholas Zambetti <http://www.zambetti.com>

// Demonstrates use of the Wire library
// Receives data as an I2C/TWI slave device
// Refer to the "Wire Master Writer" example for use with this

// Created 29 March 2006

// This example code is in the public domain.

//////////////////////////////////////////////////////////////////
//                                                              //
//          Test en I²C de réception de l'esclave               //
//                                                              //
//////////////////////////////////////////////////////////////////


#include <Wire.h>

char message[100];

char c;

void setup() {
  Wire.begin(1);                // join i2c bus with address #8
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);           // start serial for output
}

void loop() {
  delay(100);
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany) {
  
  int i = 0;
  
  while (1 < Wire.available()) { // loop through all but the last

    
    c = Wire.read(); // receive byte as a character

    
    
    message[i] = c;
    i++;

  }
 
  c = Wire.read();    // receive last byte as a character

  
  message[i] = c;
  Serial.println(message);         // print the message
  
  
  //delay (1000);
  

}

Pourtant j’ai bien un printLN à la fin du message mais rien n’y fait…

ou bien détecter la fin d’une trame et faire en sorte qu’il ne ré-écrive pas dessus ==> c’est peut-être avec mon “tampon” de ‘char message[100]’ que ça lui pose problème ?..

Salut Doc

Je te propose un petit saut dans le passé ICI

bricoleau: Tu veux faire beaucoup trop de choses dans receiveEvent() Cette fonction est appelée dans le cadre d'une interruption. Elle doit être la plus courte possible.

Elle doit donc : Lire la valeur reçue par un Wire.read(), et se contenter de stocker le résultat dans une variable globale sans le traiter tout de suite. Valoriser une seconde variable globale qui sert d'indicateur pour signaler qu'il y a quelque chose à traiter. Et rien d'autre, même pas un Serial.print et encore moins un delay()

Et dans le loop(), lorsqu'il y a quelque chose à traiter (c'est là que la valeur de la variable indicateur est utile), faire tout ce que tu as mis initialement dans receiveEvent().

Il faudrait surtout mettre une fin de chaine à la fin de la réception

message[i] = c;
  Serial.println(message);         // print the message

remplacé par

message[i] = c;
message[i+1] = 0; // marque la fin de la chaine
  Serial.println(message);         // print the message

D’accord, mais avant d’en arriver là, j’ai encore un autre souci; ce que j’appellerai un bug !!
J’ai fait en sorte de faire le moins de chose possibles dans l’interruption de réception d’informations sur le bus I²C géré par l’esclave; j’ai mis un flag dans la loop qui dit si une réception I²C a été reçue ou non en l’initialisant à zéro bien sûr et en le mettant à UN dès qu’il a traité l’info reçue.
Mais il ne peut pas la traiter puisque le flag de réception I²C qui est mis soit à 0 ou à 1, prends la valeur ‘111’ dès qu’il reçoit quelque chose sur le bus I²C; à comprends pas, moi, j’appelle ça un bug… ou c’est moi uqi bug…

l’esclave:

// Wire Slave Receiver
// by Nicholas Zambetti <http://www.zambetti.com>

// Demonstrates use of the Wire library
// Receives data as an I2C/TWI slave device
// Refer to the "Wire Master Writer" example for use with this

// Created 29 March 2006

// This example code is in the public domain.

//////////////////////////////////////////////////////////////////
//                                                              //
//          Test en I²C de réception de l'esclave               //
//                                                              //
//////////////////////////////////////////////////////////////////


#include <Wire.h>

char message[5];

char c;

int flagi2c = 0;

void setup() {
  Wire.begin(1);                // join i2c bus with address #8
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);           // start serial for output
}

void loop() {
  delay(100);
  
  Serial.print("flagi²c (dans loop) = ");
  Serial.println(flagi2c);
  
  
  if (flagi2c == 111)  {
  //if (flagi2c == 1)  {
    flagi2c = 0;    //  remise à zéro du flag I²C
    Serial.print("Une réception sur I²C a été reçue : ");
    Serial.println(message);         // print the message
  }
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany) {
  
  int i = 0;
  
  flagi2c = 1; // flag de réception sur I²C
  
  while (1 < Wire.available()) { // loop through all but the last

    
    c = Wire.read(); // receive byte as a character

    
    
    message[i] = c;
    i++;

  }
 
  c = Wire.read();    // receive last byte as a character

  
  message[i] = c;
  

}

==> je suis obligé de mettre le test de flag à 111 au lieu de 1 tout simplement, juste pour voir que j’ai bien réception du maître
En gros tout foinctionne comme il faut sauf que la variable ‘flagi2c’ ne devrait prendre que 0 ou 1 comme valeur mais là, elle est à 111 !!!

ERRATUM !!!

Je viens de m'apercevoir en relisant ma dernière question, que le tampon de réception du message était resté à 5, je l'ai surélevé à 100 et là, OK; la variable 'flagi2c' prends bien les valeurs 0 ou 1 selon si j'appuie sur le bouton du maître pour lui envoyer une trame de données ou non ...

==> j'devrais m'ouvrir un autoforum, ou un auto brainstorming ou un auto arrête tes conneries...

Merci à vous.