Elektroda.pl
Elektroda.pl
X
Mitronik
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Transmisja I2C pomiędzy dwoma modułami Arduino

ghost666 29 Lip 2015 20:00 11244 7
  • Transmisja I2C pomiędzy dwoma modułami Arduino
    Czasami, niektóre projekty wymagają rozdzielenia jakichś zadań na kilka modułów Arduino lub umożliwienie im wzajemnej komunikacji. Interfejs IIC (Inter-Integrated Circuit ang. pomiędzy układami scalonymi) czyli I²C jest idealnym rozwiązaniem tej kwestii.

    I²C to bardzo interesujący protokół. Zazwyczaj wykorzystuje się go do komunikacji pomiędzy procesorem a innymi układami scalonymi na płytce drukowanej np. aparatur fotograficznego, czy innych urządzeń elektronicznych.

    W poniższym projekcie jednakże, wykorzystamy I²C do komunikacji pomiędzy dwoma (lub więcej) modułami Arduino. Jeden z modułów będzie w tej transmisji masterem, a pozostałe będą działały jako urządzenia podległe. Wykorzystamy to do prostego pokazu - Arduino będzie mrugało diodą, w zależności od odebranych danych, raz lub dwa. Pozwoli to pokazać, że komunikacja działa.

    Aby zbudować pokazany układ potrzebne są co najmniej dwa moduły Arduino oraz kabelki do ich połączenia.

    Krok 1: Jak połączyć moduły ze sobą.

    Transmisja I2C pomiędzy dwoma modułami Arduino Transmisja I2C pomiędzy dwoma modułami Arduino


    Aby spiąć moduły ze sobą do transmisji z wykorzystaniem interfejsu I²C konieczne jest wykonanie trzech połączeń. Konieczne jest spięcie pinów A4 i A5 pomiędzy modułami (w przypadku Arduino UNO) i połączenie ich masze sobą. Poniżej pokazano prosty schemat ideowy, pokazujący w jaki sposób trzeba zrealizować to połączenie.

    Uwaga! trzeba pamiętać, że nie można łączyć ze sobą modułów Arduino zasilanych 5 V i 3,3 V. Takie połączenie może nie uszkodzi modułu zasilanego 5 V, ale może być niebezpieczne dla modułu zasilanego 3,3 V.

    Krok 2: Program

    Zaprezentowany poniżej kod podzielony jest na dwie części, program dla modułu nadzorującego transmisję i program dla urządzeń podległych. Najpierw spójrzmy na program dla mastera sieci I²C:





    Kod: c
    Zaloguj się, aby zobaczyć kod


    A poniżej znajduje się program, który wgrany jest do podległych modułów. Zajmuje się on odbiorem i interpretacją danych nadawanych przez mastera:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Krok 3: analiza kodu

    Najpierw przyjrzyjmy się programowi mastera. Zaczyna się od dołączenia do programu biblioteki Wire.h

    Code:
    #include <Wire.h> 


    Następnie w funkcji setup uruchamiamy interfejs I²C funkcją Wire.begin(). Jeśli nie podamy funkcji żadnych argumentów, Arduino rozpocznie pracę jako master I²C.

    Następnie wysyłamy zmienną x, pomiędzy 0 a 5, do urządzenia o adresie 9. Służą temu następujące funkcje:

    Code:
    Wire.beginTransmission(9); // nadawanie do urządzenia numer 9
    
    Wire.write(x);              // wyślij x
    Wire.endTransmission();    // koniec transmisji


    A teraz przyjrzyjmy się programowi w modułach odbierających dane. One także wykorzystują bibliotekę Wire.h, ale rozpoczynają funkcją Wire.begin(9), co powoduje, że układ działa jako slave z adresem 9. Wszystkie układy mające ten sam adres będą odbierały dane podczas transmisji.

    Oczywiście trzeba jakoś zareagować na odebranie danych poprzez interfejs I²C. Poniższa funkcja definiuje co ma się stać, gdy odebrane zostaną dane. Oznacza to, że za każdym razem, gdy Arduino odbierze dane poprzez interfejs I²C to uruchomi zadeklarowaną funkcję.

    Code:
    Wire.onReceive(receiveEvent); 


    A poniżej znajduje się prosta funkcja, która ma być deklarowana:

    Code:
    void receiveEvent(int bytes) { 
    
       x = Wire.read();
    }


    W sekcji loop(), po prostu interpretowane są odebrane dane i zmieniana jest częstotliwość mrugania diody LED, zależna od odebranych danych.

    Krok 4: więcej o I²C

    Mówiąc w dużym skrócie, I²C to dwuprzewodowy interfejs szeregowy. Warstwa fizyczna składa się z dwóch linii - danych (SDA) i zegarowej (SCL). Każda sieć I²C musi mieć jednego mastera w sieci i do 112 układów. Master może zapisywać dane oraz odczytywać informacje z układów slave. Jednakże odczyt danych z slave odbywa się tylko na żądanie mastera.

    Prędkość transmisji w takiej sieci wynosi około 100 kb/s. Niezbyt szybko, jednakże dostatecznie dużo, aby móc korzystać z komunikacji z wieloma układami.

    Jest dostępnych wiele sensorów, wyposażonych w interfejs I²C - moduły inercyjne, termometry, sonary i wiele innych. Przy ich stosowaniu pamiętać należy, że interfejs ten nie został zaprojektowany do dalekich transmisji kablowych i już odległość 2 m jest dla niego problematyczna.

    Wszystkie moduły Arduino mają wyprowadzone piny tego połączenia, jednakże na różnych fizycznych pinach modułu.

    Dla Arduino Uno i Pro Mini są to A4 (SDA), A5 (SCL),
    Da Arduini Mega i Due są to piny 20 (SDA), 21 (SCL),
    A dla Arduino Leonardo oraz Yun 2 (SDA), 3 (SCL).

    Krok 5: Podłączanie większej liczby układów

    Jeśli chcemy połączyć więcej niż dwa moduły w ten sposób, wystarczy że połączymy masy i sygnały interfejsu I²C - SDA i SCL. Każde podrzędne urządzenie, może być niezależnie adresowane przez Arduino zarządzające siecią.

    Poniżej pokazane jest w jaki sposób funkcjonuje sieć złożona z 3 podległych modułów Arduino i jednego mastera.



    Źródło: http://www.instructables.com/id/I2C-between-Arduinos/?ALLSTEPS


    Fajne! Ranking DIY
  • Mitronik
  • #3 29 Lip 2015 21:36
    ghost666
    Tłumacz Redaktor

    piotr_go napisał:
    A pull-upy to gdzie?


    W porcie :).

  • Mitronik
  • #4 29 Lip 2015 22:12
    2361799
    Użytkownik usunął konto  
  • #5 30 Lip 2015 12:37
    22053
    Użytkownik usunął konto  
  • #6 30 Lip 2015 16:52
    Kużdo
    Poziom 20  

    Kurde, to się naprawdę zalicza do DIY? Co tutaj właściwie zostało zrobione? Podłączone kilka takich samych urządzeń i napisany kod do wysyłania i odbierania prostego kodu... Przecież nie ma w tym nic z DIY. Na takiej samej zasadzie mógłbym iść do sklepu, kupić wkładkę do drzwi i zrobić DIY "Zróbmy sobie zamek w drzwiach" i w instrukcji wpisał "Włóżcie wkładkę w otwór w drzwiach przygotowany przez producenta drzwi. Gotowe! Właśnie zrobiliśmy zamek w drzwiach"...

    PS. Tak, wiem, że autor postu nie jest autorem tekstu, tylko tłumaczem. Pretensje mam do autora "projektu".
    PPS. Tutaj mamy odpowiednik tego artykułu: https://www.arduino.cc/en/Tutorial/MasterWriter


    R-MIK napisał:
    ghost666 napisał:
    piotr_go napisał:
    A pull-upy to gdzie?


    W porcie :).


    A o jakiej wartości?

    A o datasheet słyszał?

    Pytacie się o rzeczy, które łatwo znaleźć w sieci, a jak nowi przychodzą z pytaniem to jest "milion razy było wałkowane, że bilion razy było to już na forum, więc użyj szukajki". Arduino Uno zawiera Atmege328.
    https://www.arduino.cc/en/uploads/Main/Arduino_Uno_Rev3-schematic.pdf

  • #7 01 Sie 2015 00:44
    hawryszka
    Poziom 11  

    Witam,
    W temacie i ja dodam swoje "5 groszy".
    Warto dodać że Arduino przy transmisji I2C może pracować w 2 różnych "trybach"
    1. Master Sender - Slave Reciever
    2. Slave Sender - Master Reciever
    Tryby nadawanie - odbiór znajdują zastosowanie w różnych projektach.
    W trybie 1 master nie ma zdefiniowanego adresu i wysyła w "świat" dane do adresowanych slavów np.
    - wyślij "o" do slave o adresie 1
    - wyślij "b" do slave o adresie 15
    itd ..

    W trybie 2 adresowane slave'y wysyłają dane w świat ale to master aby odebrać wysyła zapytanie do slava o podanym adresie.

    Bardzo łatwo wysłać pojedyncze bity, problem zaczyna się dopiero jak przesyłamy całe słowa lub liczby większe niż 8 bitów - tu zaczynają się "schody" bo okazuje się że biblioteka Wire.h jest trochę niedorobiona i ma problem z odbiorem takich danych.

  • #8 01 Sie 2015 05:40
    dondu
    Moderator Mikrokontrolery Projektowanie

    Kużdo napisał:
    A o datasheet słyszał?

    Pytacie się o rzeczy, które łatwo znaleźć w sieci, a jak nowi przychodzą z pytaniem to jest "milion razy było wałkowane, że bilion razy było to już na forum, więc użyj szukajki". Arduino Uno zawiera Atmege328.
    https://www.arduino.cc/en/uploads/Main/Arduino_Uno_Rev3-schematic.pdf

    Sądzę, że kol. piotr_go i R-MIK zadali pytanie wskazujące problem bo dobrze wiedzą, że wewnętrzne rezystory pull-up w ATmega328 wartość zgodnie z dokumentacją mają od 20 do 50kΩ, podczas gdy standard I2C przewiduje wartość około 4,7-10kΩ, co może skutkować błędami transmisji dla dużych prędkości.

    Warto oczywiście rezystory dobrać do konkretnego przypadku: http://www.ti.com/lit/an/slva689/slva689.pdf