- Co to jest protokół komunikacyjny I2C?
- Jak działa komunikacja I2C?
- Gdzie korzystać z komunikacji I2C?
- I2C w Arduino
- Wymagane składniki
- Schemat obwodu
- Wyjaśnienie robocze
- Programowanie I2C w Arduino
- Objaśnienie programowania Master Arduino
- Objaśnienie programowania Slave Arduino
W naszym poprzednim samouczku dowiedziałem się o komunikacji SPI w Arduino. Dziś dowiemy się o innym protokole komunikacji szeregowej: I2C (Inter Integrated Circuits). Porównując I2C z SPI, I2C ma tylko dwa przewody, podczas gdy SPI wykorzystuje cztery, a I2C może mieć Multiple Master i Slave, podczas gdy SPI może mieć tylko jednego mastera i wiele slaveów. Tak więc w projekcie jest więcej niż jeden mikrokontroler, który musi być masterem, a następnie używany jest I2C. Komunikacja I2C jest zwykle używana do komunikacji z żyroskopem, akcelerometrem, czujnikami ciśnienia barometrycznego, wyświetlaczami LED itp.
W tym samouczku Arduino I2C wykorzystamy komunikację I2C między dwiema płytami arduino i wyślemy do siebie wartości (od 0 do 127) za pomocą potencjometru. Wartości zostaną wyświetlone na wyświetlaczu LCD 16x2 podłączonym do każdego z Arduino. Tutaj jeden Arduino będzie działał jako Master, a inny jako Slave. Zacznijmy więc od wprowadzenia o komunikacji I2C.
Co to jest protokół komunikacyjny I2C?
Termin IIC oznacza „ Inter Integrated Circuits ”. Zwykle jest oznaczany jako I2C lub I do kwadratu C lub nawet jako protokół interfejsu 2-przewodowego (TWI) w niektórych miejscach, ale wszystko oznacza to samo. I2C to synchroniczny protokół komunikacyjny, co oznacza, że oba urządzenia, które udostępniają informacje, muszą dzielić wspólny sygnał zegarowy. Ma tylko dwa przewody do udostępniania informacji, z których jeden służy do sygnału koguta, a drugi do wysyłania i odbierania danych.
Jak działa komunikacja I2C?
Komunikację I2C po raz pierwszy wprowadził Phillips. Jak wspomniano wcześniej, ma dwa przewody, te dwa przewody zostaną połączone między dwoma urządzeniami. W tym przypadku jedno urządzenie nazywa się nadrzędnym, a drugie jako podrzędne. Komunikacja powinna i zawsze będzie zachodzić między dwoma urządzeniami Master i Slave. Zaletą komunikacji I2C jest to, że więcej niż jeden slave może być podłączony do Master.
Cała komunikacja odbywa się za pośrednictwem tych dwóch przewodów, mianowicie zegara szeregowego (SCL) i danych szeregowych (SDA).
Zegar szeregowy (SCL): dzieli sygnał zegara generowany przez urządzenie nadrzędne z urządzeniem podrzędnym
Serial Data (SDA): Wysyła dane do i pomiędzy Master a Slave.
W dowolnym momencie tylko kapitan będzie mógł zainicjować komunikację. Ponieważ w magistrali jest więcej niż jeden slave, master musi odnosić się do każdego slave'a używając innego adresu. Po zaadresowaniu tylko slave o tym konkretnym adresie odpowie z informacją, podczas gdy inni będą kontynuować. W ten sposób możemy używać tej samej magistrali do komunikacji z wieloma urządzeniami.
Te poziomy napięcia I2C nie są predefiniowane. Komunikacja I2C jest elastyczna, oznacza to, że urządzenie zasilane napięciem 5 V, może używać 5 V dla I2C, a urządzenia 3,3 V mogą używać 3 V do komunikacji I2C. Ale co, jeśli dwa urządzenia pracujące na różnych napięciach muszą komunikować się za pomocą I2C? Magistrali I2C 5V nie może być połączony z 3.3V urządzenia. W tym przypadku przesuwniki napięcia służą do dopasowania poziomów napięcia między dwiema szynami I2C.
Istnieje kilka warunków, które stanowią ramę dla transakcji. Inicjalizacja transmisji rozpoczyna się opadającym zboczem SDA, który jest zdefiniowany jako stan „START” na poniższym schemacie, w którym master pozostawia wysoki poziom SCL podczas ustawiania niskiego poziomu SDA.
Jak pokazano na powyższym schemacie poniżej, Zbocze opadające SDA jest wyzwalaczem sprzętowym dla warunku START. Następnie wszystkie urządzenia na tej samej magistrali przechodzą w tryb nasłuchu.
W ten sam sposób narastające zbocze SDA zatrzymuje transmisję, co jest pokazane jako stan „STOP” na powyższym schemacie, w którym master opuszcza wysoki poziom SCL, a także zwalnia SDA, aby przejść w stan wysoki. Tak więc narastające zbocze SDA zatrzymuje transmisję.
Bit R / W wskazuje kierunek transmisji kolejnych bajtów, jeśli jest WYSOKI oznacza, że slave będzie transmitować, a jeśli jest niski, oznacza to, że master będzie transmitował.
Każdy bit jest przesyłany w każdym cyklu zegara, więc przesłanie bajtu zajmuje 8 cykli zegara. Po wysłaniu lub odebraniu każdego bajtu dziewiąty cykl zegara jest wstrzymywany dla potwierdzenia / NACK (potwierdzony / niepotwierdzony). Ten bit ACK jest generowany przez slave lub master w zależności od sytuacji. Dla bitu ACK SDA jest ustawiane w stan niski przez master lub slave w 9- tym cyklu zegara. Więc jest niski, uważany za ACK, w przeciwnym razie NACK.
Gdzie korzystać z komunikacji I2C?
Komunikacja I2C jest używana tylko do komunikacji na krótkie odległości. Z pewnością jest do pewnego stopnia niezawodny, ponieważ ma zsynchronizowany impuls zegara, aby uczynić go inteligentnym. Protokół ten jest używany głównie do komunikacji z czujnikiem lub innymi urządzeniami, które muszą przesyłać informacje do mastera. Jest to bardzo przydatne, gdy mikrokontroler musi komunikować się z wieloma innymi modułami slave przy użyciu minimum samych przewodów. Jeśli szukasz komunikacji dalekiego zasięgu, powinieneś wypróbować RS232, a jeśli szukasz bardziej niezawodnej komunikacji, powinieneś wypróbować protokół SPI.
I2C w Arduino
Poniższy obrazek przedstawia piny I2C obecne w Arduino UNO.
Linia I2C | Pin w Arduino |
SDA | A4 |
SCL | A5 |
Zanim zaczniemy programować I2C za pomocą dwóch Arduino. Musimy poznać bibliotekę Wire używaną w Arduino IDE.
biblioteki
1. Wire.begin (adres):
Zastosowanie: Ta biblioteka służy do komunikacji z urządzeniami I2C. Spowoduje to zainicjowanie biblioteki Wire i dołączenie do magistrali I2C jako master lub slave.
Adres: 7-bitowy adres slave jest opcjonalny i jeśli adres nie jest określony, dołącza do magistrali jako master w ten sposób.
2. Wire.read ():
Zastosowanie: Ta funkcja jest używana do odczytu bajtu, który został odebrany z urządzenia nadrzędnego lub podrzędnego, który został przesłany z urządzenia podrzędnego do urządzenia nadrzędnego po wywołaniu funkcji requestFrom () lub został przesłany z urządzenia nadrzędnego do podrzędnego.
3. Wire.write ():
Zastosowanie: Ta funkcja służy do zapisywania danych w urządzeniu slave lub master.
Slave to Master: Slave zapisuje dane do mastera, gdy Wire.RequestFrom () jest używana w master.
Master to Slave: Do transmisji z urządzenia master do slave Wire.write () jest używana pomiędzy wywołaniami Wire.beginTransmission () i Wire.endTransmission ().
Wire.write () można zapisać jako:
- Wire.write (wartość)
wartość: wartość do wysłania jako pojedynczy bajt.
- Wire.write (ciąg):
string: ciąg do wysłania jako seria bajtów.
- Wire.write (dane, długość):
dane: tablica danych do wysłania w bajtach
długość: liczba bajtów do przesłania.
4. Wire.beginTransmission (adres):
Użycie: Funkcja służy do rozpoczęcia transmisji do urządzenia I2C o podanym adresie slave. Następnie należy zbudować kolejkę bajtów do transmisji za pomocą funkcji write (), a następnie przesłać je przez wywołanie funkcji endTransmission () . Przesyłany jest 7-bitowy adres urządzenia.
5. Wire.endTransmission ();
Użycie: Ta funkcja służy do zakończenia transmisji do urządzenia podrzędnego, która została rozpoczęta przez beginTransmission () i przesyła bajty, które zostały umieszczone w kolejce przez Wire.write ().
6. Wire.onRequest ();
Użycie: Ta funkcja jest wywoływana, gdy master żąda danych za pomocą Wire.requestFrom () z urządzenia slave. Tutaj możemy dołączyć funkcję Wire.write () do wysyłania danych do mastera.
7. Wire.onReceive ();Użycie: Ta funkcja jest wywoływana, gdy urządzenie slave otrzymuje dane od mastera. Tutaj możemy dołączyć Wire.read (); funkcja odczytu danych przesłanych z mastera.
8. Wire.requestFrom (adres, ilość);
Użycie: Ta funkcja jest używana w urządzeniu głównym do żądania bajtów z urządzenia slave. Funkcja Wire.read () służy do odczytu danych wysłanych z urządzenia slave.
adres: 7-bitowy adres urządzenia, z którego ma żądać bajtów
ilość: liczba bajtów do żądania
Wymagane składniki
- Arduino Uno (2-Nos)
- Moduł wyświetlacza LCD 16X2
- Potencjometr 10 K (4-Nos)
- Płytka prototypowa
- Podłączanie przewodów
Schemat obwodu
Wyjaśnienie robocze
Tutaj, aby zademonstrować komunikację I2C w Arduino, używamy dwóch Arduino UNO z dwoma połączonymi ze sobą wyświetlaczami LCD 16X2 i używamy dwóch potencjometrów w obu arduino do określenia wartości wysyłania (od 0 do 127) od mastera do slave i slave do master, zmieniając potencjometr.
Przyjmujemy wejściową wartość analogową na pinie A0 arduino od (0 do 5 V) za pomocą potencjometru i przekształcamy je na wartość analogowo-cyfrową (od 0 do 1023). Następnie te wartości ADC są dalej konwertowane na (0 do 127), ponieważ możemy przesyłać tylko 7-bitowe dane przez komunikację I2C. Komunikacja I2C odbywa się poprzez dwa przewody na pinach A4 i A5 obu arduino.
Wartości na wyświetlaczu LCD Slave Arduino zostaną zmienione przez zmianę POT po stronie głównej i odwrotnie.
Programowanie I2C w Arduino
Ten samouczek ma dwa programy, jeden dla Master Arduino, a drugi dla Slave Arduino. Kompletne programy dla obu stron są podane na końcu tego projektu wraz z filmem demonstracyjnym.
Objaśnienie programowania Master Arduino
1. Przede wszystkim musimy dołączyć bibliotekę Wire do korzystania z funkcji komunikacyjnych I2C oraz bibliotekę LCD do korzystania z funkcji LCD. Zdefiniuj również piny LCD dla 16x2 LCD. Dowiedz się więcej o łączeniu LCD z Arduino tutaj.
#zawierać
2. In void setup ()
- Rozpoczynamy komunikację szeregową z prędkością transmisji 9600.
Serial.begin (9600);
- Następnie rozpoczynamy komunikację I2C na pinie (A4, A5)
Wire.begin (); // Rozpoczyna komunikację I2C na pinie (A4, A5)
- Następnie inicjalizujemy moduł wyświetlacza LCD w trybie 16X2 i wyświetlamy komunikat powitalny i usuwamy go po pięciu sekundach.
lcd.begin (16,2); // Inicjalizacja wyświetlacza LCD lcd.setCursor (0,0); // Ustawia kursor w pierwszym wierszu Display lcd.print ("Circuit Digest"); // Wyświetla CIRCUIT DIGEST w LCD lcd.setCursor (0,1); // Ustawia kursor w drugim wierszu Display lcd.print ("I2C 2 ARDUINO"); // Wyświetla I2C ARDUINO z opóźnieniem LCD (5000); // Opóźnienie o 5 sekund lcd.clear (); // Czyści wyświetlacz LCD
3. W pustej pętli ()
- Najpierw musimy pobrać dane z Slave, więc używamy requestFrom () z adresem slave 8 i żądamy jednego bajtu
Wire.requestFrom (8,1);
Odebrana wartość jest odczytywana za pomocą Wire.read ()
byte MasterReceive = Wire.read ();
- Następnie musimy odczytać wartość analogową z mastera arduino POT podłączonego do pinu A0
int potvalue = analogRead (A0);
Konwertujemy tę wartość na jeden bajt z 0 na 127.
byte MasterSend = map (potvalue, 0,1023,0,127);
- Następnie musimy wysłać te przekonwertowane wartości, więc transmisję zaczynamy od slave arduino z adresem 8
Wire.beginTransmission (8); Wire.write (MasterSend); Wire.endTransmission ();
- Następnie wyświetlamy te odebrane wartości od slave arduino z opóźnieniem 500 mikrosekund i stale otrzymujemy i wyświetlamy te wartości.
lcd.setCursor (0,0); // Ustawia kursor w pierwszym wierszu LCD lcd.print (">> Master <<"); // Drukuje >> Master << na LCD lcd.setCursor (0,1); // Ustawia kursor w drugim wierszu LCD lcd.print ("SlaveVal:"); // Drukuje SlaveVal: w LCD lcd.print (MasterReceive); // Drukuje MasterReceive na wyświetlaczu LCD otrzymany z Slave Serial.println ("Master Received From Slave"); // Drukuje w Serial Monitor Serial.println (MasterReceive); opóźnienie (500); lcd.clear ();
Objaśnienie programowania Slave Arduino
1. Podobnie jak master, przede wszystkim musimy dołączyć bibliotekę Wire do korzystania z funkcji komunikacyjnych I2C oraz bibliotekę LCD do korzystania z funkcji LCD. Zdefiniuj również piny LCD dla 16x2 LCD.
#zawierać
2. In void setup ()
- Rozpoczynamy komunikację szeregową z prędkością transmisji 9600.
Serial.begin (9600);
- Następnie rozpoczynamy komunikację I2C na pinie (A4, A5) z adresem slave'a 8. Tutaj ważne jest, aby określić adres slave.
Wire.begin (8);
Następnie musimy wywołać funkcję, gdy Slave otrzyma wartość od mastera i gdy Master zażąda wartości od Slave
Wire.onReceive (acceptEvent); Wire.onRequest (requestEvent);
- Następnie inicjalizujemy moduł wyświetlacza LCD w trybie 16X2 i wyświetlamy komunikat powitalny i usuwamy go po pięciu sekundach.
lcd.begin (16,2); // Inicjalizacja wyświetlacza LCD lcd.setCursor (0,0); // Ustawia kursor w pierwszym wierszu Display lcd.print ("Circuit Digest"); // Wyświetla CIRCUIT DIGEST w LCD lcd.setCursor (0,1); // Ustawia kursor w drugim wierszu Display lcd.print ("I2C 2 ARDUINO"); // Wyświetla I2C ARDUINO z opóźnieniem LCD (5000); // Opóźnienie o 5 sekund lcd.clear (); // Czyści wyświetlacz LCD
3. Następnie mamy dwie funkcje, jedną dla zdarzenia żądania, a drugą dla zdarzenia odbioru
Na żądanie Event
Gdy Master zażąda wartości od slave, ta funkcja zostanie wykonana. Ta funkcja pobiera wartość wejściową z Slave POT i konwertuje ją na 7-bitową i wysyła tę wartość do mastera.
void requestEvent () { int potvalue = analogRead (A0); byte SlaveSend = map (potvalue, 0,1023,0,127); Wire.write (SlaveSend); }
Odbierz wydarzenie
Gdy Master wyśle dane do slave'a z adresem slave (8), ta funkcja zostanie wykonana. Ta funkcja odczytuje otrzymaną wartość z mastera i przechowuje w zmiennej typu bajt .
void otrzymaszEvent (int howMany { SlaveReceived = Wire.read (); }
4. W pętli Void ():
Otrzymaną wartość z mastera wyświetlamy w sposób ciągły w module wyświetlacza LCD.
void loop (void) { lcd.setCursor (0,0); // Ustawia kursor w pierwszym wierszu LCD lcd.print (">> Slave <<"); // Drukuje >> Slave << na LCD lcd.setCursor (0,1); // Ustawia kursor w drugim wierszu LCD lcd.print ("MasterVal:"); // Drukuje MasterVal: w LCD lcd.print (SlaveReceived); // Wyświetla wartość SlaveReceived na wyświetlaczu LCD otrzymaną od urządzenia głównego Serial.println ("Slave otrzymano od urządzenia głównego:"); // Drukuje w Serial Monitor Serial.println (SlaveReceived); opóźnienie (500); lcd.clear (); }
Przez obracanie potencjometrów z jednej strony, można zobaczyć różne wartości na wyświetlaczu LCD na innej stronie:
Tak więc komunikacja I2C odbywa się w Arduino, tutaj użyliśmy dwóch Arduino, aby zademonstrować nie tylko wysyłanie danych, ale także odbieranie danych za pomocą komunikacji I2C. Teraz możesz połączyć dowolny czujnik I2C z Arduino.
Pełne kodowanie dla Arduino Master i Slave jest podane poniżej wraz z filmem demonstracyjnym