- Co to jest protokół komunikacyjny I2C?
- Jak działa komunikacja I2C?
- Gdzie korzystać z komunikacji I2C?
- I2C z PIC16F877a przy użyciu kompilatora XC8
- Programowanie za pomocą plików nagłówkowych I2C:
- Symulacja Proteus:
Mikrokontrolery PIC to potężna platforma dostarczana przez mikroczip do projektów wbudowanych, jej wszechstronny charakter sprawił, że znalazł sposoby na wiele zastosowań i faza ta wciąż trwa. Jeśli śledziłeś nasze samouczki PIC, zauważyłeś, że omówiliśmy już szeroki zakres samouczków na temat mikrokontrolera PIC, zaczynając od podstaw. Od teraz omówiliśmy podstawy, które możemy uzyskać w bardziej interesujących rzeczach, takich jak portal komunikacyjny.
W rozległym systemie aplikacji wbudowanych żaden mikrokontroler nie jest w stanie samodzielnie wykonać wszystkich czynności. Na pewnym etapie musi komunikować się z innymi urządzeniami, aby udostępniać informacje, istnieje wiele różnych typów protokołów komunikacyjnych do udostępniania tych informacji, ale najczęściej używane są USART, IIC, SPI i CAN. Każdy protokół komunikacyjny ma swoje zalety i wady. Na razie skupmy się na części IIC, ponieważ tego nauczymy się w tym samouczku.
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 za pomocą innego adresu. Po zaadresowaniu tylko maść z tym konkretnym adresem 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.
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 z PIC16F877a przy użyciu kompilatora XC8
Dość wstępów, przejdźmy do tego i dowiedzmy się, jak możemy wykorzystać mikrokontroler do realizacji komunikacji I2C. Zanim zaczniemy, wyjaśnij, że ten samouczek mówi tylko o I2C w PIC16F877a przy użyciu kompilatora XC8, proces będzie taki sam dla innych mikrokontrolerów, ale mogą być wymagane niewielkie zmiany. Pamiętaj również, że w przypadku zaawansowanych mikrokontrolerów, takich jak seria PIC18F, sam kompilator może mieć wbudowaną bibliotekę do korzystania z funkcji I2C, ale w przypadku PIC16F877A nic takiego nie istnieje, więc zbudujmy ją samodzielnie. Wyjaśniona tutaj biblioteka będzie podana jako plik nagłówkowy do pobrania na dole, który może być użyty do komunikacji PIC16F877A z innymi urządzeniami I2C.
Jak zawsze najlepszym miejscem do rozpoczęcia wszystkiego jest nasz arkusz danych. Poszukaj szczegółów na temat I2C w arkuszu danych i sprawdź, które rejestry należy skonfigurować. Nie będę wyjaśniał szczegółowo, ponieważ arkusz danych już to zrobił. W dalszej części wyjaśnię różne funkcje obecne w pliku nagłówkowym i ich odpowiedzialność w programie.
void I2C_Initialize ()
Funkcja inicjalizacji służy do poinformowania mikrokontrolera, że będziemy używać protokołu I2C. Można to zrobić, ustawiając wymagane bity w rejestrze SSPCON i SSPCON2. Pierwszym krokiem byłoby zadeklarowanie pinów IIC jako pinów wejściowych, tutaj szpilki RC3 i RC4 powinny być użyte do komunikacji I2C, więc deklarujemy je jako szpilki wejściowe. Następnie należy ustawić SSPCON i SSPCON2, które są rejestrami sterującymi MSSP. Pracujemy na PIC w trybie IIC master z częstotliwością zegara FOSC / (4 * (SSPADD + 1)). Zapoznaj się z numerami stron arkusza danych wymienionymi w wierszach komentarzy poniżej, aby zrozumieć, dlaczego ten konkretny rejestr jest ustawiony w ten sposób.
Następnie musimy ustawić częstotliwość zegara, częstotliwość zegara dla różnych aplikacji może się różnić, stąd wybór otrzymujemy od użytkownika poprzez zmienną feq_k i używamy jej w naszych formułach do ustawienia rejestru SSPADD.
void I2C_Initialize (const unsigned long feq_K) // Rozpocznij IIC jako master { TRISC3 = 1; TRISC4 = 1; // Ustaw piny SDA i SCL jako piny wejściowe SSPCON = 0b00101000; // pg84 / 234 SSPCON2 = 0b00000000; // pg85 / 234 SSPADD = (_XTAL_FREQ / (4 * feq_K * 100)) - 1; // Ustawianie szybkości zegara pg99 / 234 SSPSTAT = 0b00000000; // pg83 / 234 }
Void I2C_Hold ()
Następną ważną funkcją jest funkcja I2C_hold, która służy do wstrzymania wykonania urządzenia do zakończenia bieżącej operacji I2C. Musielibyśmy sprawdzić, czy operacje I2C muszą być wstrzymane przed rozpoczęciem jakiejkolwiek nowej operacji. Można to zrobić, sprawdzając rejestr SSPSTAT i SSPCON2. SSPSTAT zawiera informacje o stanie magistrali I2C.
Program może wydawać się nieco skomplikowany, ponieważ zawiera operator „i” oraz „lub”. Kiedy złamiesz to jako
SSPSTAT i 0b00000100 SSPCON2 i 0b00011111
Wcześniejsze
Oznacza to, że jesteśmy upewniając się, że 2 nd nieco na SSPSTAT wynosi zero i podobnie bity od 0 do 4 są zerowe na SSPCON2. Następnie łączymy to wszystko, aby sprawdzić, czy wynik wynosi zero. Jeśli wynik jest zerowy program będzie postępować, jeśli nie będzie trzymać tam, aż robi się zeru, ponieważ jest on używany w while pętli.
void I2C_Hold () { while ((SSPCON2 & 0b00011111) - (SSPSTAT & 0b00000100)); // sprawdź to w rejestrach, aby upewnić się, że IIC nie jest w toku }
Void I2C_Begin () i void I2C_End ()
Za każdym razem, gdy zapisujemy lub czytamy jakiekolwiek dane za pomocą magistrali I2C powinniśmy rozpocząć i zakończyć połączenie I2C. Aby rozpocząć komunikację I2C musimy ustawić bit SEN i aby zakończyć komunikację musimy ustawić bit statusu PEN. Przed przełączeniem któregokolwiek z tych bitów należy również sprawdzić, czy magistrala I2C jest zajęta, używając funkcji I2C_Hold, jak omówiono powyżej.
void I2C_Begin () { I2C_Hold (); // Wstrzymaj program, czy I2C jest zajęty SEN = 1; // Rozpocznij IIC pg85 / 234 } void I2C_End () { I2C_Hold (); // Wstrzymaj program jest zajęty I2C jest zajęty PEN = 1; // Koniec IIC pg85 / 234 }
Void I2C_Write ()
Funkcja zapisu służy do przesyłania dowolnych danych z modułu głównego do modułu salve. Ta funkcja jest zwykle używana po funkcji I2C begin, po której następuje funkcja I2C End. Dane, które mają zostać zapisane na magistrali IIC, są przekazywane przez dane zmienne. Dane te są następnie ładowane do rejestru bufora SSPBUF, aby wysłać je przez magistralę I2C.
Zwykle przed zapisaniem danych zostanie zapisany adres, więc będziesz musiał dwukrotnie użyć funkcji zapisu, raz do ustawienia adresu, a drugi raz do wysłania rzeczywistych danych.
void I2C_Write (dane bez znaku) { I2C_Hold (); // Wstrzymaj program jest zajęty I2C jest zajęty SSPBUF = dane; // pg82 / 234 }
unsigned short I2C_Read ()
Ostatnią funkcją, o której musimy wiedzieć, jest funkcja I2C_Read . Ta funkcja służy do odczytu danych, które są aktualnie na magistrali I2C. Jest używany po poproszeniu slave'a o zapisanie wartości na magistrali. Otrzymana wartość będzie w SSPBUF, którą możemy przenieść do dowolnej zmiennej dla naszej operacji.
Podczas komunikacji I2C slave po wysłaniu danych żądanych przez Master wyśle kolejny bit, który jest bitem potwierdzenia, ten bit powinien również zostać sprawdzony przez Mastera, aby upewnić się, że komunikacja przebiegła pomyślnie. Po sprawdzeniu bitu ACKDT do potwierdzenia, należy go włączyć ustawiając bit ACKEN.
krótki bez znaku I2C_Read (krótki komunikat bez znaku) { przychodzący krótki bez znaku; I2C_Hold (); RCEN = 1; I2C_Hold (); incoming = SSPBUF; // pobierz dane zapisane w SSPBUF I2C_Hold (); ACKDT = (ACK)? 0: 1; // sprawdź, czy otrzymano bit potwierdzenia ACKEN = 1; // pg 85/234 powrót przychodzące; }
Czyli te funkcje powinny wystarczyć do nawiązania komunikacji I2C i zapisu lub odczytu danych z urządzenia. Należy również zauważyć, że istnieje wiele innych funkcji, które może pełnić komunikacja I2C, ale ze względu na prostotę nie omawiamy ich tutaj. Zawsze możesz odwołać się do arkusza danych, aby poznać pełne działanie
Pełny kod z plikiem nagłówkowym do komunikacji PIC16F877A I2C można pobrać z linku.
Programowanie za pomocą plików nagłówkowych I2C:
Teraz, gdy dowiedzieliśmy się, jak działa komunikacja I2C i jak możemy wykorzystać utworzony dla niej plik nagłówkowy, stwórzmy prosty program, w którym użyjemy pliku nagłówkowego i zapiszemy pewne wartości w liniach I2C. Następnie zasymulujemy ten program i sprawdzimy, czy te wartości są zapisywane na magistrali.
Jak zawsze program zaczyna się od ustawienia bitów konfiguracyjnych i ustawienia częstotliwości zegara na 20 MHz, jak pokazano poniżej
#pragma config FOSC = HS // Bity wyboru oscylatora (oscylator HS) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT wyłączony) #pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT włączony) # pragma config BOREN = ON // Brown-out Reset Enable bit (BOR włączony) #pragma config LVP = OFF // Niskonapięciowe (pojedyncze zasilanie) In-Circuit Serial Programming Bit Enable (RB3 to cyfrowe we / wy, HV włączone MCLR musi być używany do programowania) #pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off) #pragma config WRT = OFF // Flash Program Memory Write Enable bits (ochrona przed zapisem wyłączona; cała pamięć programu może być napisane do kontroli EECON) #pragma config CP = OFF // Bit ochrony kodu pamięci programu Flash (ochrona kodem wyłączona) #define _XTAL_FREQ 20000000
Następnym krokiem byłoby dodanie pliku nagłówkowego, o którym właśnie rozmawialiśmy. Plik nagłówkowy nosi nazwę PIC16F877a_I2C.h i można go pobrać z linku, który omówiliśmy powyżej. Upewnij się, że plik nagłówkowy został dodany do pliku nagłówkowego listy projektów, struktura pliku projektu powinna wyglądać następująco
Po upewnieniu się, że plik nagłówkowy został dodany do pliku projektu, umieść plik nagłówkowy w głównym pliku C.
#zawierać
Wewnątrz while pętli rozpocznie się komunikacja I2C zapisu kilka losowych wartości do magistrali I2C, a następnie Zakończ komunikację I2C. Losowe wartości, które wybrałem, to D0, 88 i FF. Możesz wprowadzić dowolne wartości. Ale pamiętaj o tych wartościach, ponieważ będziemy je weryfikować w naszej symulacji.
while (1) { I2C_Begin (); I2C_Write (0xD0); I2C_Write (0x88); I2C_Write (0xFF); I2C_End (); __delay_ms (1000); }
Cały program można znaleźć na dole strony, możesz go użyć lub pobrać pełny plik zip programu z tego miejsca. Po otrzymaniu programu skompiluj go i przygotuj się do symulacji.
Symulacja Proteus:
Proteus ma fajny instrument zwany debuggerem I2C, który może być użyty do odczytu danych z magistrali I2C, więc zbudujmy obwód używając go i sprawdźmy czy dane są zapisywane poprawnie. Pełny schemat obwodu pokazano poniżej
Załaduj plik hex, który został wygenerowany przez nasz program, dwukrotnie klikając Mikrokontroler. Następnie zasymuluj program. Zauważysz wyskakujące okienko, które wyświetli wszystkie informacje o magistrali I2C. Okno naszego programu pokazane jest poniżej.
Jeśli przyjrzysz się dokładnie zapisywanym danym, możesz zauważyć, że są one takie same, jak te, które zapisaliśmy w naszym programie. Wartości to D0, 88 i FF. Wartości są zapisywane co 1 sekundę, więc czas jest również aktualizowany, jak pokazano poniżej. Niebieska strzałka wskazuje, że jest ona zapisywana od mastera do slave'a i wskazywałaby w przeciwnym kierunku, gdyby było inaczej. Bliższe spojrzenie na przesyłane dane przedstawiono poniżej.
To tylko rzut oka na to, co może zrobić I2C, może również odczytywać i zapisywać dane na wielu urządzeniach. Więcej informacji na temat I2C omówimy w naszych nadchodzących samouczkach, łącząc różne moduły współpracujące z protokołem I2C.
Mam nadzieję, że zrozumiałeś projekt i nauczyłeś się z niego czegoś pożytecznego. Jeśli masz jakiekolwiek wątpliwości, umieść je w sekcji komentarzy poniżej lub skorzystaj z forum, aby uzyskać pomoc techniczną.
Pełny kod podano poniżej; możesz pobrać pliki nagłówkowe z całym kodem stąd.