Arduino doskonale nadaje się do pracy z magistralą I2C, ponieważ obsługuje ją sprzętowo i udostępnia wygodną bibliotekę Wire. Za pomocą tylko dwóch linii sygnałowych można podłączyć wiele czujników, wyświetlaczy i innych modułów. Linia SDA przesyła dane, natomiast SCL odpowiada za sygnał zegarowy.
Co to jest I2C i dlaczego jest tak popularne w Arduino?
Magistrala I2C (Inter-Integrated Circuit) to szeregowy interfejs służący do komunikacji między układami cyfrowymi. Mikrokontroler może za jego pomocą wymieniać dane z czujnikami, pamięciami, wyświetlaczami i innymi mikrokontrolerami.
Najważniejsze cechy magistrali I2C to:
- Dwie linie sygnałowe – do komunikacji służą wyłącznie SDA i SCL;
- SDA – dwukierunkowa linia danych Serial Data;
- SCL – linia zegarowa Serial Clock, zazwyczaj sterowana przez kontroler;
- Wiele urządzeń – do wspólnych linii można podłączyć wiele układów, o ile mają różne adresy;
- Adresowanie 7-bitowe – zapewnia 128 wartości adresowych, z których zwykle około 112 można przeznaczyć dla urządzeń;
- Adresowanie 10-bitowe – rozszerza przestrzeń adresową do 1024 wartości.
W typowej konfiguracji Arduino działa jako kontroler: rozpoczyna transmisję i generuje sygnał zegarowy. Czujnik, wyświetlacz lub drugi mikrokontroler pełni funkcję urządzenia peryferyjnego i odpowiada na żądania kontrolera.
Jak fizycznie działa magistrala I2C?
Linie SDA i SCL oraz logika otwartego drenu
Linie SDA i SCL wykorzystują wyjścia typu otwarty dren lub otwarty kolektor. Urządzenie może ściągnąć linię do masy, wymuszając stan niski, albo przejść w stan wysokiej impedancji i ją zwolnić. Nie wymusza natomiast bezpośrednio stanu wysokiego.
Z tego powodu każda linia I2C wymaga rezystora podciągającego do odpowiedniego napięcia zasilania. Gdy żadne urządzenie nie ściąga linii do masy, rezystor ustala na niej stan wysoki.
Najczęściej stosuje się rezystory o wartości od 1 do 10 kΩ, a popularnym wyborem jest 4,7 kΩ. Wartość należy dobrać do napięcia, częstotliwości magistrali, długości przewodów i całkowitej pojemności połączeń.
Większość gotowych modułów I2C ma już własne rezystory podciągające. Przy podłączaniu kilku modułów należy sprawdzić ich łączną rezystancję, ponieważ rezystory połączone równolegle mogą nadmiernie obciążyć urządzenia podczas wymuszania stanu niskiego.
Piny I2C na różnych płytkach Arduino
Rozmieszczenie linii SDA i SCL zależy od modelu płytki. Najpopularniejsze warianty przedstawia tabela:
| Płytka | SDA | SCL | Uwagi |
|---|---|---|---|
| Arduino UNO | A4 | A5 | linie są również dostępne na osobno opisanych wyprowadzeniach SDA i SCL |
| Klasyczne Arduino Nano | A4 | A5 | należy sprawdzić wariant płytki i użyty mikrokontroler |
| Arduino Mega 2560 | 20 | 21 | linie są także wyprowadzone na piny opisane jako SDA i SCL |
| Nowsze płytki Arduino | zależnie od modelu | zależnie od modelu | mogą udostępniać osobne złącza lub więcej niż jedną magistralę |
Przed wykonaniem połączeń należy sprawdzić dokumentację konkretnej płytki oraz opis biblioteki Wire dla używanego rdzenia Arduino.
Jak podłączyć pojedyncze urządzenie I2C do Arduino?
Typowy moduł I2C wymaga czterech połączeń:
- VCC – zasilanie 5 V lub 3,3 V, zależnie od wymagań modułu;
- GND – wspólna masa układu;
- SDA – linia danych;
- SCL – linia zegarowa.
Przykładowe połączenie modułu z Arduino UNO wygląda następująco:
| Pin modułu | Pin Arduino UNO |
|---|---|
| VCC | 5V lub 3.3V, zgodnie z dokumentacją modułu |
| GND | GND |
| SDA | A4 lub pin opisany jako SDA |
| SCL | A5 lub pin opisany jako SCL |
Podstawowa zasada brzmi: SDA łączymy z SDA, SCL z SCL, GND z GND, a VCC z napięciem odpowiednim dla danego modułu.
Jak podłączyć wiele urządzeń I2C do jednej magistrali?
Jedną z największych zalet I2C jest możliwość podłączenia wielu urządzeń do wspólnych linii SDA i SCL.
Topologia połączeń
Wszystkie urządzenia należy dołączyć równolegle:
- SDA – linie SDA wszystkich urządzeń należy połączyć z pinem SDA Arduino;
- SCL – linie SCL wszystkich urządzeń należy połączyć z pinem SCL Arduino;
- VCC – każdy moduł należy zasilić napięciem zgodnym z jego wymaganiami;
- GND – wszystkie urządzenia muszą mieć wspólną masę z Arduino.
Na płytce stykowej przewody SDA powinny tworzyć jedną wspólną linię, a przewody SCL drugą. Zasilanie należy rozprowadzić zgodnie z wymaganiami poszczególnych urządzeń.
Każde urządzenie na magistrali powinno mieć unikalny adres, a poziomy logiczne wszystkich podłączonych układów muszą być zgodne. Szczególnej uwagi wymaga łączenie urządzeń pracujących z logiką 5 V i 3,3 V.
Ile urządzeń można podłączyć?
Adresowanie 7-bitowe udostępnia nominalnie 128 adresów. Część z nich jest zarezerwowana, dlatego standardowo pozostaje około 112 adresów użytkowych.
Rzeczywista liczba obsługiwanych urządzeń zależy jednak również od parametrów elektrycznych magistrali:
- Pojemność magistrali – tworzą ją przewody, ścieżki oraz wejścia podłączonych układów;
- Długość połączeń – dłuższe przewody zwiększają pojemność i podatność na zakłócenia;
- Rezystory podciągające – ich wartość wpływa na czas narastania sygnału i prąd w stanie niskim;
- Prędkość transmisji – typowe częstotliwości to 100 kHz i 400 kHz;
- Zasilanie i mikrokontroler – ograniczenia mogą wynikać z wydajności źródła zasilania, bufora biblioteki lub sprzętowego kontrolera I2C.
Adresy urządzeń I2C – jak to działa?
Każde urządzenie I2C ma adres, za pomocą którego kontroler wybiera odbiorcę transmisji. Urządzenia o innych adresach ignorują komunikację, która nie jest do nich skierowana.
Rodzaje adresów
W magistrali I2C można spotkać następujące rodzaje adresów:
- Adresy 7-bitowe – najczęściej używany wariant obejmujący nominalny zakres od 0 do 127;
- Adresy zarezerwowane – wartości przeznaczone do specjalnych zastosowań, których nie należy przypisywać zwykłym urządzeniom;
- Adresy 10-bitowe – rzadziej stosowane rozszerzenie pozwalające obsłużyć większą liczbę urządzeń.
Adres konkretnego modułu można ustalić na kilka sposobów:
- Nota katalogowa – zawiera podstawowy adres układu i sposób jego zmiany;
- Dokumentacja modułu – może uwzględniać dodatkowe zworki lub układ połączeń na płytce;
- Przykładowy program – często zawiera domyślny adres urządzenia;
- Skaner I2C – pozwala wykryć adresy urządzeń odpowiadających na magistrali.
Zmiana adresu modułu
Wiele modułów pozwala zmienić adres za pomocą zworek lub pól lutowniczych. Niektóre układy umożliwiają również zapisanie nowego adresu w rejestrze konfiguracyjnym.
Jeżeli dwa moduły mają ten sam, niezmienny adres, nie można ich bezpośrednio używać na jednej magistrali. Rozwiązaniem może być multiplekser I2C, dodatkowa magistrala albo mikrokontroler pośredniczący.
Rezystory podciągające – kiedy trzeba o nie zadbać?
Magistrala I2C wymaga rezystorów podciągających zarówno na linii SDA, jak i SCL. Gotowe moduły zazwyczaj mają je już wlutowane, natomiast układy projektowane samodzielnie zwykle wymagają dodania własnej pary rezystorów.
Najczęściej stosowana wartość to 4,7 kΩ. W praktyce używa się wartości od około 1 do 10 kΩ, zależnie od napięcia, prędkości transmisji, długości przewodów i pojemności magistrali.
Problemy przy wielu modułach
Jeżeli każdy moduł ma własne rezystory podciągające, ich równoległe połączenie zmniejsza rezystancję zastępczą. Przyspiesza to narastanie sygnałów, ale jednocześnie zwiększa prąd płynący podczas ściągania linii do stanu niskiego.
Przy większej liczbie modułów warto wykonać następujące czynności:
- Wyłączyć część rezystorów – na niektórych płytkach można przeciąć odpowiednią ścieżkę, rozłączyć zworkę albo odlutować elementy;
- Pozostawić jedną właściwie dobraną parę – rezystory mogą znajdować się na jednym module lub na głównej płytce projektu;
- Sprawdzić przebiegi – w bardziej wymagających układach warto zmierzyć sygnały oscyloskopem lub analizatorem logicznym.
I2C a napięcia 5 V i 3,3 V
Klasyczne Arduino UNO i Nano pracują z logiką 5 V, natomiast wiele nowoczesnych czujników wykorzystuje logikę 3,3 V.
Niektóre moduły mają wbudowany stabilizator 3,3 V oraz dwukierunkowy konwerter poziomów logicznych. Dzięki temu mogą współpracować z Arduino działającym przy napięciu 5 V. Obecność takich zabezpieczeń należy zawsze potwierdzić w dokumentacji modułu.
Jeśli czujnik pracuje wyłącznie z napięciem 3,3 V i nie toleruje sygnałów 5 V, należy przestrzegać następujących zasad:
- Nie podciągać SDA i SCL do 5 V – mogłoby to uszkodzić wejścia czujnika;
- Zastosować dwukierunkowy konwerter poziomów – powinien być przeznaczony do magistrali I2C;
- Stronę HV połączyć z układem 5 V – obejmuje to napięcie odniesienia i odpowiednią stronę sygnałową;
- Stronę LV połączyć z czujnikiem 3,3 V – linie po tej stronie nie powinny przekraczać bezpiecznego napięcia urządzenia.
Alternatywą jest użycie płytki Arduino pracującej z logiką 3,3 V. W niektórych konfiguracjach wystarczy podciągnięcie SDA i SCL do 3,3 V, ale wyłącznie wtedy, gdy poziomy wejściowe wszystkich urządzeń są zgodne.
Komunikacja I2C w Arduino – biblioteka Wire
Arduino udostępnia bibliotekę Wire, która upraszcza konfigurację magistrali oraz wysyłanie i odbieranie danych.
Podstawowe funkcje po stronie kontrolera
Najczęściej używane funkcje biblioteki Wire to:
Wire.begin()– inicjalizuje magistralę I2C w trybie kontrolera;Wire.beginTransmission(adres)– rozpoczyna przygotowywanie danych dla urządzenia o wskazanym adresie;Wire.write(dane)– zapisuje bajt lub tablicę bajtów do bufora transmisji;Wire.endTransmission()– wysyła przygotowane dane i kończy transmisję;Wire.requestFrom(adres, liczba)– żąda określonej liczby bajtów od urządzenia;Wire.available()– zwraca liczbę bajtów dostępnych do odczytu;Wire.read()– odczytuje jeden bajt z bufora.
Minimalny schemat programu
Poniższy przykład przedstawia ogólny schemat zapisu i odczytu danych z urządzenia I2C:
#include <Wire.h>
const byte DEVICE_ADDR = 0x68;
void setup() {
Wire.begin();
Serial.begin(9600);
}
void loop() {
// Zapis wartości 0x12 do przykładowego rejestru 0x00
Wire.beginTransmission(DEVICE_ADDR);
Wire.write(0x00);
Wire.write(0x12);
byte error = Wire.endTransmission();
if (error != 0) {
Serial.print("Błąd transmisji: ");
Serial.println(error);
delay(500);
return;
}
// Wybór rejestru początkowego 0x01
Wire.beginTransmission(DEVICE_ADDR);
Wire.write(0x01);
// false powoduje wysłanie powtórzonego START zamiast STOP
error = Wire.endTransmission(false);
if (error == 0) {
Wire.requestFrom(DEVICE_ADDR, (uint8_t)2);
if (Wire.available() == 2) {
byte b1 = Wire.read();
byte b2 = Wire.read();
Serial.print("Dane: ");
Serial.print(b1);
Serial.print(", ");
Serial.println(b2);
}
}
delay(500);
}
Dokładna sekwencja komunikacji zależy od konkretnego układu. W nocie katalogowej należy sprawdzić adresy rejestrów, format danych oraz wymaganą liczbę wysyłanych i odbieranych bajtów.
Podłączenie wielu urządzeń – przykład z kodem
Załóżmy, że do jednej magistrali podłączono dwa czujniki o adresach 0x68 i 0x76.
Fizyczne połączenie
Oba moduły należy połączyć z Arduino w następujący sposób:
- VCC obu modułów – podłączyć do napięcia zgodnego z wymaganiami urządzeń;
- GND obu modułów – połączyć ze wspólną masą Arduino;
- SDA obu modułów – połączyć z pinem SDA Arduino;
- SCL obu modułów – połączyć z pinem SCL Arduino.
Przykładowy kod obsługujący dwa adresy
Poniższy program wywołuje tę samą funkcję odczytu dla dwóch różnych adresów:
#include <Wire.h>
const byte SENSOR1_ADDR = 0x68;
const byte SENSOR2_ADDR = 0x76;
void setup() {
Wire.begin();
Serial.begin(9600);
}
void readSensor(byte addr) {
// Przykładowy adres rejestru z wynikiem pomiaru
Wire.beginTransmission(addr);
Wire.write(0x00);
byte error = Wire.endTransmission(false);
if (error != 0) {
Serial.print("Brak odpowiedzi z 0x");
Serial.println(addr, HEX);
return;
}
Wire.requestFrom(addr, (uint8_t)2);
if (Wire.available() == 2) {
byte hi = Wire.read();
byte lo = Wire.read();
int value = (hi << 8) | lo;
Serial.print("Czujnik 0x");
Serial.print(addr, HEX);
Serial.print(" = ");
Serial.println(value);
} else {
Serial.print("Niepełne dane z 0x");
Serial.println(addr, HEX);
}
}
void loop() {
readSensor(SENSOR1_ADDR);
readSensor(SENSOR2_ADDR);
delay(1000);
}
Arduino za każdym razem kieruje żądanie do konkretnego adresu, a pozostałe urządzenia ignorują transmisję. Sposób wyboru rejestrów i interpretacji wyniku trzeba dostosować do dokumentacji używanych czujników.
Jak połączyć dwie płytki Arduino przez I2C?
I2C może również służyć do komunikacji między dwoma lub większą liczbą mikrokontrolerów.
Połączenie fizyczne
W przypadku dwóch płytek Arduino UNO należy wykonać następujące połączenia:
- SDA pierwszej płytki – połączyć z SDA drugiej płytki;
- SCL pierwszej płytki – połączyć z SCL drugiej płytki;
- GND obu płytek – połączyć ze sobą, aby zapewnić wspólny punkt odniesienia.
Wspólna masa jest konieczna także wtedy, gdy płytki są zasilane z osobnych źródeł. Nie należy natomiast łączyć ich linii zasilania bez sprawdzenia napięć i sposobu zasilania całego układu.
Role kontrolera i urządzenia peryferyjnego
Płytka działająca jako kontroler inicjuje komunikację za pomocą Wire.begin() bez argumentu. Płytka pełniąca funkcję urządzenia peryferyjnego otrzymuje własny adres, na przykład przez wywołanie Wire.begin(0x12).
Kontroler może przesyłać dane do urządzenia peryferyjnego, które odbiera je w funkcji zarejestrowanej przez Wire.onReceive(). Dane zwracane na żądanie kontrolera przygotowuje się w funkcji zarejestrowanej przez Wire.onRequest().
Skaner I2C – jak znaleźć adres urządzenia?
Jeżeli adres modułu nie jest znany albo urządzenie nie odpowiada, warto użyć skanera I2C. Program sprawdza kolejne adresy magistrali i wyświetla te, dla których otrzymał potwierdzenie ACK.
Podstawowy mechanizm skanowania przebiega następująco:
- sprawdzenie adresów użytkowych, najczęściej od 1 do 126;
- wywołanie
Wire.beginTransmission(adres); - wywołanie
Wire.endTransmission(); - sprawdzenie wyniku, przy czym wartość
0oznacza odpowiedź urządzenia.
Skaner I2C może pomóc w kilku sytuacjach:
- Wykrywanie urządzeń – pokazuje adresy modułów odpowiadających na magistrali;
- Weryfikacja dokumentacji – pozwala potwierdzić domyślny lub zmieniony adres;
- Kontrola połączeń – ułatwia wykrycie problemów z zasilaniem, masą, SDA i SCL;
- Diagnozowanie konfliktów – wskazuje brak odpowiedzi, choć sam nie zawsze rozpozna dwa urządzenia działające pod tym samym adresem.
Typowe problemy i sposoby ich diagnozowania
Najczęstsze problemy z I2C dotyczą okablowania, adresowania, napięcia, rezystorów podciągających oraz parametrów magistrali.
Brak odpowiedzi z urządzenia
Brak komunikacji może mieć następujące przyczyny:
- Nieprawidłowe połączenie – przewody SDA i SCL zostały zamienione albo podłączone do niewłaściwych pinów;
- Brak wspólnej masy – Arduino i moduł nie mają wspólnego punktu odniesienia GND;
- Błędny adres – program odwołuje się do innego adresu niż używany przez urządzenie;
- Niewłaściwe zasilanie – moduł nie jest zasilany albo otrzymuje nieodpowiednie napięcie;
- Nieprawidłowe podciąganie – rezystorów brakuje lub ich rezystancja zastępcza jest niewłaściwa;
- Uszkodzenie urządzenia – moduł mógł zostać uszkodzony przez odwrotną polaryzację lub przekroczenie dopuszczalnego napięcia.
Diagnostykę warto przeprowadzić w następującej kolejności:
- Sprawdź okablowanie – upewnij się, że SDA i SCL nie zostały zamienione;
- Sprawdź wspólną masę – wszystkie urządzenia powinny mieć połączone piny GND;
- Zmierz napięcie spoczynkowe – na nieaktywnej magistrali SDA i SCL powinny mieć poziom zbliżony do napięcia podciągającego;
- Uruchom skaner I2C – sprawdź, czy urządzenie odpowiada pod oczekiwanym adresem;
- Sprawdź dokumentację – zweryfikuj adres, format transmisji, rejestry i wymagania dotyczące zasilania;
- Zmniejsz częstotliwość – w razie potrzeby zastosuj instrukcję
Wire.setClock(100000);.
Konflikt adresów
Jeżeli dwa urządzenia mają identyczny i niezmienny adres, kontroler nie może ich niezależnie wybrać. Oba układy mogą odpowiadać jednocześnie, co prowadzi do błędnych danych lub nieprzewidywalnego działania.
Konflikt adresów można rozwiązać na kilka sposobów:
- Zmiana adresu – za pomocą zworek, pól lutowniczych lub konfiguracji programowej;
- Multiplekser I2C – pozwala umieścić urządzenia o tych samych adresach na oddzielnych kanałach;
- Osobna magistrala – można jej użyć, jeśli płytka udostępnia więcej niż jeden sprzętowy kontroler I2C;
- Dodatkowy mikrokontroler – może pośredniczyć w komunikacji z jednym z urządzeń.
Problemy przy długich przewodach
I2C nie zostało zaprojektowane do komunikacji na duże odległości. Długie przewody zwiększają pojemność magistrali, spowalniają narastanie sygnałów i podnoszą ryzyko błędów, szczególnie przy częstotliwości 400 kHz lub wyższej.
Stabilność komunikacji można poprawić w następujący sposób:
- Zmniejszyć częstotliwość – na przykład do 100 kHz lub niższej;
- Dobrać rezystory podciągające – z uwzględnieniem pojemności i prądu w stanie niskim;
- Skrócić przewody – ograniczyć również liczbę rozgałęzień i długość odgałęzień;
- Ograniczyć zakłócenia – oddalić magistralę od silników, przetwornic i przewodów dużej mocy;
- Zastosować odporniejszy interfejs – przy większych odległościach rozważyć na przykład RS-485.
Dobre praktyki przy projektowaniu magistrali I2C z Arduino
Podczas projektowania układu warto przestrzegać następujących zasad:
- Zawsze łącz wspólną masę – wszystkie urządzenia muszą mieć wspólny punkt odniesienia GND;
- Sprawdzaj przypisanie pinów – lokalizacja SDA i SCL zależy od modelu płytki Arduino;
- Kontroluj poziomy napięcia – przed podłączeniem urządzenia ustal, czy pracuje z logiką 5 V, czy 3,3 V;
- Stosuj konwerter poziomów – użyj go, gdy urządzenia nie mają zgodnych poziomów logicznych;
- Dobieraj rezystory podciągające – w typowych projektach często sprawdza się jedna para rezystorów 4,7 kΩ, ale wartość powinna wynikać z parametrów magistrali;
- Sprawdzaj adresy – urządzenia podłączone do jednej magistrali powinny mieć unikalne adresy;
- Używaj skanera I2C – pozwala szybko wykryć moduły i podstawowe problemy z komunikacją;
- Ograniczaj długość przewodów – krótsze połączenia zmniejszają pojemność i podatność na zakłócenia;
- Zmniejszaj prędkość w razie problemów – niższa częstotliwość często poprawia stabilność rozbudowanej magistrali.


