Bonjour,
Comment faire pour savoir si le bus I2C est libre ou en cours d'utilisation ?
Merci de vos réponses
Cordialement
Tout dépend de la qualité du code qui gère l'I2C.
La norme I2C prévoit des "arbitrages" quand plusieurs maîtres sont présent sur le bus et que 2 veulent parler simultanément.
Pour plus de détails voir :http://www.nxp.com/documents/user_manual/UM10204.pdf
Je pense que ta question est : est-ce que la bibliothèque arduino gère intégralement la norme I2C.
Malheureusement je ne sais pas ou trouver la réponse.
En fait, j'ai un arduino maitre, et 2 esclaves qui s' echangent des donnees, jusque la pas, de prb, le bus est bien equilibre au niveaux des resistances de pull up, je regarde mes trames a l'analyseur et elles sont ok mais je dois afficher des donnees sur un module lcd 1602 i2c qui par contre lui a ses trames qui s' integre dans celles qui sont en cours de transmission donc cela provoque des caracteres bizarres sur l'ecran du lcd i2c. Je voudrais integrer avant d'envoyer les trames au lcd une fonction qui verifie que le bus est libre avant d'envoyer sinon il doit attendre la fin de la trame i2c precedente pour transmettre mais je ne vois pas comment mettre cela en place...
Un petit coup de main svp
Cordialement
Bonjour,
Normalement, si il n'y a qu'un maitre sur le i2c, cela ne doit pas poser de problèmes...
Chaque esclave a bien une adresse unique?
Pierre
bonjour,
oui bien sur chacun a une adresse unique...
oui mais comme il y a des requêtes qui interroge les 2 esclaves toutes les 200mS, si il y a une action de l'utilisateur sur un clavier, le lcd print génère une trame i2C car c'est un module basé sur un pcf8574A et cette requête se fait aléatoirement. Par moment ça passe mais des moments ça se mélange avec une autre trame i2C et la c'est le bordel...
lcd print génère une trame i2C car c'est un module basé sur un pcf8574A
Bonjour,
ceci est impossible car le pcf8574 est un pur esclave (voire le plus pur d'entre eux !). La seule chose qu'il puisse générer spontanément c'est un signal d'interruption sur une ligne dédiée, mais rien sur les lignes i2c, sauf à y être cordialement invité
Bonjour,
Le prb est que les trames I2C générées pour afficher sur le LCD, se mélangent avec celles qui tournent toutes les 200 mS...
voila ce que j'ai pour l'envoie I2C de mes trames de transmission esclave:
volatile byte Buffer_Reception[BUFFER_LENGTH];//BUFFER_LENGTH defini dans Wire.h
volatile byte Nb_Octets_A_Traiter = 0;
volatile unsigned long Nb_Octets_Perdus = 0;
void setup() {
// Initialisation de l'I2C.
mySUI.println(F("***********************"));
mySUI.println(F("Module Esclave"));
mySUI.print(F("Adresse du Module Esclave: 0x"));
Serial.println(Adresse_I2C_Esclave_Clavier_1,HEX);
mySUI.println(F("***********************"));
Wire.begin(Adresse_I2C_Esclave_Clavier_1); // Activate I2C network
Wire.onReceive(Receive_Event);
Wire.onRequest(Request_Event);
}
void loop() {
// Traitement de la receptions d'octets en I2C
if (Nb_Octets_A_Traiter > 0) Traiter_Reception_I2C();
Analyse_Etat_Centrale();
}
void Receive_Event(int HowMany)
{
if (Nb_Octets_A_Traiter == 0) //buffer de reception dispo, sinon destruction du message sans traitement
{
while (Nb_Octets_A_Traiter < sizeof(Buffer_Reception) && Nb_Octets_A_Traiter < HowMany)
{
Buffer_Reception[Nb_Octets_A_Traiter++] = Wire.read();
}
}
while (Wire.available())
{
// wdt_reset(); // Resette le WatchDog
Nb_Octets_Perdus++;
Wire.read();
}
} // Fin du void Receive_Event(int howMany)
void Request_Event()
{
// Variables a envoyer lors d'une requete I2C recue par le Maitre
///////////////////////////////////////////////////////////////////////
// Variables a envoyer lors d'une requete I2C recue par le Maitre
Variable_Requette_Esclave_1[0] = Adresse_I2C_Esclave_Clavier_1;
Variable_Requette_Esclave_1[1] = Adresse_I2C_Maitre_Centrale_Bureau;
Variable_Requette_Esclave_1[2] = Etat_Clavier_1_I2C;
Variable_Requette_Esclave_1[3] = Etat_Alarme_Clavier_1_I2C;
///////////////////////////////////////////////////////////////////////
} // Fin du void Request_Event()
void Traiter_Reception_I2C()
{
//Transfert des octets a traiter dans des variables locales
Nb = Nb_Octets_A_Traiter;
for (byte i = 0; i < Nb; i++)
{
// wdt_reset(); // Resette le WatchDog
Buffer_Traitement[i] = Buffer_Reception[i];
}
Nb_Octets_A_Traiter = 0; // A partir de la , le buffer de reception est dispo
// pour enregistrer tout nouveau message entrant
//Traitement effectif du message a partir des variables locales
//...
if (Buffer_Traitement[0] == Adresse_I2C_Maitre_Centrale_Bureau) // Confirmation qu'il s'agit bien d'un ordre de la centrale
{
if (Buffer_Traitement[1] == Adresse_I2C_Esclave_Clavier_1) // Confirmation qu'il s'agit bien de l'ordre pour l'esclave 1
{
if (Buffer_Traitement[2] == 0x01) // Confirmation de l'etat de la centrale
{
Octet_Centrale_Maitre_Recu_2 = 0x01; // Etat de la centrale
} // Fin du if (Buffer_Traitement[2] == 0x01)
else if (Buffer_Traitement[2] == 0x00)
{
Octet_Centrale_Maitre_Recu_2 = 0x00; // Etat de la centrale
} // Fin du else if (Buffer_Traitement[2] == 0x00)
} // Fin du if (Buffer_Traitement[1] == Adresse_I2C_Esclave_Clavier_1)
} // Fin du if (Buffer_Traitement[0] == Adresse_I2C_Maitre_Centrale_Bureau)
} // Fin du void TraiterReception()
void Analyse_Etat_Centrale()
{
//On désactive les interruptions, afin de ne pas boucler
//cli();
if (Buffer_Traitement[0] == Adresse_I2C_Maitre_Centrale_Bureau)
{
if (Buffer_Traitement[1] == Adresse_I2C_Esclave_Clavier_1)
{
if (Buffer_Traitement[2] != Old_Buffer_Traitement[2]) // Si la variable est differente de l'etat precedent
{
if (Buffer_Traitement[2] == 0x01)
{
lcd.clear(); // clear display, set cursor position to zero
lcd.setCursor(0, 0); // 1ere colonne,1ere ligne
lcd.print("Alarme Domotique");
delay(1);
lcd.setCursor(0, 1); // 1ere colonne,2eme ligne
lcd.print(" Systeme Arme ");
delay(1);
} // Fin du if (Buffer_Traitement[2] == 0x01)
else if (Buffer_Traitement[2] == 0x00)
{
lcd.clear(); // clear display, set cursor position to zero
lcd.setCursor(0, 0); // 1ere colonne,1ere ligne
lcd.print("Alarme Domotique");
delay(1);
lcd.setCursor(0, 1); // 1ere colonne,2eme ligne
lcd.print(" Systeme Desarme");
delay(1);
} // Fin du else if (Buffer_Traitement[2] == 0x00)
} // Fin du if (Buffer_Traitement[2] != Buffer_Traitement[2])
} // Fin du if (Buffer_Traitement[1] == Adresse_I2C_Esclave_Clavier_1)
// wdt_reset(); // Resette le WatchDog
Old_Buffer_Traitement[2] = Buffer_Traitement[2];
} // Fin du if (Octet_A_Traiter[0] == Adresse_I2C_Maitre_Centrale_Bureau)
//On active le support des interruptions
//sei();
} // Fin du void Analyse_Etat_Centrale
Ton écran LCD à commande I2C, il reçoit ses ordres de qui ?
D'un périphérique esclave présent sur le même bus I2C ?
Oui
Aïe
Donc ton périphérique se comporte tantôt comme un esclave, tantôt comme un maître (vis à vis du LCD).
Basiquement, un bus I2C est fait pour un seul maître et plusieurs esclaves.
C'est le maître qui distribue le temps de parole.
En théorie, le protocole I2C permet à plusieurs maîtres de partager le même bus (ou à un composant d'être tantôt maître, tantôt esclave).
Je ne sais pas si c'est réalisable facilement avec la bibliothèque Wire intégrée à l'IDE arduino.
Si ça l'est, il faut probablement que tu jongles avec les Wire.begin() pour changer de rôle
merci pour cette bonne info, celle que c'est le maitre qui doit s'adresser aux LCD... Je vais revoir mon programme afin que ce soit juste le maitre qui envoi les données aux LCD...
Pour le moment, j'avais réussi a stabiliser les lcd en utilisant ce code avant d'utiliser un print.lcd
Label_1:
if(Wire.available() == 0) // Si I2C libre alors on peut afficher sur le LCD
{
lcd.clear(); // clear display, set cursor position to zero
lcd.setCursor(0, 0); // 1ere colonne,1ere ligne
lcd.print("Alarme Domotique");
delay(1);
lcd.setCursor(0, 1); // 1ere colonne,2eme ligne
lcd.print(" Systeme Arme ");
delay(1);
} // Fin du if(Wire.available() > 0)
else // Sinon on attend et on recommence
{
delayMicroseconds(50);
goto Label_1;
} // Fin du else
Une autre question:
J'utilise un capteur optique d'empreintes digitales sur mes esclaves, celui ci a besoin d'un port série dédié en temps réel, se que ne sait pas faire la librairie serialSoftware, je suis donc obligé d'utiliser la com qui viens du FTDI (car carte mini) mais j'ai besoin d'utiliser ce même port pour utiliser une interface serial... Comment puis je faire pour utiliser l'interface serie avant l'utilisation du finger print en temps réel ?
ton périphérique se comporte tantôt comme un esclave, tantôt comme un maître
Bonjour,
c'est quoi au juste, ce périphérique ?
Comment puis je faire pour utiliser l'interface série
2 solutions hard :
- utiliser un Leonardo, dont le port série est entièrement disponible
- raccorder un 2ème mini à l'i2c, qui fait l'interface avec le capteur (lourd ...)
A priori je dirais que c'est gérable avec Wire, au niveau d'un arduino (mini) qui se comporterait tantôt comme un maître, tantôt comme un esclave.
Pas sûr de moi à 100%, mais :
Un Wire.begin() permet de passer en maître.
Un Wire.begin(adresse) permet de passer en esclave, avec peut-être les routines onReceive et onRequest à redéclarer à chaque fois.
Dans tous les cas, un esclave ne parle que si un maître le lui a demandé par un requestFrom
Et lorsqu'un maître initie une communication avec un esclave (dans un sens ou dans l'autre), les primitives twi utilisées vérifient que le bus est libre avant de prendre la main.
Donc en théorie, avec un code correct, il ne devrait pas y avoir de conflit sur le bus, même avec plusieurs maîtres.
Par contre, le problème est que le maître qui veut parler peut attendre éternellement que le bus soit libéré, car les bibliothèques fournies avec arduino n'intègrent aucun timeout.
C'est une cause de blocage régulièrement rencontrée (chercher "endTransmission hangs") en cas d'anomalie électrique sur le bus, lorsque SDA et/ou SCL est maintenue à 0V (connexion parasite, absence de pull up etc.)
Dans ce cas, même avec un seul maître, celui-ci peut croire que le bus est occupé par un autre et freezer.
A mon sens, le coupe Wire / twi en fait trop ou pas assez, ce qui induit cette vulnérabilité aux montages foireux. Un timeout serait le bienvenu pour ne plus avoir de risque de freeze, ou bien les fonctionnalités proposées pourraient exclure la gestion multi-maîtres, ce qui satisferait certainement la très grande majorité des arduinistes.
J'ai déjà regardé, mais pas eu le courage de m'attaquer à ces libs pour les rendre plus robustes (quitte à virer la gestion multi-maître dont je n'ai pas besoin).
Par contre, maintenant j'ajoute systématiquement un watchdog dès que j'utilise l'I2C.
(et pareil pour les libs ethernet / w5100, contre lesquelles j'ai aussi des griefs similaires :D)
Mais bon, c'est juste une pauvre solution permettant de contourner le problème.
Merci a tous pour vos réponses....
J'ai tout de même avancé dans mes problèmes. J'ai modifier le soft maitre afin que ce soit lui qui pilotes les 2x LCD esclaves.
Pour la gestion du port série Hard, j'ai modifié la fonction setup en la faisant boucler le temps d'utiliser mon interface de configuration de l'esclave. J'utilise le port serie Hard pour 2 choses, la 1ere pour pouvoir configurer mon esclave et la 2eme pour commander un lecteur optique de reconnaissance d'empreintes digitales. donc comme je boucle dans le setup, je peux modifier des variables au démarrage, ce qui me suffit car ces variables servent a enregistrer ou effacer des empreintes et une fois terminé, je découple le bouclage afin que se soit le lecteur optique qui prend la relève. Ca marche, pour le moment, il ne me reste plus qu'a modifier la tempo du bouclage le temps que j'utilise le menu serial...
En tout cas merci a vous, je n'avais pas pensé a faire la commande des lcd esclaves par le maitre, ce qui me change de beaucoup de choses comme des caractères bizarres qui apparaissaient par moment et la fonction serial menu qui en était perturbée...
