Co je to I2C sběrnice?

Co je to I2C sběrnice?

V některých návodech se v sekci zapojení vyskytuje výraz I2C sběrnice. V tomto článku se vám pokusím vysvětlit, co to I2C sběrnice je, a hlavně si ukážeme, proč ji u Arduina využíváme. O teorii si nebudeme povídat příliš, spíše nás bude zajímat, jak všechno reálně použít. Přesto si alespoň základní teoretické minimum říct musíme.

Sběrnici si můžeme představit jako dálnici. Na této dálnici jsou připojeny různé vjezdy a výjezdy. Samotná dálnice představuje vodiče sběrnice, zatímco vjezdy a výjezdy odpovídají vodičům periferií.

V reálném světě to u I2C vypadá tak, že k Arduinu (master) stačí připojit pouze dva vodiče, které zajistí komunikaci s dalšími periferiemi (slave). Díky tomu nemusíme každou periferii připojovat zvlášť k desce – stačí ji připojit ke sběrnici. To nám umožní ušetřit spoustu vodičů i pinů na desce.

Pokud je to pro vás stále nejasné, snad vám pomůže obrázek.

Obecné schéma zapojení I2C sběrnice

Ve schématu vidíme rezistory pull-up sloužící k zajištění klidového potenciálu na sběrnici. Ty však často nemusíme samostatně připojovat, protože bývají již zabudované v modulech periferií. Pokud by je periferie neobsahovaly, pak stačí použít rezistory externí.

Technické specifikace sběrnice I2C

  • Každé zařízení má unikátní I2C adresu (jak ji zjistit, si ukážeme níže).
  • I2C sběrnice vyžaduje pouze dva vodiče:
    • SDA – datový vodič
    • SCL – taktovací vodič
  • I2C sběrnice využívá 7bitové adresování, což umožňuje adresovat až 128 různých adres (0–127). Prakticky je však možné připojit až 112 zařízení, protože některé adresy jsou rezervovány pro speciální účely.
  • Architektura podporuje režim multi-master (více řídicích zařízení).
  • Množství přenášených dat není omezeno.
  • Standardní rychlosti I2C sběrnice jsou 100 kHz (Standard Mode), 400 kHz (Fast Mode) a 1 MHz (Fast Mode Plus). Některá zařízení podporují až 3,4 MHz (High-Speed Mode). Rychlost 5 MHz není běžně podporována.

Průběh komunikace na I2C sběrnici (krok za krokem)

  • Inicializace komunikace: Master (např. Arduino) zahájí komunikaci vysláním signálu START a zároveň pošle adresu konkrétní periferie (slave), se kterou chce komunikovat.
  • Detekce adresy: Všechna zařízení na sběrnici obdrží tuto adresu. Pouze zařízení, jehož adresa odpovídá, na ni zareaguje. Ostatní zařízení komunikaci ignorují.
  • Potvrzení připravenosti: Vybrané slave zařízení odešle potvrzení, že je připraveno přijímat data (ACK – acknowledge).
  • Přenos dat: Master postupně posílá data, která slave zařízení přijímá.
  • Ukončení komunikace: Po odeslání všech dat vyšle master signál STOP, čímž ukončí komunikaci a sběrnice se uvolní pro další použití.

Zapojení I2C do Arduina

Jak jsem již zmínil, I2C sběrnice vyžaduje pouze dva vodiče. Ty však nemůžeme zapojit do libovolných pinů na desce – je nutné je připojit ke speciálním pinům určeným právě pro I2C. Aby to bylo ještě zajímavější, tyto piny se liší podle typu desky. Níže najdete jednoduchý přehled.

Deska SDA (datový) SCL (taktovací)
Arduino Uno A4 A5
Arduino Nano A4 A5
Arduino Mega 2560 20 21
Arduino Leonardo 2 3
Arduino Due 20 21
ESP8266 (např. NodeMCU) D2 (GPIO4) D1 (GPIO5)
ESP32 GPIO21 GPIO22
Arduino Uno R4 Minima A4 A5
Arduino Uno R4 WiFi A4 A5

 

Poznámka: Na deskách Uno, Nano a Mega jsou piny SDA/SCL často navíc vyvedeny i na samostatné konektory poblíž napájecího konektoru (značené jako SDA/SCL).

I2C adresa

Konečně se dostáváme k adrese – právě pomocí ní Arduino pozná, se kterou periferií na sběrnici komunikuje. Tato adresa se následně zapisuje do programu.

Pokud používáme I2C sběrnici pouze s jednou periferií, není vždy nutné adresu do programu explicitně zapisovat. Jakmile však připojíme dvě nebo více periferií, je určení adresy nezbytné.

I2C adresu zjistíme velmi jednoduše

Stačí stáhnout jednoduchý skenovací kód, nahrát ho do Arduino desky, připojit periférii a otevřít sériový monitor. Adresa připojeného zařízení se zobrazí přímo v monitoru.

    #include <Wire.h>
     
     
    void setup()
    {
      Wire.begin();
     
      Serial.begin(9600);
      while (!Serial);             
      Serial.println("\nI2C Scanner");
    }
     
     
    void loop()
    {
      byte error, address;
      int nDevices;
     
      Serial.println("Scanning...");
     
      nDevices = 0;
      for(address = 1; address < 127; address++ )
      {
        Wire.beginTransmission(address);
        error = Wire.endTransmission();
     
        if (error == 0)
        {
          Serial.print("I2C device found at address 0x");
          if (address<16)
            Serial.print("0");
          Serial.print(address,HEX);
          Serial.println("  !");
     
          nDevices++;
        }
        else if (error==4)
        {
          Serial.print("Unknown error at address 0x");
          if (address<16)
            Serial.print("0");
          Serial.println(address,HEX);
        }    
      }
      if (nDevices == 0)
        Serial.println("No I2C devices found\n");
      else
        Serial.println("done\n");
     
      delay(5000);           
    }
 

 

Výstup by měl vypadat nějak takte, adresa mého zařízení je tedy 0x27

Zjištění I2C adresy zařízení - Arduino návody

Příklad pro I2C

Nakonec si ukážeme příklad. Z nějakého důvodu potřebujeme poslat zprávu z jedné Arduino desky do druhé – a k tomu použijeme I2C sběrnici. Z první desky, která bude v roli slave, budeme odesílat textovou zprávu. Druhá deska, nastavená jako master, tuto zprávu přijme a zobrazí. Nicméně v I2C komunikaci iniciuje přenos vždy master zařízení to znamená master nejprve vyslat požadavek na čtení.

Protože spolu komunikují pouze dvě zařízení, nemusíme řešit specifické adresování. Stačí desky správně propojit podle schématu.

Schéma zapojení příkladu s I2C sběrnicí

Program pro master, tudíž přijímací desku bude vypadat takto:

// master - reader

// importování knihovny
#include <Wire.h>

void setup()
{
  // inicializace I2C komunikace
  Wire.begin();    
  // inicializace sériové komunikace   
  Serial.begin(9600);  
}

void loop()
{
  // vyžádáme si 11 bytů z adresy 5
  Wire.requestFrom(5, 11);    

  // pokud slave něco pošle, tak zprávu znak po znaku přečteme
  while (Wire.available())
  { 
    // přečte se znak
    char c = Wire.read(); 
    // a ten se vytiskne
    Serial.print(c);         
  }

  delay(500);
}

 

 Program pro slave, tedy odesílatele bude vypadat následovně:

// slave - sender

// imporotvání knihovny
#include <Wire.h>

void setup()
{
  // připojení na I2C s adresou 5
  Wire.begin(5);
  // pokud si slave vyžadá, tak se sepne funkce "request event"                
  Wire.onRequest(requestEvent); 
}

void loop()
{
  delay(100);
}

// vlastní funkce, která když bude volaná, tak
void requestEvent()
{
  // pošle zprávu
  Wire.write("HW kitchen "); 
  // z funkce se vlastně nedostaneme, proto bude běhat pořád dokola 
}
 

 

Závěr článku o I2C

Tímto jsme si představili základní principy fungování I2C sběrnice. Je velmi pravděpodobné, že se s ní dříve nebo později setkáte. Pokud máte jakékoli dotazy nebo něčemu nerozumíte, napište nám do komentářů. Můžete se také podívat na další návody z naší dílny.

Znalosti a zkušenosti se sběrnicí I2C můžete dále prohloubit například na následujících projektech: