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

Obsługa ekspandera na I2C przez Raspberry Pi

ghost666 05 Lip 2015 13:59 9753 5
  • Obsługa ekspandera na I2C przez Raspberry Pi

    W większość projektów, które realizował autor tego poradnika w oparciu o Raspberry Pi wykorzystywał on piny GPIO jako wejścia i wyjścia cyfrowe. Wyprowadzonych na płytce RPi jest 17 takich pinów. Co zrobić jak potrzebujemy więcej? Najprostszym sposobem zwiększenia liczy wejść i wyjść cyfrowych, jest wykorzystanie jakiegoś ekspandera portów I/O. Tego rodzaju urządzenie pozwala zwiększyć liczbę dostępnych w układzie portów cyfrowych.

    Przykładem takiego ekspandera może być układ MSP23017. Jest to ekspander, komunikujący się z urządzeniem z pomocą portu I²C. Interfejs ten, to szeregowy interfejs komunikacyjny, pozwalający na podłączenie do jednej szyny danych większej liczby urządzeń. Ekspander konwertuje dane z/do I²C do/z równoległego wyjścia cyfrowego. Do podłączenia ekspandera wystarczy kilka pinów GPIO, a z pomocą interfejsu I²C obsłużyć można wiele urządzeń i sensorów.

    Część sprzętowa

    MCP23017 to 16 bitowy ekspander portu z interfejsem I²C. Wybrany został ten układ, z uwagi na to że oferuje aż 16 wyjść/wejść cyfrowych. Do jego sterowania wykorzystano wyprowadzony z Raspberry Pi port I²C wyprowadzony na pinach 3 i 5 listwy GPIO. To łącznie daje 31 pinów GPIO (15 + 16) w systemie z tylko jednym ekspanderem. Możliwe jest wykorzystanie większej ilości ekspanderów, co pozwala ogromnie zwiększyć ilość dostępnych portów GPIO. Dodanie kolejnego układu MCP23017 do systemu zwiększy liczbę dostępnych pinów GPIO z 31 do 47 (15 + 16 + 16). I to wszystko przy bardzo niewielkich kosztach (w Polsce układ jest dostępny w wielu sklepach w cenie od 4 zł do 6 zł - przyp. red.).

    Ogromną zaletą tych układów jest to, że są tanie i wymagają bardzo niewielkiej ilości dodatkowych dyskretnych do działania.

    W naszym przykładzie z pomocą tego ekspandera podłączyć do RPi chcemy 3 diody LED i przełącznik - wszystko przez interfejs I²C. Wykorzystano oporniki 330 Ω do ograniczenia prądu płynącego przez diody LED. Można wykorzystać inny rezystor, takie autor akurat miał pod ręką. Poniżej widoczny jest rozkład wyprowadzeń układu MCP23017 oraz schemat podłączenia go do płytki Raspberry Pi.

    Obsługa ekspandera na I2C przez Raspberry Pi




    Obsługa ekspandera na I2C przez Raspberry Pi


    Opornik przy przełączniku włączony jest pomiędzy wejście układu a masę. Jego rezystancja wynosi 10 kΩ. Zapewnia to stan niski na wejściu z przełącznikiem, będący tam do czasu jego naciśnięcia. Przyciśnięcie przycisku powoduje, że na wejściu obecne jest 3,3 V czyli stan wysoki. Rezystor zapobiega powstaniu zwarcia pomiędzy masą a zasilaniem i ogranicza płynący prąd.

    Pin 9 (VDD) podłączony jest do zasilania 3,3 V,
    Pin 10 (VSS) podłączony jest do masy,
    Pin 12 (SCL) podłączony jest di 5 pinu RPi,
    Pin 13 (SDA) podłączony jest di 5 pinu RPi,
    Pin 18 (Reset) powinien być w stanie wysokim w czasie normalnego działania układu, należy podłączyć do 3,3 V,
    Piny 15, 16 oraz 17 (A0-A2) determinują jaki jest adres układu. Używamy w systemie tylko jednego układu, więc wystarczy ustawić zero (wszystkie piny do masy).

    Tak wygląda złożony układ na płytce prototypowej:

    Obsługa ekspandera na I2C przez Raspberry Pi


    Część systemowa

    Aby wykorzystywać interfejs I²C na płytce Raspberry Pi należy włączyć w Raspbianie kilka rzeczy, które domyślnie są wyłączone. Konfiguracja realizowana jest w kilku prostych krokach. Opisane poniżej tyczą się nowszej wersji Raspbiana, więc posiadacze starszej instalacji muszą albo zmienić system na nowy, albo prześledzić zmiany.

    Krok pierwszy - załączenie I²C poprzez raspi-config

    Z linii komend wpisz:

    Code:
    sudo raspi-config


    Uruchomi to narzędzie do konfiguracji układu raspi-config, wygląda ono następująco:

    Obsługa ekspandera na I2C przez Raspberry Pi


    Teraz postępuj zgodnie z poniższym opisem:

    Wybierz “8 Advanced Options”
    Wybierz “A7 I2C”
    Wybierz “Yes”
    Komunikat zapyta czy na pewno włączyć interfejs I²C.

    Wybierz “Yes”
    Wybierz “Ok”
    Komunikat zapyta czy domyślnie ładować moduł.

    Wybierz “Yes”
    Komunikat oznajmi, że moduł ładowany będzie domyślnie.

    Wybierz “Ok”
    Wybierz “Finish”, aby powrócić do linii komend.

    Gdy uruchomisz ponownie system, moduły I²C będą załadowane

    Krok drugi - manualna edycja pliku modułów

    Następnie musimy dokonań ręcznej edycji pliku modułów. Korzystamy w tym celu z komendy:

    Code:
    sudo nano /etc/modules


    I w pliku dodajemy dwie następujące linijki:

    Code:
    i2c-bcm2708
    
    i2c-dev


    Naciskami CTRL-X, następnie Y, następnie RETURN aby zapisać plik i wyjść.

    Krok trzeci - instalacja plików programów interfejsu

    Aby pomóc sobie w debuggowaniu działania interfejsu I²C i aby móc korzystać z niego pod Pythonem. Instalujemy “python-smbus” i “i2c-tools”:

    Code:
    sudo apt-get update
    
    sudo apt-get install -y python-smbus i2c-tools


    Krok czwarty – Shutdown

    Wyłącz Raspberry Pi:

    Code:
    sudo halt


    Odczekaj dziesięć sekund, odłącz zasilanie i możesz podłączać ukłądy do interfejsu I²C.

    Sprawdzanie czy moduł I²C jest załączony (opcjonalne)

    Gdy uruchomiesz lub zrestartujesz RPi, aby sprawdzić czy moduł interfejsu pracuje wystarczy wpisać komendę:

    Code:
    lsmod | grep i2c_


    W wyniku zobaczymy wszystkie moduły zaczynające się od "i2c_". JEśli widzimy wśród nich “i2c_bcm2708″ to oznacza że moduł załadował się poprawnie.

    Testowanie sprzętu

    Gdy udało się już z powodzeniem załączyć działanie modułów I²C i podłączyć układy, trzeba sprawdzić ich działanie. Po upewnieniu się, że zasilanie podłączone jest w odpowiedni sposób i nie ma żadnych zwarć, możemy uruchomić system. Jeśli mamy RPi Rev 2 lub późniejsze, do testów korzystamy z komendy:

    Code:
    sudo i2cdetect -y 1


    Jeśli dysponujemy układem Rev 1 to wykorzystamy komendę:

    Code:
    sudo i2cdetect -y 0


    Jaka jest różnica? Pomiędzy Rev 1 a Rev 2 zamianie uległy sygnały idące do pinów 3 i 5 na GPIO. Zmienia to numer urządzenia, jaki nadaje się I²C, stąd też zmiana z 0 na 1.

    Autor wykorzystywał RPi Rev 1. Na wyjściu powyższej komendy uzyskał:

    Code:
    pi@raspberrypi ~ $ sudo i2cdetect -y 0
    
         0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
    00:          -- -- -- -- -- -- -- -- -- -- -- -- --
    10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    20: 20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    70: -- -- -- -- -- -- -- --



    Pokazuje to, że do systemu podłączony jest tylko jeden układ, którego adres do 0x20 (32dec). Taka konfiguracja wynika z ustawienia pinów adresowych układu. Jeśli na na przykład A0 podalibyśmy stan wysoki, to adres wynosił by 0x21 (33dec). Od tego jak ustawione zostaną piny konfigurujące adres układu - A0, A1 i A2 - zależy pod jakim adresem występować będzie układ. Zadbać jedynie trzeba, aby adres był unikalny.

    Test z linii komnd

    Aby przeprowadzić szybki test działania układu pod GPA0 podłączamy LEDa. Skonfigurujmy Port A w następujący sposób: GPA0..6 jako wyjścia i GPA7 jako wejście. (10000000bin lub 0x80hex).

    Code:
    sudo i2cset -y 1 0x20 0x00 0x80 


    Następnie ustawmy GPA0 w stan wysoki, co zapali LEDa:

    Code:
    sudo i2cset -y 1 0x20 0x14 0x01


    Aby wyłączyć LEDa wystaczy:

    Code:
    sudo i2cset -y 1 0x20 0x14 0x00


    Pamiętajmy o zmianie 1 na 0, jeśli korzystamy z RPi Rev 1.


    Zatem konfigurację i testowane układu mamy za sobą, teraz spróbujmy kontrolować wyjścia GPIO z ekspandera z pomocą Pythona! Poniżej znajduje się opis jak wykorzystywać go jako wyjścia i wejścia cyfrowe w prostym skrypcie Pythona.

    W poniższym przykładzie skupimy się na wykorzystaniu pierwszych trzech pinów portu A układu MCP23017 jako wyjść. Opróc portu A układ posiada jeszcze port B (GPB0..7), który kontrolować można w analogiczny sposób.

    W tego rodzaju skryptach niezwykle pomocna jest umiejętność szybkiej konwersji pomiędzy liczbami dziesiętnymi, binarnymi i szesnastkowymi. Można też skorzystać z kalkulatora, który wbudowany jest w system operacyjny lub z jakiegoś narzędzia on-line.

    Skrypt Pythona dla wyjść

    Poniżej znajduje się bardzo prosty, przykładowy skrypt, który wykorzystuje pierwsze trzy piny portu A do liczenia od 1 do 8, co widoczne jest na diodach:

    Kod: python
    Zaloguj się, aby zobaczyć kod


    Skrypt pobrać można ze strony komendą:

    Code:
    wget https://bitbucket.org/MattHawkinsUK/rpispy-misc/raw/master/mcp23017/mcp23017_outputs.py


    Uruchomić skrypt można poprzez:

    Code:
    sudo python mcp23017_outputs.py


    Powyższy skrypt realizuje następujące kroki:

    Importuje biblioteki smbus i time,
    Tworzy obiekt typu smbus “bus”,
    Konfiguruje pewne stałe,
    Ustawia wszystkie piny GPA jako wyjścia,
    Ustawia wszystkie piny GPA jako zero,
    Odlicza od 1 do 8, ustawiając aktualną wartość na GPA, czekając 1 sekundę pomiędzy każdym krokiem,
    Zeruje wszystkie piny GPA.

    Powinno to być widoczne na diodach LED w postaci sekwencji:

    000, 001, 010, 011, 100, 101, 110, 111

    Niezwykle istotną rzeczą, na którą trzeba zwrócić uwagę, jest to, że rejestry trzeba konfigurować po 8 bitów naraz. Zatem, aby skonfigurować GPA jako wyjścia wpisujemy 00000000 do IODIR, aby skonfigurować jako wyjścia wpisujemy 11111111 (255dec, 0xFFhex). Aby nastawiać GPA0..3 jako wyjścia i GPA4..7 do IODIR wpiszemy 11110000 (240dec, 0xF0hex) etc.

    Podobnie rzecz ma się z zapisem danych na wyjścia. Jeśli mamy GPA jako wyjścia i chcemy do GPA1 zapisać stan wysoki, a do innych niski musimy wysłać 00000010 na rejestr OLATA. Analigicznie, aby ustawić w stan wysoki jedynie GPA2 i GPA8 do tego rejestru zapiszemy 10000100

    It’s the same story for setting the pins of outputs. If you’ve set the GPA pins as outputs and you want to set GPA1 high and all the other pins low you need to send 00000010 to the OLATA register. If you want to set GPA2 and GPA7 high you would send 10000100.

    Skrypt Pythona dla wejść

    Poniżej przedstawiono przykładowy skrypt, pozwalający na odczyt w pętli stanu przełącznika i wypisywanie informacji, gdy przycisk zostanie naciśnięty.

    Kod: python
    Zaloguj się, aby zobaczyć kod



    Skrypt pobrać można ze strony komendą:

    Code:
    wget https://bitbucket.org/MattHawkinsUK/rpispy-misc/raw/master/mcp23017/mcp23017_inputs.py


    Uruchomić skrypt można poprzez:

    Code:
    sudo python mcp23017_inputs.py


    Powyższy skrypt realizuje następujące kroki:

    Importuje biblioteki smbus i time,
    Tworzy obiekt typu smbus “bus”,
    Konfiguruje pewne stałe,
    Ustawia wszystkie siedem pierwszych pinów GPA jako wyjścia,
    Ustawia ostatni pin GPA jako wejście
    Odczytuje w pętli stan ósmego bitu GPA
    Generuje komunikat na ekranie “Switch was pressed!”, gdy naciśnięty zostanie przycisk.

    W tym przykładzie wykorzystano jedynie jeden przycisk. Wykorzystując wszystkie osiem bitów rejestrów GPA i GPB podłączyć można aż 16 GPIO do wykorzystania jako wyjścia lub wejścia. Oznacza to 16 LEDów albo przycisków albo cokolwiek chcemy! Wystarczy tylko w odpowiedni sposób skonfigurować rejestry IODIRA i IODIRB.

    Źródła:

    http://www.raspberrypi-spy.co.uk/2013/07/how-...der-with-the-raspberry-pi-part-1/#prettyPhoto
    http://www.raspberrypi-spy.co.uk/2013/07/how-...c-port-expander-with-the-raspberry-pi-part-2/
    http://www.raspberrypi-spy.co.uk/2013/07/how-...c-port-expander-with-the-raspberry-pi-part-3/
    http://www.raspberrypi-spy.co.uk/2014/11/enabling-the-i2c-interface-on-the-raspberry-pi/


    Fajne!
  • Sklep HeluKabel
  • #2 05 Lip 2015 21:51
    sstasinek
    Poziom 12  

    Rozumiem że Microchip został użyty jako przykład, w dodatku poradnik przetłumaczony. Nie mam nic przeciwko, bardzo dobra robota, nie dziwi mnie brak komentarzy bo co tu komentować? Świetnie opisane, nic tylko używać... Ale popatrzyłem na to i zapytałem siebie czy mnie jara, coś by trzeba skomentować i jedyne co uwiera podczas lektury to Microchip i zabrane piny GPIO :D

    Cena nie jest zła jak na gotowca na raz. Znośna jeśli potrzeba prostego rozszerzania bez fajerwerków, ale nie do końca skoro za 4-6zł można mieć 8 bitowca (może być Microchip PIC może być Atmel) lub nawet 32-bitowca 48MHz(STM32) i osobnym softem uprościć główny soft, uniezależnić expander od maliny. Osobny uC daje możliwość dowolnej komunikacji SPI, TWI, RS232, RS485, 1wire, USB - zmienionej praktycznie dowolnie przez zmiane wsadu. Ponadto prawie każdy procesorek ma wejścia analogowe, komparator analogowy, multum przerwań w tym takich jak zmiana stanu pinów. Może buforować, rejestrować, generować PWM, odliczać, być tanim FPGA(256B eeprom = tabilca stanów 11bit) Wybudzać nazorce(rabsberry) jedynie wtedy kiedy bedzie potrzeba.

    Skoro cena podobna do expandera, szybkość podobna lub lepsza, pobór energii podobny, a możliwości I2C Microchipa znacznie niższe niż procesor Cortex-M0, Attiny, PIC. To raczej nie dodam do ulubionych tak jak nie dodaje expanderów Philipsa lub NXP. Powód ten sam - cena.
    Aczkolwiek.. cena jak na 16 dodatkowych wejść jest bardzo niska. W porównaniu do 8 bitowych Philipsów rewelacyjna.

    PS Moje niedawne odkrycie cenowe STM32 za 3.60zł, bo ma wszystko w sobie razem z RTC(którego brakuje malinie) goły wychodzi taniej niż 8 bitowiec. Na płytce Discovery za 15zł programowanej STLink lub RS232(Boot0=1) nawet łatwiejszy w stosowaniu i tańszy niż Arduino. Komunikacja z malinami via kaskada RS232 a przerwania via kaskada GPIO. Plus jest taki że port szeregowy zadziala też z PC, Laptopem czy nawet tabletem. Czyli na zasadzie samodzielny "serwer" kontra dowolny klient.

    Jeśli by sie uprzeć do sterowania LED na wyjścia AVR(zamiast ekspandera) nie potrzeba wcale rezystorów(jak to zaprezentowano) pod warunkiem zasilenia układów via jedna dioda prostownicza(3.3V -> 2.7V) wydajność wyjść AVR jest wtedy idealnie dopasowana do diod http://spritesmods.com/?art=minimalism&page=2 Potrzeba wówczas jednego konwertera napieć dla 3 pinów MISO, MOSI, CLK jeśli sterować SPI przy tym mieć możliwość programowania "inteligentnego expandera". Można pozostawić 3.3V ale dopinać diody katoda-anoda przeciwsobnie do pinów i sterować świecenie stanami 01,10, a wygaszać 00,11. Dwa mosfety na PORT to jak dwa rezystory - sumarycznie takie sterowanie da wymagane 10-20mA. W sumie: troche kombinacji ale kilka elementów fizycznie mniej przy podobnym zużyciu energii co powyższy gotowiec Microchip(1mA) i podobnych lub nieco lepszych parametrach czasowych(50ns). No chociażby dla wyciepania rezystorów warto pokombinować ;)

  • Sklep HeluKabel
  • #3 06 Lip 2015 08:36
    PiotrPitucha
    Poziom 33  

    Witam
    sstasinek strasznie narzekasz :)
    Tematem jest MCP23017 a nie to z czym współpracuje expander.
    Nie porównuj STM32 do maliny, podniecasz się 48MHz, w malinie masz 20 razy więcej, sam procesor nie daje życia systemowi, dodaj do procesora LAN, dodaj do procesora HDMI, dodaj do procesora 1GB RAM, dodaj do procesora 4 USB i możliwość wyboru systemu operacyjnego z kilku oferowanych.
    Czy to dalej uzyskasz w cenie Discovery?, dodaj jeszcze cenę płytki do peryferiów i okaże się że przeskoczysz cenę maliny a na dodatek zajmie Ci to kilka razy więcej miejsca.
    Nie jest też prawdą że MCP23017 blokuje nam GPIO, do tych samych pinów I2C możemy podpiąć kilka urządzeń pod innym adresem.
    Malina ma swoje zalety, wiadomo że nie używa jej się tylko po to pomrugać LEDami, choć można :), ale na mruganie są prostsze metody, tak samo jak karkołomnym zadaniem byłoby zrobienie TV internetowej na Discovery, co w przypadku maliny ogranicza się do wetknięcia kabla HDMI i kabla LAN, działa i na dodatek obsługuje sie z tego samego pilota co TV.
    Bardzo dobre opracowanie ghost666, niby wiem niby stosuję ale mam nagle całość w jednym miejscu za co wielkie brawa.
    Pozdrawiam

  • #4 06 Lip 2015 23:11
    Stefan_2000
    Poziom 18  

    PiotrPitucha napisał:

    Nie porównuj STM32 do maliny


    Myślę, że sstasinek nie porównuje STM32 do maliny, a raczej STM32 do ekspandera - cena zbliżona, tylko zakres możliwości jakby inny.


    sstasinek, mógłbyś podpowiedzieć skąd wytrzasnąłeś STM32 razem z Discovery za 15 zł?

    pozdrówki,
    sw

  • #5 17 Lip 2015 07:22
    alsa
    Poziom 12  

    Gdyby ktoś potrzebował kodu w C do sterowania tym expanderem :

    Kod: c
    Zaloguj się, aby zobaczyć kod


    :)

  • #6 07 Sty 2016 19:33
    Jacek1708
    Poziom 12  

    a mnie interesuje jeszcze jedno. Ekspander posiada wyjście INTA i INTB. Chciałbym wykorzystać je do generowania przerwania w momencie zmiany stanu portu i dopiero w tym momencie uruchomić odczyt z I2C jego stanu. Po co w pętli sprawdzać czy coś się zmieniło jeśli nic się nie zmieniło. Ekspander podłączony do maliny. Proszę o przykład obsługi przerwań dla maliny.