Arduino 15arduino_goodfields_64.jpgdécouverte du bus I2C
 
Sommaire

Deux  ARDUINO en dialogue Deux ARDUINO en dialogue Interface  3,3V vers 5V Interface 3,3V vers 5V Prenons  un exemple Prenons un exemple
MAITRE MAITRE ESCLAVE ESCLAVE Discussion  sur le sens maître-esclave Discussion sur le sens maître-esclave
Idée pour multi-esclaves de la station Météo Idée pour multi-esclaves de la station Météo
La page principale ... La page principale ...
   
Vers le début Vers Page 2 Vers sommaire Deux ARDUINO en dialogue
Le bus I2C (voir pour débuter http://arduino.cc/en/Reference/Wire) permet de faire communiquer des modules ensemble. Ces modules peuvent être des actionneurs(circuit de multiplexage de 7 segments), des catpeurs (BMP085 pour pression atmosphérique, mais aussi des ARDUINO.

Ce bus comprend 2 fils : SDA pour les datas et SCL pour l'horloge (clock). Il peut admettre jusqu'à 128 esclaves, et un nombre quelconque de maîtres, la limitation est la capacité de ligne, maximum à 400pF, ce qui en fait limite la LONGUEUR de ce bus à environ 7 mètres. Le maître est le module qui initie l'échange et contrôle l'horloge, l'esclave attend des ordres et répond au sollicitations du maître.

Les maîtres ont pour adresse 0. Les esclaves de 1 à 128. Lorsqu'il y a plusieurs maîtres, ils interrogent à volonté les esclaves, chacun à leur tour. La vitesse du bus est assez élevé (100 à 400 kbits/seconde), ce qui permet des échanges assez nourris ...

Par contre, les esclaves ne peuvent pas converser entre eux : on est obligé de demander au maître de retransmettre ... C'est possible !

En pratique, il suffit de relier les broches A4 et A5 entre les 2 ARDUINO, la masse étant commune, le 5V aussi si besoin. Il faut installer aussi 2 résistances de 4,7kOhms entre ces 2 fils de bus et le +5Volts (résistances de tirage).
Les broches A4 et A5 sont d'ailleurs "dupliquées" sur les ARDUNINO UNO R3, après les broches 12,13,GND et Aref.

   
Vers le début Vers Page 2 Vers sommaire Interface 3,3V vers 5V
Certains modules I2C sont en 3,3V. Il faut alors intercaler une interface telle que celle-ci :
cliquez pour agrandir : photo/15_interface_3-3_5.gif Interface entre modules 5V et 3,3V
I2C_interface_3-3_5_an97055.pdf I2C_interface_3-3_5_an97055.pdf
On peut envisager d'avoir une ligne en 12 Volts avec ce type d'interafce. CEci pour améliorer l'immunité et peur-être la portée ?
Pour augmenter la distance, on peut interfacer avec des convertisseurs RS485.

   
Vers le début Vers Page 2 Vers sommaire Prenons un exemple
Un ARDUINO possède une horloge précise (DS1307 ou horlge DCF-77), il veut envoyer son heure toutes les secondes à des afficheurs.
   
Vers le début Vers Page 2 Vers sommaire MAITRE
Pour le maître, partant du programme 14, j'ai ajouté les lignes suivantes pour obtenir _15_I2C_maitre.ino :
//**********************************************************
// DECLARATIONS
// *** Bus I2C ***
#include <Wire.h>
...
//**********************************************************
// INITIALISATIONS
void setup() {
...
// Bus I2C
 Wire.begin();    // initialisation en maitre (A4=SDA et A5=SCL)
...
//**********************************************************
// PROGRAMME PRINCIPAL
void loop() {
...
// opérations à chaque seconde
  if (top_1000ms) {
    top_1000ms = false;
    tours_ps=tours; tours=0;
// I2C vers ARDUINO No 1
   Wire.beginTransmission(0x01);    // autre Arduino en 1
// préparation du message de type "Tyymmjjhhmmss"
   memset (valueff,'\0',15); strcat( valueff, "T" );
   i = year(); if (i >= 2000) { i-=2000; } else { i-=1900; }
   dtostrf(i,2,0,valuef); strcat( valueff, valuef );
   dtostrf(month(),2,0,valuef); strcat( valueff, valuef );
   dtostrf(day(),2,0,valuef); strcat( valueff, valuef );
   dtostrf(hour(),2,0,valuef); strcat( valueff, valuef );
   dtostrf(minute(),2,0,valuef); strcat( valueff, valuef );
   dtostrf(second(),2,0,valuef); strcat( valueff, valuef );
// envoi
   Wire.write(valueff);
// fin de transmission
   i = Wire.endTransmission();
   if (i == 0) Serial << "Wire OK=" << valueff << "=" << endl;
   if (i != 0) Serial << "Wire ERREUR code=" << i << endl;
  }
...
   
Vers le début Vers Page 2 Vers sommaire ESCLAVE
Pour l'esclave, j'ai fait un simple programme qui gère un LCD, affiche en prmière ligne le message recu, et en seconde ligne le nombre de tours du CPU.
Remarquez dans le Setup() la programmation qui, sur réception, déroute vers le sous-programme "receiveEvent" :
Wire.onReceive(receiveEvent); // register event

#define version "15_I2C_esclave"
//**********************************************************
// BIBLIOTHEQUES
// incluses dans le package Arduino de base
// *** LCD *** afficheur LCD
#include <LiquidCrystal.h>  // LCD
//  LiquidCrystal lcd(RS, Enable,  D4, D5, D6, D7)
  LiquidCrystal lcd(4, 2, 6, 7, 8, 9);

// ajoutées
// *** GENERAL *** formatage des entrees sorties ASCII
#include <Streaming.h>

// *** Bus I2C ***
#include <Wire.h>
int icol;
byte c;
char bufr[15];

// *** GENERAL *** 
// speedomètre = calcul de vitesse ...
unsigned long tours_ps,tours,tours_led;
#define led_a 13

//**********************************************************
// INITIALISATIONS
void setup() {
// initialize the pins
  pinMode(led_a, OUTPUT);
  digitalWrite(led_a,HIGH);

// définition taille du LCD :
  lcd.begin(16, 2);
// annonce version
  lcd.clear(); lcd.setCursor(0, 0); lcd << version; 

// ligne série (pour traces)
  Serial.begin(9600);  // ou 9600 selon votre port COM
  Serial << "Serial ok " << version << endl;

// Bus I2C
 Wire.begin(0x01);    // initialisation en esclave (A4=SDA et A5=SCL)
 Wire.onReceive(receiveEvent); // register event

  delay(2000);
  lcd.clear();
  } // Fin du SETUP
//**********************************************************
// PROGRAMME PRINCIPAL
void loop() {

// compte-tours par seconde et led_a "heart-beat" commutée
  tours++;  tours_led++;
  if (tours_led >= 10000) { tours_led = 0 ;  digitalWrite(led_a,HIGH); } // allumage led // digitalWrite(led_a, !digitalRead(led_a)); } 
  if (tours_led == 250) digitalWrite(led_a, LOW); // extinction led  
  if (tours_led == 0) { 
    lcd.setCursor(0, 0); lcd << bufr;
    lcd.setCursor(0, 1); lcd << tours << " " << icol << "  "; 
  }
}

// I2C
// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
  while(Wire.available()) // loop through all but the last
  {
    char c = Wire.read(); // receive byte as a character
    icol++; if (icol > 15) icol=0;
    if (c=='T') icol=0;
    bufr[icol]=c;
  }
//  int x = Wire.read();    // receive byte as an integer
//  Serial.println(x);         // print the integer
}
   
Vers le début Vers Page 2 Vers sommaire Discussion sur le sens maître-esclave
Dans notre idée de "station horaire et météo", on peut se demander dans quel sens attribuer le MAITRE. A priori, on pourrait penser que la station météo soit ESCLAVE, comme une "super-capteur", et que tous les utilisateurs viennent récupérer les données quand ils en ont besoin. Mais, les horloges temps réelles telles que les DS1302,6,7 et les capteurs tel le BMP085(pression-température) sont eux-mêmes esclaves. Il faut donc que notre station météo soit MAITRE, et distribue ses informations aux esclaves utilisateurs ...

 
Idée pour multi-esclaves de la station Météo
// Etablir une table d'adresses d'esclaves probables :
int meteo_esclave = {1,2,3,4,5}, meteo_nb=5;
// Tenter d'envoyer les données, si code=erreur mettre l'adresse en négatif
for (i=0;i<meteo_nb,i++) {
// si esclave Ok, ou 1 fois de temps en temps si pas ok
 if (meteo_esclave[i] > 0 || abs(meteo_esclave[i]) == second() ) {
// envoi des datas
  ...
   Wire.write(valueff);
// fin de gtransmission
   i = Wire.endTransmission();
   if (i != 0) { meteo_esclave[i] = -abs(meteo_esclave[i]); } else { meteo_esclave[i] = abs(meteo_esclave[i]); }
 }
}

la suite ... la suite ... La page principale ... La page principale ...

Photos de la page :

Dernière mise à jour : 11:40:02 18/09/2020