Popularny protokół I2C umożliwia komunikację dwóch lub więcej płyt Arduino. Dowiedz się, jak je połączyć i zakodować.
Podczas gdy pojedynczy Arduino może wykonać wiele zadań, niektóre projekty mogą wymagać użycia więcej niż jednej płytki do obsługi różnych funkcji. Tak więc, aby umożliwić przesyłanie danych między dwoma mikrokontrolerami, należy skonfigurować protokół komunikacyjny, taki jak CAN, SPI, I2C lub UART.
W tym przewodniku omówimy podstawy działania I2C, połączenia sprzętowe i implementację oprogramowania potrzebną do skonfigurowania dwóch płyt Arduino jako urządzeń nadrzędnych i podrzędnych I2C.
Co to jest I2C?
Inter-Integrated Circuit (I2C) to szeroko stosowany protokół komunikacyjny w systemach wbudowanych i mikrokontrolerach umożliwiający przesyłanie danych między urządzeniami elektronicznymi. W przeciwieństwie do SPI (Serial Peripheral Interface), I2C umożliwia podłączenie więcej niż jednego urządzenia nadrzędnego do magistrali z jednym lub wieloma urządzeniami podrzędnymi. Został po raz pierwszy użyty przez firmę Philips i jest również znany jako protokół komunikacyjny Two Wire Interface (TWI).
Jak działa komunikacja I2C?
I2C wykorzystuje dwie linie dwukierunkowe: dane szeregowe (SDA) i zegar szeregowy (SCL) do przesyłania danych i synchronizacji komunikacji między urządzeniami. Każde urządzenie podłączone do magistrali I2C posiada unikalny adres, który identyfikuje je podczas komunikacji. Protokół I2C umożliwia wielu urządzeniom współdzielenie tej samej magistrali, a każde urządzenie może działać jako master lub slave.
Komunikacja jest inicjowana przez urządzenie nadrzędne, a nieprawidłowe adresowanie urządzeń podrzędnych może powodować błędy w transmisji. Zapoznaj się z naszym szczegółowym przewodnikiem na temat jak działa komunikacja szeregowa UART, SPI i I2C aby dać ci kontekst.
Główną zaletą komunikacji I2C, na którą warto zwrócić uwagę, jest elastyczność, jaką oferuje, jeśli chodzi o zarządzanie energią. Urządzenia działające na różnych poziomach napięcia mogą nadal skutecznie komunikować się za pomocą przesuwników napięcia. Oznacza to, że urządzenia pracujące z napięciem 3,3 V wymagają przesuwników napięcia, aby połączyć się z magistralą 5 V I2C.
Biblioteka drutu
Biblioteka Wire to wbudowana biblioteka Arduino, która zapewnia funkcje do komunikacji przez I2C. Wykorzystuje dwa piny — SDA i SCL — na płycie Arduino do komunikacji I2C.
Piny I2C na Arduino Uno:
Piny Arduino Nano I2C:
Aby korzystać z biblioteki, należy dołączyć Drut h plik nagłówkowy na początku szkicu Arduino.
#włączać
Biblioteka Wire udostępnia funkcje do inicjowania komunikacji z urządzeniem I2C, wysyłania i odbierania danych. Niektóre ważne funkcje, które powinieneś znać, obejmują:
- Drut.rozpocznij(): używany do dołączania do magistrali I2C i inicjowania komunikacji.
- Wire.beginTransmission(): służy do określenia adresu urządzenia podrzędnego i rozpoczęcia transmisji.
- Wire.write(): używany do wysyłania danych do urządzenia I2C.
- Wire.endTransmission(): służy do kończenia transmisji i sprawdzania błędów.
- Wire.requestFrom(): używany do żądania danych z urządzenia I2C.
- Przewód.dostępny(): służy do sprawdzania, czy dane są dostępne do odczytu z urządzenia I2C.
- Wire.read(): służy do odczytu danych z urządzenia I2C.
Użyj Wire.beginTransmission() funkcja ustawiania adresu czujnika, który jest wstawiany jako argument. Na przykład, jeśli adres czujnika to 0x68, użyłbyś:
Drut.rozpocząć Transmisja(0x68);
Konfiguracja sprzętu Arduino I2C
Aby połączyć dwie płyty Arduino za pomocą I2C, potrzebne będą następujące komponenty sprzętowe:
- Dwie płytki Arduino (master i slave)
- deska do krojenia chleba
- Przewody rozruchowe
- Dwa rezystory podciągające 4,7 kΩ
Podłącz SDA I SCL piny obu płyt Arduino do płytki prototypowej. Podłącz rezystory podciągające między SDA I SCL szpilki i 5V szyna zasilająca na płytce stykowej. Na koniec połącz ze sobą dwie płytki stykowe za pomocą przewodów połączeniowych.
Obwód Arduino Uno
Obwód Arduino Nano
Konfigurowanie płyt Arduino jako urządzeń nadrzędnych i podrzędnych I2C
Użyj Wire.requestFrom() do określenia adresu urządzenia podrzędnego, z którym chcemy się komunikować. Następnie skorzystaj z Wire.read() funkcja pobierania danych z urządzenia podrzędnego.
Kod urządzenia głównego:
#włączać
próżniaorganizować coś(){
Drut.zaczynać(); // dołącz do magistrali i2c
Seryjny.zaczynać(9600); // uruchom serial do wyjścia
}
próżniaOtrzymywać dane(){
int adres = 8;
int bajty do odczytu = 6;
Drut.żądanie od(adres, bajty do odczytu);
chwila (Drut.dostępny()) {
zwęglać dane = Drut.Czytać();
Seryjny.wydrukować(dane);
}
opóźnienie(500);
}
próżniapętla(){
Otrzymywać dane();
}
The Wire.onReceive() służy do określenia, co należy zrobić, gdy urządzenie podrzędne odbierze dane z urządzenia nadrzędnego. W powyższym kodzie plik Przewód.dostępny() funkcja sprawdza, czy dane są dostępne, a Wire.read() funkcja odczytuje dane przesłane przez urządzenie nadrzędne.
Kod urządzenia podrzędnego:
#włączać
próżniaorganizować coś(){
Drut.zaczynać(8); // dołącz do magistrali I2C o adresie 8
Drut.onOdbierz(zdarzenie odbioru); // wywołaj funkcję receiveEvent po odebraniu danych
}
próżniapętla(){
opóźnienie(100);
}
próżniaOdbierzZdarzenie(int bajty){
Drut.pisać("Witam "); // odpowiedz komunikatem o długości 6 bajtów zgodnie z oczekiwaniami mastera
}
Wysyłanie i odbieranie danych za pomocą I2C
W tym przykładzie odczytajmy temperaturę z czujnika temperatury DHT11 połączonego z podrzędnym Arduino i wydrukujmy ją na monitorze szeregowym nadrzędnego Arduino.
Zmodyfikujmy kod, który napisaliśmy wcześniej, aby zawierał pomiar temperatury, który następnie wyślemy do płyty głównej przez magistralę I2C. Płyta główna może następnie odczytać przesłaną przez nas wartość, a następnie wyświetlić ją na monitorze szeregowym.
Kod urządzenia głównego:
#włączać
próżniaorganizować coś(){
Drut.zaczynać();
Seryjny.zaczynać(9600);
Seryjny.println(„Master zainicjowany!”);
}
próżniapętla(){
Drut.żądanie od(8, 1); // Żądanie danych temperatury od urządzenia podrzędnego
Jeśli (Drut.dostępny()) {
bajt temperatura = Drut.Czytać(); // Odczyt danych temperatury z urządzenia podrzędnego
Seryjny.wydrukować("Temperatura: ");
Seryjny.wydrukować(temperatura);
Seryjny.println(„°C”);
}
opóźnienie(2000); // Poczekaj 2 sekundy przed ponownym zażądaniem temperatury
}
Kod urządzenia podrzędnego:
#włączać
#włączać#definiować DHTPIN 4 // Pin podłączony do czujnika DHT
#definiować TYP DHT DHT11 // Typ czujnika DHT
DHT dht(DHTTPIN, DHTTYPE);
bajt temperatura;próżniaorganizować coś(){
Drut.zaczynać(8); // Adres podrzędny to 8
Drut.na prośbę(zdarzenie żądania);
dht.zaczynać();
}próżniapętla(){
opóźnienie(2000); // Poczekaj 2 sekundy, aż DHT się ustabilizuje
temperatura = dht.czytajTemperatura(); // Odczyt temperatury z czujnika DHT
}
próżniażądanieZdarzenie(){
Drut.pisać(temperatura); // Wyślij dane temperatury do mastera
}
Możesz dostosować ten kod, aby pasował do dowolnych czujników, które możesz mieć w swoim projekcie, a nawet wyświetlić wartości czujników na module wyświetlacza, aby stwórz własny termometr pokojowy i miernik wilgotności.
Adresowanie Slave z I2C na Arduino
Aby odczytać wartości z komponentów dodanych do magistrali I2C w takim projekcie, ważne jest, aby podczas kodowania podać prawidłowy adres urządzenia podrzędnego. Na szczęście Arduino oferuje bibliotekę skanerów, która upraszcza proces identyfikacji urządzenia podrzędnego adresów, eliminując potrzebę przeglądania długich arkuszy danych czujników i dezorientacji w Internecie dokumentacja.
Użyj poniższego kodu, aby zidentyfikować adres dowolnego urządzenia podrzędnego obecnego na szynie I2C.
#włączać
// Dołącz bibliotekę Wire do komunikacji I2C próżniaorganizować coś(){
Drut.zaczynać(); // Zainicjuj komunikację I2C
Seryjny.zaczynać(9600); // Zainicjuj komunikację szeregową z szybkością 9600 bodów
chwila (!Seryjny); // Poczekaj na nawiązanie połączenia szeregowego
Seryjny.println("\nSkaner I2C"); // Wydrukuj wiadomość informującą o rozpoczęciu skanowania I2C
}próżniapętla(){
bajt błąd, adres; // Zadeklaruj zmienne do przechowywania błędów i adresów urządzeń
int nUrządzenia; // Zadeklaruj zmienną do przechowywania liczby znalezionych urządzeńSeryjny.println("Łów..."); // Wydrukuj wiadomość informującą o rozpoczęciu skanowania I2C
nUrządzenia = 0; // Ustaw liczbę znalezionych urządzeń na 0
Do (adres = 1; adres < 127; adres++) { // Iteruj po wszystkich możliwych adresach I2C
Drut.rozpocząć Transmisja(adres); // Rozpocznij transmisję na bieżący adres
błąd = Drut.koniec Transmisja(); // Zakończ transmisję i zapisz wszelkie błędyJeśli (błąd == 0) { // Jeśli nie znaleziono żadnych błędów
Seryjny.wydrukować(„Znaleziono urządzenie I2C pod adresem 0x”); // Wydrukuj komunikat wskazujący, że urządzenie zostało znalezione
Jeśli (adres < 16) Seryjny.wydrukować("0"); // Jeśli adres jest mniejszy niż 16, dodaj początkowe 0 dla celów formatowania
Seryjny.wydrukować(adres, HEX); // Wydrukuj adres w formacie szesnastkowym
Seryjny.println(" !"); // Wydrukuj komunikat wskazujący, że urządzenie zostało znalezione
nUrządzenia++; // Zwiększ liczbę znalezionych urządzeń
}
w przeciwnym razieJeśli (błąd == 4) { // Jeśli został znaleziony błąd
Seryjny.wydrukować(„Nieznany błąd pod adresem 0x”); // Wydrukuj komunikat informujący o znalezieniu błędu
Jeśli (adres < 16) Seryjny.wydrukować("0"); // Jeśli adres jest mniejszy niż 16, dodaj początkowe 0 dla celów formatowania
Seryjny.println(adres, HEX); // Wydrukuj adres w formacie szesnastkowym
}
}
Jeśli (nUrządzenia == 0) { // Jeśli nie znaleziono żadnych urządzeń
Seryjny.println("Nie znaleziono urządzeń I2C\n"); // Wydrukuj komunikat informujący, że nie znaleziono żadnych urządzeń
}
w przeciwnym razie { // Jeśli znaleziono urządzenia
Seryjny.println("gotowe\n"); // Wydrukuj komunikat informujący o zakończeniu skanowania I2C
}
opóźnienie(5000); // Opóźnij o 5 sekund przed rozpoczęciem następnego skanowania
}
Rozwiń swój projekt już dziś
Połączenie dwóch płyt Arduino za pomocą protokołu komunikacyjnego I2C oferuje elastyczny i wydajny sposób realizacji złożonych zadań, których nie może obsłużyć pojedyncza płyta. Z pomocą biblioteki Wire komunikacja między dwiema płytami za pomocą I2C jest łatwa, co pozwala na dodanie większej liczby komponentów do twojego projektu.