Vernetzung zweier Mikrocontroller über I2C-Bus



Der I2C-Bus . . .

  • ist ein zweiadriger Bus, bestehend aus Taktleitung (SCL) und Datenleitung (SDA)

  • I²C, für englisch Inter-Integrated Circuit

  • im Deutschen gesprochen als: "I-Quadrat-C" oder "I-Zwo-C"

  • im Englischen: "I-Squared-C" oder  "I-Two-C"

  • Atmel nennt ihn "TWI"

  • ist als Master-Slave-Bus konzipiert

  • Der Master sendet und ein Slave reagiert darauf. Oder ein Master fragt und ein Slave antwortet darauf.

  • Mehrere Slaves (standard: 112  / max: 1136) aber auch (seltener) mehrere Master sind möglich.
    Jeder Slave hat eine eigene Adresse.

  • Geschwindigkeit: von 100 kbit/s (Standard Mode) bis 3,4 Mbit/s (High Speed Mode)





Experiment 1:

Arduino1 (Master) sendet an Arduino2 (Slave) eine Information über I2C-Bus.
Was soll passieren?

  • Arduino 1 (Master) bekommt über den Seriellen Monitor ein H oder ein L eingegeben

  • dieses L oder H sendet er an Arduino 2 (Slave)

  • Arduino 2 reagiert darauf mit an/aus seiner LED an Pin 13 (das ist seine On-Board-LED)


Bauen Sie folgende Schaltung auf:



Lade folgenden Code in den Master:

#include <Wire.h> //I2C-Bibliothek

void setup(){
  Serial.begin(9600);
  Wire.begin(); //I2C-Aktivierung
}

void loop(){
  while( Serial.available() ) {
    char c = Serial.read();
   
    if(c == 'H') {
      Wire.beginTransmission(5); //I2C: an Adresse 5 senden
      Wire.write('H');
      Wire.endTransmission();
    }
    else if(c == 'L') {
      Wire.beginTransmission(5);
      Wire.write('L');
      Wire.endTransmission();
    }
  }
}


Lade folgenden Code in den Slave:

#include <Wire.h>

void setup(){

  //I2C-Adresszuweisung: Slave 5 
  Wire.begin(5);

  //Handler für das I2C-Empfangsereignis festlegen (siehe unten)
  Wire.onReceive(receiveEvent);
 
  pinMode(13,OUTPUT); digitalWrite(13,LOW); // Bord-LED
}


void loop(){} // derzeit nix drin hier (siehe unten)


void receiveEvent(int howMany){
  while(Wire.available())
  {
    char c = Wire.read();
   
    if(c == 'H')
    {
      digitalWrite(13,HIGH);
    }
    else if(c == 'L')
    {
      digitalWrite(13,LOW);
    }
  }
}


Weshalb ist hier nichts in der loop()?

In der loop() könnte gewöhnlicher Quelltext stehen, der wie immer abgearbeitet werden würde..

Die Funktion bzw. Methode receiveEvent()ist ein sogenannter Ereignis-Handler (auch: Event-Handler).
Diese Funktion bzw. Methode wird immer dann ausgeführt, wenn ein Datenpaket über I2C angekommen ist.

Stünde in der loop() Quelltext, der abgearbeitet wird, wird diese Abarbeitung kurz unterbrochen, wenn ein Empfangsereignis statt fand. Eine solche Unterbrechung nennt man "Interrupt".






Experiment 2:

Arduino1 (Master) empfängt von Arduino2 (Slave) Daten über I2C-Bus

Was soll passieren?

  • Arduino 1 (Master) fragt Daten von Arduino 2 (Slave) ab

  • diese Daten gibt der Master im Seriellen Monitor aus

Die Schaltung ist dieselbe, wie im 1. Experiment:




Lade folgenden Code in den Master:

//i2c Master Code
#include <Wire.h>

void setup()
{
  Wire.begin();
  Serial.begin(9600);
 
  Wire.requestFrom(5,10); //Adesse:5, Anzahl der Zeichen: 10
 
  while(Wire.available())
  {
    char c = Wire.read();
    Serial.print(c);
  }
}


void loop()
{
    // hier steht jetzt mal nix
}



Lade folgenden Code in den Slave:

//i2c Slave Code
#include <Wire.h>

void setup()
{
  Wire.begin(5);
  Wire.onRequest(requestEvent);
}

void loop()
{
  delay(100);
}

void requestEvent()
{
  Wire.write("1234567890");// diese Daten sollen übermittelt werden
}




Mögliche Denkansätze und Aufgaben:

•    ein weiterer Slave soll hinzugefügt werden

•    Nutzen von Slaves als Porterweiterungen (digital/analog In/Out)

•    Nutzen von Slaves als LCD- und andere Ausgabeeinheiten