Przedstawię tutaj prosty w użyciu moduł pozwalający na uzyskanie dodatkowych portów I/O. Jeden PCF8574 sterowany jest tylko dwoma sygnałami, a daje nam aż całe 8 konfigurowalnych wejść/wyjść razem z dodatkowym opcjonalnym sygnałem przerwania. Co więcej, dwa piny mogą wysterować jednocześnie aż osiem PCF8574, co daje nam w sumie 64 piny, a połączeniu z wersją alternatywnym adresie do 128 pinów! Warto też wiedzieć, że nic nie stoi na przeszkodzie, by razem z PCF8574 na magistrali I2C podłączyć inne urządzenia, takie jak przykładowo czujniki czy tam zegar RTC... ale po kolei.
PCF8574 to tzw. ekspander IO, czyli układ który odpowiednio sterowany pozwala nam uzyskać dodatkowe piny wejścia/wyjścia w naszym projekcie. PCF8574 konkretnie sterowany jest za pomocą magistrali I2C, czyli magistrali opierającej się o dwa sygnały (zegar i dane) i pozwalającej obsłużyć wiele urządzeń jednocześnie - do jednej linii I2C można podłączyć wiele układów o ile ich adresy nie kolidują.
PCF pracuje na napięciu od 2,5 V do 6 V, więc nie powinno być problemów z jego uruchomieniem zarówno z klasycznym Arduino, jak i z ESP8266.
Rozważmy wyprowadzenia PCF8574:
SDA i SCL to obowiązkowe linie I2C, nim sterujemy tym układem. P0-P7 to nóżki układu którymi sterujemy, mogą być w roli wejść i wyjść cyfrowych. Piny A0, A1, A2 pozwalają nam zmienić adres danej sztuki PCF, dzięki czemu można podłączyć ich więcej na jedną magistralę:
PCF oferuje cztery tryby pracy GPIO:
Dla bardziej zaawansowanych użytkowników warto jest też przedstawić dokładniejszy schemat, który uwzględnia też rezystory podciągające linii od I2C:
Z ciekawostek dodam, że nota katalogowa też proponuje układ PCB pod expander:
Tu jednak skorzystam z gotowego modułu, który wszystko znacznie uprości.
Moduł PCF8574
Ogólnodostępny w sprzedaży moduł PCF8574 wyprowadza wszystkie jego nóżki na goldpiny, co zwalnia nas z obowiązku lutowania. Wyprowadzone są wszystkie IO, wyjście przerwania, piny adresowe oraz magistrala I2C - i to z dwóch stron. Wspomniane rezystory podciągające też są na pokładzie.
Moduł można dostać za kilka złotych. Sprowadzając zza granicy można nawet dostać 5 sztuk za 10-20 zł, zależnie od promocji.
Platforma do demonstracji
Z reguły tego typu prezentację wykonywałem na Arduino, ale tym razem pokusiłem się o NodeMCU z ESP8266. I tak wyjdzie prawie na to samo, ale moim zdaniem PlatformIO jest nieco wygodniejsze od Arduino IDE, a znajomość Visual Code przyda się też do innych języków. Przypomnijmy temat, gdzie już PlatformIO prezentowałem:
Zegar na ESP12 i wyświetlaczu MAX7219 - tutorial - część 1, ArduinoOTA, podstawy
Jak programować płytkę Wemos D1 (ESP8266) w kształcie Arduino? ArduinoOTA w PlatformIO
Użyta płytka:
Skan I2C
Użycie expandera jest bardzo proste, ale użytkownicy często gubią się przez adresy I2C. Z tego powodu na początek zawsze proponuję uruchomienie skanera I2C. Ten prosty program zweryfikuje nasze połączenia oraz wyświetli adresy I2C urządzeń podłączonych do magistrali. To powie nam, czy chociaż sprzętowo sytuacja jest okej, bo łatwo jest zamienić SCL z SDA lub coś źle podłączyć...
Tu moje podłączenie:
No i wspomniany skaner:
Kod: C / C++
Działa, adres układu jest widziany:
Teraz to samo, ale w przypadku pięciu expanderów z różnymi adresami. Podłączenie jest banalnie proste:
Rezultat:
Scanning...
I2C device found at address 0x20
I2C device found at address 0x21
I2C device found at address 0x22
I2C device found at address 0x24
I2C device found at address 0x26
Wszystkie expandery są widziane.
Dodajemy bibliotekę PCF8574
Dodawanie biblioteki w PlatformIO już wcześniej omawiałem, ale zasadniczo to wykonuje się to poprzez Libraries, wystarczy wyklikać. W wyszukiwarkę wpisujemy PCF8574 i dodajemy najlepiej ten sam wynik co u mnie na zrzucie ekranu (by Renzo Mischianti):
Wyszukiwarka może pokazać wcześniej też bibliotekę od LCD 2x16 sterowanego przez PCF8574, ale nam zależy na samym sterowaniu PCF8574. LCD uruchomimy innym razem.
Przy dodawaniu biblioteki można zapoznać się z jej przykładami, ale sam też przygotowałem poniżej kilka uproszczonych demonstracji.
Blink
Proponowaną przeze mnie bibliotekę (autorstwa Renzo Mischianti) charakteryzuje składnia do złudzenia przypominająca piny z Arduino, czyli mamy tu dalej nasze słynne pinMode, digitalWrite i digitalRead, tyle że nie jako funkcje globalne, tylko na obiekcie klasy PCF8574. Aby uruchomić PCF8574 korzystamy z konstruktora, który na moim przykładzie za argumenty pobiera adres I2C urządzenia oraz piny SDA i SCL:
Kod: C / C++
Uruchomienie PCFa, powie nam ono, czy go dobrze podłączyliśmy oraz czy adres się zgadza:
Kod: C / C++
Ustawienie trybu pracy pinu wygląda tak jak już wcześniej wspomniałem:
Kod: C / C++
Analogicznie ustawienie wartości na wyjściu:
Kod: C / C++
Pełny kod:
Kod: C / C++
Raczej nie ma tu co komentować, dioda po prostu mruga:
Oczywiście dioda podłączona z rezystorem - dałem około 300 omów, by nie spalić diody.
Odliczanie binarne
To teraz pomigajmy wszystkimi diodami. Nie jest to chyba konieczne, ale kusiło mnie odpalenie w ten sposób jakiejś prostej animacji. Zróbmy odliczanie binarne.
Tu nastąpił pierwszy zgrzyt, bo myślałem, że wystawię bajt na piny IO, tak jakbym to zrobił normalnie na mikrokontrolerze, ale funkcja z klasy PCF8574 jest prywatna...
src\main.cpp: In function 'void loop()':
src\main.cpp:29:33: error: 'bool PCF8574::digitalWriteAllBytes(byte)' is private within this context
29 | pcf8574.digitalWriteAllBytes(x);
Ostatecznie użyłem wywołań digitalWrite w pętli... ale to zostawiam do samodzielnej interpretacji.
Kod: C / C++
Działa:
PS: Teraz widzę, że zdefiniowanie PCF8574_LOW_MEMORY by może pomogło i wystawiło funkcję przyjmującą bajt, zostawiam to do wypróbowania Wam.
Przycisk
Skoro było digitalWrite, to mamy też digitalRead. Co więcej, nie musimy sami podłączać rezystora pull-up, gdyż układ sam "ściaga" wejścia na potencjał logicznego 1. My jedynie możemy zwierać je do masy (np. przyciskiem) i wtedy uzyskamy na nim stan niski. Dzięki temu nie musimy samodzielnie podłączać rezystora.
A więc podłączyłem:
- przycisk między GPIO a masą
- dodatkowo, tylko dla wizualizacji, diodę LED na drugim GPIO wraz z rezystorem kilkaset omów
Uruchomienie pinów:
Kod: C / C++
Pętla, odczyt GPIO, wypisywanie na konsolę (na UART), oraz ustawienie drugiego pinu:
Kod: C / C++
Działa, tyle że przycisk zwolniony tu oznacza stan 1, więc dioda jest zapalona, a wciśnięty przycisk to stan 0 - dioda zgaszona.
Przycisk i przerwanie
Zostaje do omówienia pin INT od PCF8574. Na tym pinie pojawi się zbocze opadające gdy zmieni się coś na wejściu PCF8574. Można to użyć w połączeniu z przerwaniem GPIO na naszym NodeMCU by otrzymać informacje o tym, że coś się przy PCF8574 zadziało, przykładowo ktoś wcisnął przycisk.
Podłączamy zatem INT do, powiedzmy, GPIO5. Teraz trzeba uruchomić przerwanie:
Kod: C / C++
Funkcja interruptHandler wywoła się gdy na D5 będzie zbocze opadające (FALLING):
Kod: C / C++
Tutaj w celach demonstracyjnych tylko ustawiam zmienną, której potem używam do sprawdzenia w głównej pętli, czy trzeba odczytać ponownie piny PCFa.
Kod: C / C++
Działanie jest dość podobne do poprzedniego przykładu, tyle, że pętla sprawdza stan pinów tylko po otrzymaniu przerwania.
W ten sposób można obsłużyć więcej pinów - oto przykład z dokumentacji użytej biblioteki:
Kod: C / C++
Zwalnia to nas z obowiązku wykonywania skanu digitalReadAll co odświeżenie.
Czy można podłączyć jeszcze więcej wyjść/wejść?
Na rynku jest też dostępna wersja układu z innym adresowaniem, co w sumie daje nam 128 kontrolowanych pinów:
Podsumowanie
Przydatny i prosty w użyciu moduł. Wszystko co potrzeba jest wyprowadzone na goldpiny, a i wybór adresu jest dość szeroki. Przy 8 sztukach można wysterować całe 64 odbiorniki, czy ktoś będzie potrzebować więcej?
Warto też wspomnieć, że pokazany tu moduł potrafi znacznie więcej - w użytej bibliotece jest nawet demko enkodera, ale nie miałem żadnego pod ręką by je dzisiaj wypróbować:
Spoiler:
Kod: C / C++
Ale nawet i bez tego mogę stwierdzić, że to bardzo przydatny układ. A jak Wy uważacie? Czy korzystaliście w swoich projektach z PCF8574 a jeśli tak to do czego?
Fajne? Ranking DIY Pomogłem? Kup mi kawę.