Spisu treści:

Magistrala I2C dla ATtiny i ATmega: 8 kroków
Magistrala I2C dla ATtiny i ATmega: 8 kroków

Wideo: Magistrala I2C dla ATtiny i ATmega: 8 kroków

Wideo: Magistrala I2C dla ATtiny i ATmega: 8 kroków
Wideo: Arduino 25: MAGISTRALA I2C 2024, Lipiec
Anonim
Magistrala I2C dla ATtiny i ATmega
Magistrala I2C dla ATtiny i ATmega

Uwielbiam mikrokontrolery Atmel AVR! Od czasu zbudowania systemu rozwoju getta opisanego w tej instrukcji, nie miałem końca zabawy eksperymentując z AVR ATtiny2313 i ATmega168 w szczególności. Posunąłem się nawet do napisania instrukcji dotyczącej używania przełączników jako wejść i rozszerzyłem koncepcję systemu rozwoju getta na CPLD. Podczas ostatniego projektu potrzebowałem kilku przełączników do ustawiania wartości kontrolnych. AVR nie miały wystarczającej liczby pinów I/O, więc musiałem coś wymyślić. Mógłbym wypróbować złożony system wejściowy z klawiaturą i wyświetlaczem, ale ATtiny2313 wyczerpałby się zasoby. Na szczęście Atmel zapewnił sposób na obejście tego problemu, dołączając interfejs, który może łączyć się z dodatkowymi układami (takimi jak pamięć lub porty I/O) za pomocą prostego dwuprzewodowego interfejsu. Zgadza się, używając tylko dwóch pinów I/O na AVR, możemy uzyskać dostęp do wielu dodatkowych pinów I/O, a także innych zasobów. Ten dwuprzewodowy interfejs jest formalnie znany jako magistrala Inter-Integrated Circuit lub po prostu magistrala I2C i został wynaleziony przez NXP, gdy był jeszcze półprzewodnikami Philips. Jeśli czytasz tę instrukcję, prawdopodobnie słyszałeś o magistrali I2C i być może nawet używałeś jej na PIC lub innym mikrokontrolerze. Chociaż koncepcyjnie bardzo proste i obsługiwane przez zasoby sprzętowe w amplitunerach AVR, sterowniki programowe są nadal niezbędne do korzystania z magistrali I2C. Atmel udostępnia uwagi dotyczące aplikacji (patrz Zasoby w dalszej części tej instrukcji), ale są one niekompletne i nie pokazują żadnych przykładów poza komunikacją z innym urządzeniem AVR. Celem tej instrukcji nie jest nauczenie nikogo, jak tworzyć sterowniki I2C dla AVR. Zamiast tego przedstawię rozszerzone wersje sterowników Atmel dla urządzeń ATtiny2313 i ATmega168, wyjaśnię wymagania i ograniczenia, które obowiązują podczas korzystania z nich, a także pokażę działające przykłady urządzeń I2C. Po przejściu tego Instructable będziesz mógł z powodzeniem korzystać z magistrali I2C w swoich projektach AVR. Oczywiście możesz zignorować sterowniki dla małego lub MEGA, jeśli jesteś zainteresowany tylko jednym z nich. Dla zainteresowanych poznaniem magistrali I2C podam linki do odpowiednich materiałów.

Krok 1: O co właściwie chodzi z tymi I2C?

O co chodzi z tym wszystkim I2C?
O co chodzi z tym wszystkim I2C?
Co to właściwie za I2C?
Co to właściwie za I2C?
O co chodzi z tym wszystkim I2C?
O co chodzi z tym wszystkim I2C?
O co chodzi z tym wszystkim I2C?
O co chodzi z tym wszystkim I2C?

Magistrala I2C to proste, dwuprzewodowe połączenie, które może łączyć ze sobą wiele urządzeń i umożliwiać im wymianę danych. W najprostszej postaci istnieje jedno urządzenie nadrzędne, które komunikuje się z wieloma urządzeniami podrzędnymi. Wszystkie urządzenia są połączone równolegle do dwóch przewodów magistrali I2C. Dwa przewody są znane jako SCL i SDA. SCL to linia zegara i jest kontrolowana przez urządzenie nadrzędne. SDA to dwukierunkowa linia danych. Aby przesłać dane, urządzenie nadrzędne wysyła adres podrzędny połączony z jednobitową flagą odczytu/zapisu. Jeśli wymagany jest zapis, master będzie kontynuował wysyłanie danych do adresowanego slave'a. Jeśli zażądano odczytu, slave odpowie danymi. Aby koordynować transakcje, linie SCL i SDA są manipulowane przez master i slave, aby zasygnalizować kilka warunków. Należą do nich START, STOP, ACK (potwierdzenie) i NAK (brak potwierdzenia). Szczegółami tych warunków zajmują się kierowcy. Prawdziwi geekowie wśród was mogą poznać wszystkie szczegóły w linkach podanych na końcu tej instrukcji. Wymagania elektryczne są dość proste. Master i slave muszą używać tego samego poziomu dla Vcc, uziemienia muszą być połączone, a linie SCL i SDA muszą być podciągnięte do Vcc. Wartość rezystorów podciągających jest dokładnie określona na podstawie obliczeń opartych na całkowitej pojemności szyny, ale praktycznie może wynosić prawie dowolną wartość między 1,8K a 10K. Zaczynam od 5.1K i używam niższych wartości, dopóki nie zadziała. Zwykle nie stanowi to problemu, chyba że masz dużo urządzeń lub długie odcinki przewodów między urządzeniami. Nominalna szybkość transmisji danych na magistrali I2C wynosi 100 Kb/s. Możliwe są również szybkości 400 Kbit / sekundę, 1 Mbit / sekundę i wyższe, ale nie są obsługiwane przez sterowniki w tej instrukcji. Wszystkie urządzenia I2C będą działać z szybkością 100Kbit/s. ATtiny2313 i ATmega168 implementują magistralę I2C w inny sposób. ATtiny2313 wykorzystuje sprzęt Universal Serial Interface (USI) - który może być również użyty do magistrali SPI. ATmega168 ma dedykowany sprzęt dla magistrali I2C znanej jako interfejs dwuprzewodowy (TWI). Po napisaniu sterowników różnice te są w większości niewidoczne dla użytkownika. Jedna istotna różnica dotyczy oprogramowania: sterownik ATmega168 I2C jest sterowany przerwaniami, podczas gdy sterownik ATtiny2313 nie. Oznacza to, że program ATmega168 nie musi czekać na transmisję danych I2C, a jedynie musi czekać przed zainicjowaniem kolejnego transferu lub na przybycie danych z operacji odczytu. Poniższe przykłady i dyskusja powinny to wyjaśnić. Adresy I2C mają długość 7 bitów, więc do 127 urządzeń może znajdować się na magistrali, jeśli każde ma unikalny adres. Jak pokazano na rysunku, ten 7-bitowy adres jest przesuwany w lewo o jeden bit, a najmniej znaczący bit jest używany do oflagowania odczytu lub zapisu urządzenia pod adresem. Tak więc pełny adres urządzenia podrzędnego to 8-bitowy bajt. Rzeczywisty adres jest częściowo określany wewnętrznie w urządzeniu i nie można go zmienić (4 najbardziej znaczące bity), a częściowo określany przez bity, które mogą być podłączone do pinów urządzenia (3 najmniej znaczące bity), które można ustawić na wysokim lub niskim poziomie konkretny adres. Brzmi dezorientująco, ale przykład wyjaśni to. Karta katalogowa PCA8574A pokazuje, że cztery najbardziej znaczące bity adresu I2C zawsze będą miały wartość 0111. Kolejne trzy bity są określone przez ustawienia na pinach AD0, AD1 i AD2. Piny te mogą być połączone z masą lub z dodatnim napięciem zasilającym (5 woltów), aby odpowiednio reprezentować 0 lub 1. Tak więc zakres możliwych adresów wynosi od 38 do 3F w systemie szesnastkowym, jak pokazano na drugim rysunku z karty katalogowej PCA8574. Tak więc, zmieniając ustawienia bitów adresu, do 8 PCA8574A może być jednocześnie na magistrali I2C. Każdy odpowie tylko na swój konkretny adres urządzenia podrzędnego. Jeśli potrzeba jeszcze więcej portów I/O, można użyć PCA8574. Jedyną różnicą między PCA8574 a PCA8574A jest to, że zakres adresów I2C slave PCA8574 wynosi od 20 do 27 szesnastkowo. Ustalenie adresu danego urządzenia może być mylące, ponieważ niektóre arkusze danych uznają bit odczytu/zapisu za część adres. Przeczytaj uważnie arkusz danych i pamiętaj, że adres urządzenia podrzędnego będzie miał długość 7 bitów. Bit odczytu/zapisu należy traktować oddzielnie. Ponownie pomoże przykład. Karta danych EEPROM 24C16, z którą będziemy eksperymentować, mówi, że pierwsze (najbardziej znaczące) cztery bity adresu urządzenia podrzędnego to 1010. Kolejne trzy bity mogą być określone przez A0, A1 i A2; Należy jednak pamiętać, że arkusz danych obejmuje również pamięci od 24C01 do 24C08, które są pamięciami EEPROM o mniejszych rozmiarach. Rysunek z arkusza danych pokazuje, że ustawienia tych bitów adresu są ignorowane wraz ze wzrostem rozmiaru i są całkowicie ignorowane dla 24C16. Oznacza to, że ostatnie trzy bity nie mają znaczenia, a 24C16 naprawdę używa wszystkich adresów slave I2C od 50 do 57 szesnastkowo. Zakres adresów slave będzie faktycznie adresował różne sekcje w 24C16. Pierwsze 256 bajtów znajduje się pod adresem 50h, następne 256 w 51h i tak dalej, aż do ostatnich 256 w 57h - w sumie 2K bajtów. Ponieważ adres pamięci RAM PCF8570, z którym również eksperymentujemy, mieści się w tym zakresie, 24C16 i PCF8570 nie mogą być używane razem.

Krok 2: Zamów niektóre urządzenia I2C

Skoro już wiesz trochę o magistrali I2C i chcesz z niej korzystać, dlaczego nie zamówić teraz kilku urządzeń I2C do eksperymentowania, aby mogły być w drodze do Ciebie, gdy będziesz przygotowywać oprogramowanie? Odpowiednie urządzenia obejmują I/ O Interface Expander (mój ulubiony), statyczna pamięć RAM i EEPROM. Jest o wiele więcej, ale to świetny początek. Procesory AVR, których użyjemy, to ATtiny2313 i Atmega168 (używane w Arduino). Jeśli jesteś w nich nowy, spójrz na ten wspaniały Instruktaż, aby dowiedzieć się o nich i zbudować swój system rozwoju getta. Schemat ATmega168 w niniejszym Instructable pokazuje, jak wdrożyć system rozwoju getta dla tego procesora. Kabel portu równoległego jest taki sam jak kabel ATtiny2313. (Nie próbowałem wersji USB systemu rozwoju getta, więc nie jestem pewien, w jaki sposób uzyskuje się dostęp do magistrali I2C. To samo dla Arduino.) Oto numery części Digikey. Ekspander portów: IC I2C I/O EKSPANDER 568-4236-5-NDRAM:IC SRAM 256X8 W/I2C 568-1071-5-NDEEPROM:IC EEPROM SZEREGOWY 16K CAT24C16LI-G-ND

Krok 3: Sterowniki I2C

Oto opisy funkcji sterownika dla magistrali I2C. Zostały one opracowane przy użyciu Atmel Apps Notes na początek. Nie mógłbym tego zrobić bez nich jako bazy, na której mógłbym budować. Rozwój został wykonany przy użyciu WinAVR i kompilatora gcc C. Poniżej opisano ograniczenia częstotliwości taktowania dla każdego procesora. Ponieważ nie jestem w stanie przetestować wszystkich możliwych kombinacji smaków procesora / częstotliwości taktowania, po prostu ograniczę się do tego, co faktycznie mogę przetestować i spróbuję wskazać ograniczenia i ograniczenia. Oto funkcje sterownika i sposób ich użycia. Proszę spojrzeć na przykłady, aby uzyskać więcej szczegółów i zobaczyć funkcje używane w kompletnych programach. Dla ATtiny2313:Clock Wymagania: Sterowniki są zaprojektowane dla częstotliwości zegara 1MHz (wartość domyślna) dla ATtiny2313. Jeśli chcesz działać z innymi szybkościami, będziesz musiał dostosować stałe w sterownikach. Napisz do mnie, jeśli potrzebujesz pomocy. Możesz również uzyskać kilka wskazówek z notatek aplikacji Atmel w odnośnikach w kroku Resources. USI_TWI_Master_Initialise() Ta funkcja inicjuje sprzęt USI do pracy w trybie I2C. Wywołaj to raz na początku programu. Zwraca void i nie ma żadnych argumentów. USI_TWI_Get_State_Info()Ta funkcja zwraca informacje o błędzie I2C i jest używana, jeśli podczas transakcji I2C wystąpił błąd. Ponieważ ta funkcja zwraca tylko kod błędu, używam funkcji TWI_Act_On_Failure_In_Last_Transmission(TWIerrorMsg) do migania diody błędu. Kody błędów są zdefiniowane w USI_TWI_Master.h. Oto jak to nazwać:TWI_Act_On_Failure_In_Last_Transmission(USI_TWI_Get_State_Info())USI_TWI_Start_Read_Write() Ta funkcja służy do odczytu i zapisu pojedynczych bajtów do urządzeń I2C. Służy również do zapisywania wielu bajtów. Korzystanie z tej funkcji składa się z 6 kroków. 1) Zadeklaruj, że bufor komunikatów w twoim programie przechowuje adres urządzenia podrzędnego i bajt danych do wysłania lub odebrania. unsigned char messageBuf (MESSAGEBUF_SIZE);2)Umieść adres Slave jako pierwszy bajt w buforze. Przesuń go o jeden bit w lewo i OR w bicie odczytu/zapisu. Zauważ, że bit odczytu/zapisu będzie wynosił 1 dla odczytu i 0 dla zapisu. Ten przykład dotyczy odczytu. messageBuf(0) = (TWI_targetSlaveAddress<<TWI_ADR_BITS) | (PRAWDA<<TWI_READ_BIT); 3)Podczas wykonywania zapisu umieść bajt do zapisania w następnej lokalizacji w buforze.4)Wywołaj funkcję USI_TWI_Start_Read_Write z buforem wiadomości i rozmiarem wiadomości jako arguments.temp = USI_TWI_Start_Read_Write(messageBuf, 2);5) zwróconą wartość (w tym przypadku temp) można przetestować, aby sprawdzić, czy wystąpił błąd. Jeśli tak, to jest traktowane jak omówiono powyżej. Zobacz przykłady w programach. 6) Jeśli zażądano odczytu, odczytany bajt będzie w drugiej lokalizacji w buforze. Jeśli ma być zapisanych wiele bajtów (np. do urządzenia pamięci), można użyć tej samej procedury. Konfiguracja bufora i wywoływanie procedury są nieco inne. Drugi bajt w buforze będzie początkowym adresem pamięci do zapisu. Dane do zapisu będą w kolejnych bajtach. Rozmiar wiadomości będzie rozmiarem zawierającym wszystkie prawidłowe dane. Więc jeśli ma być zapisanych 6 bajtów, wtedy rozmiar wiadomości wyniesie 8 (adres slave + adres pamięci + 6 bajtów danych). USI_TWI_Start_Random_Read() Ta funkcja służy do odczytywania wielu bajtów z urządzenia I2C, zazwyczaj ma to znaczenie tylko dla jakieś wspomnienie. Korzystanie z tej procedury jest bardzo podobne do poprzedniej procedury, z dwoma wyjątkami. Ustawienie bitu odczytu/zapisu nie ma znaczenia. Wywołanie tej procedury zawsze spowoduje wykonanie operacji odczytu. Rozmiar wiadomości powinien wynosić 2 plus liczba odczytanych bajtów. Jeśli nie wystąpiły żadne błędy, dane będą w buforze rozpoczynającym się od drugiej lokalizacji. Dla ATmega168:Clock Requirement:The sterowniki są zaprojektowane dla częstotliwości taktowania 4 MHz dla ATmega168. Przykładowy kod pokazuje, jak ustawić tę częstotliwość zegara. Jeśli chcesz działać z innymi szybkościami, będziesz musiał dostosować stałe w sterownikach. Napisz do mnie, jeśli musisz to zrobić. TWI_Master_Initialise() Ta funkcja inicjuje sprzęt TWI do pracy w trybie I2C. Wywołaj to raz na początku programu. Zwraca void i nie ma argumentów. Upewnij się, że włączyłeś przerwania, wywołując swi() po inicjalizacji. TWI_Get_State_Info() Ta funkcja zwraca informacje o błędzie I2C i jest używana, jeśli wystąpił błąd podczas transakcji I2C. Ponieważ ta funkcja zwraca tylko kod błędu, używam funkcji TWI_Act_On_Failure_In_Last_Transmission(TWIerrorMsg) do migania diody błędu. Kody błędów są zdefiniowane w TWI_Master.h, ale są modyfikowane w celu sygnalizacji na diody LED błędu. Zobacz przykładowy kod, aby uzyskać szczegółowe informacje. Oto jak to nazwać:TWI_Act_On_Failure_In_Last_Transmission(TWI_Get_State_Info())Zauważ, że sprawdzanie błędów odbywa się poprzez upewnienie się, że transakcja I2C jest zakończona (funkcja opisana poniżej), a następnie testowanie bitu w globalnym słowie statusu. TWI_Start_Read_Write()TWI_Start_Random_Read()Te dwie funkcje działają tak samo jak odpowiadające im funkcje opisane powyżej, ale z kilkoma wyjątkami. Nie zwracają żadnych wartości błędów. Odczytane dane nie są przekazywane do bufora. Zostanie to wykonane za pomocą funkcji opisanej dalej. Podczas wywoływania TWI_Start_Random_Read, messageSize powinien być liczbą żądanych bajtów danych plus jeden, a nie dwa. Sterownik I2C dla ATmega168 jest sterowany przerwaniami. Oznacza to, że transakcje I2C są uruchamiane, a następnie wykonywane niezależnie, podczas gdy główna procedura nadal działa. Gdy główna procedura potrzebuje danych z rozpoczętej transakcji I2C, musi sprawdzić, czy dane są dostępne. Sytuacja jest taka sama w przypadku sprawdzania błędów. Główna procedura musi mieć pewność, że transakcja I2C została zakończona przed sprawdzeniem błędów. Do tych celów wykorzystywane są dwie następne funkcje. TWI_Transceiver_Busy()Wywołaj tę funkcję, aby sprawdzić, czy transakcja I2C została zakończona przed sprawdzeniem błędów. Przykładowe programy pokazują, jak używać this. TWI_Read_Data_From_Buffer()Wywołaj tę funkcję, aby przesłać dane z bufora odbioru sterownika I2C do bufora komunikatów. Ta funkcja upewni się, że transakcja I2C została zakończona przed przesłaniem danych. Podczas gdy ta funkcja zwraca wartość, uważam, że sprawdzanie bitu błędu bezpośrednio jest bardziej niezawodne. Oto jak to nazwać. Rozmiar wiadomości powinien być o jeden większy niż żądana liczba bitów danych. Dane będą w messageBuf począwszy od drugiej lokalizacji.temp = TWI_Read_Data_From_Buffer(messageBuf, messageSize);

Krok 4: Budujmy

Zbudujmy!
Zbudujmy!
Zbudujmy!
Zbudujmy!
Zbudujmy!
Zbudujmy!
Zbudujmy!
Zbudujmy!

Zacznij od pobrania pliku I2C Schematics.zip. Możesz utworzyć folder I2C w swoim obszarze roboczym, aby przechowywać schematy i przykładowe pliki programów. Rozpakuj schematy do tego katalogu. Znajdziesz folder o nazwie Schematy I2C. Otwórz plik o nazwie tiny I2C.pdf. Ten schemat przedstawia system rozwoju getta ATtiny2313 oraz ekspander portów we/wy PCA8574A (otoczony dużym polem przerywanym). Układ Port Expander zbudowany jest na płytce stykowej. Spójrz na zdjęcia, aby zobaczyć, jak wyglądają te obwody. Są naprawdę bardzo proste. Część schematu ATtiny2313 to po prostu system rozwoju getta z trzema migającymi światłami (LED1, 2 i 3 oraz R4, 5 i 6) i podłączonym do niego przyciskiem (S1), plus jeden dodatkowy szczegół. Ten szczegół to dodanie zworek (JP4, 5 i 6), które można usunąć, aby umożliwić podłączenie linii SCL i SDA magistrali I2C. Zworki muszą być założone do programowania, a następnie usunięte, aby można było połączyć SCL i SDA. Zdjęcia przedstawiają zworki na miejscu i zdjęte. Umieszczenie tych zworek zależy od Ciebie, wystarczy umieścić je w swoim Getto Development System, jeśli chcesz korzystać z magistrali I2C. Magistrala I2C musi być odłączona, a zworki założone do programowania. Zauważ, że tak naprawdę musisz zajmować się tylko JP4 i JP6 dla magistrali I2C. Wstaw JP5, jeśli myślisz, że kiedykolwiek będziesz chciał korzystać z magistrali SPI. Wprowadzenie ekspandera portów I/O PCA8574A jest bardzo proste. Zapewnij połączenia Vcc (+5 woltów) i Gnd (masa) i podłącz AD0, 1 i 2 do uziemienia (sprawia, że adres podrzędny I2C wynosi 38 hex). Następnie podłącz 4 mrugające światła i 4 przełączniki DIP. (Jeśli nie masz przełączników DIP, możesz po prostu użyć przewodów. Powiąż z uziemieniem lub pozostaw pływający, aby włączyć lub wyłączyć sygnał.) Na koniec podłącz rezystory podciągające (R11 i 12) z SDA i SCL do Vcc. Są one pokazane jako 3,3K, ale każda wartość od 1,8K do 5,1K powinna działać (może do 10K, ale tego nie próbowałem). Po zaprogramowaniu ATtiny2313 możesz usunąć zworki i podłączyć SDA i SCL do testów. Teraz dla ATmega168. Jedyną zmarszczką jest to, że być może nie zbudowałeś systemu rozwoju getta dla tego procesora. Jeśli tak jest, to przedstawiony przeze mnie schemat (MEGA I2C.pdf) pokaże, jak to zrobić. To tylko permutacja wersji ATtiny2313. Jeśli planujesz z wyprzedzeniem, możesz upewnić się, że kabel do programowania będzie pasował do obu systemów. Główną różnicą jest dodanie C2 i C3. Zobacz zdjęcia, jak je umieścić, powinny być bardzo blisko chipa; jeden z nich jest faktycznie pod chipem. Pomagają one w zapobieganiu szumom w szczególności przetwornika analogowo-cyfrowego. Nie musisz zakładać zworek, chyba że planujesz użyć magistrali SPI, ponieważ nie są one potrzebne do magistrali I2C na tym chipie. Zauważ, że płytka stykowa PCA8754A pozostanie niezmieniona. Po prostu podłączysz SDA i SCL i gotowe! Spokojnie, co?

Krok 5: Kodujmy i testujmy

Kodujmy i testujmy!
Kodujmy i testujmy!
Kodujmy i testujmy!
Kodujmy i testujmy!
Kodujmy i testujmy!
Kodujmy i testujmy!

Czas zbudować sterowniki i przykładowe programy. Zaczniemy od ATtiny2313 i płytki prototypowej PCA8574A, które właśnie zbudowaliśmy. Pobierz plik I2C.zip do katalogu roboczego I2C i rozpakuj go. Otrzymasz nowy folder o nazwie I2C. Znajdziesz w nim USI I2C (dla ATtiny2313) oraz TWI I2C (dla ATmega168). W USI I2C znajdziesz folder I_O Port. Ten folder zawiera kod naszego pierwszego przykładowego programu oraz sterowniki USI I2C. Używając WinAVR, skompiluj i załaduj kod do ATtiny2313. Weź głęboki oddech i włącz zasilanie. Oto, czego można się spodziewać: Po włączeniu, dioda LED 1 na porcie PD6 ATtiny2313 miga dwa razy. Nic więcej się nie stanie, dopóki nie naciśniesz przycisku (S1). Po każdym naciśnięciu przycisku przełączniki są odczytywane, a ich ustawienie będzie wyświetlane na diodach LED podłączonych do PCA8574A. Zmień wartość przełączników, naciśnij przycisk, a diody powinny się zmienić. Rób to, aż przestaniesz czuć dreszczyk emocji, gdy zobaczysz, że to działa. Jeśli (nie daj Boże!) coś nie działa zgodnie z oczekiwaniami, dokładnie sprawdź okablowanie. Błędy I2C będą sygnalizowane mruganiem diody LED3 (PD4) i prawdopodobnie oznacza to, że trzeba sprawdzić, czy SDA i SCL są podłączone do właściwych pinów i prawidłowo podciągnięte. Jeśli nadal nie działa, przeczytaj resztę tej sekcji, aby dowiedzieć się o debugowaniu. Teraz wróć i spójrzmy na kod. Otwórz plik USI_I2C_Port.c. To jest kod przykładowego programu. (USI_TWI_Master.c i USI_TWI_Master.h zawierają sterowniki - możesz je zignorować, chyba że jesteś ciekawy.) Użyj tego przykładu, aby poprowadzić własne aplikacje I2C. Przeważnie program pokazuje, jak zainicjować i używać sterowników I2C, w tym ustawienia w górę adresu urządzenia podrzędnego i reszty bufora wiadomości oraz wyciągnięcie z niego danych. Zobaczysz także, jak odbijam przycisk i ustawiam pętlę while. Warto wspomnieć o kilku szczegółach programu. Zwróć uwagę, że dane z przełączników są odwracane, zanim zostaną zapisane do diod LED na ekspanderze portów. Należy również zauważyć, że porty wejściowe w ekspanderze portów muszą być zapisane jako wysokie, aby działały prawidłowo. Szczegóły te opisane są w karcie katalogowej PCA8574A. Zawsze uważnie czytaj arkusze danych! Bardziej interesujące jest użycie debugowania warunkowego. Na początku pliku programu znajduje się instrukcja //#define DEBUG, a w kodzie rozsiane są instrukcje #ifdef DEBUG. Dopóki DEBUG nie jest zdefiniowane (dwa ukośniki czynią wiersz komentarzem i uniemożliwiają jego zdefiniowanie), kod zawarty w instrukcjach #ifdef do #endif nie zostanie skompilowany. Ale jeśli coś nie działa zgodnie z oczekiwaniami, przekompiluj i ponownie załaduj kod z #define DEBUG bez komentarza. Otrzymasz o wiele więcej mrugnięć na diodach LED, które możesz zdekodować, aby śledzić wykonanie programu i pomóc ci znaleźć dokładne miejsce, w którym coś pójdzie nie tak. W rzeczywistości polecam spróbować tego, aby zobaczyć, co się stanie. Zobaczysz, że dioda LED 2 (na PD5) będzie migać w miarę postępu wykonywania programu. Wartość odczytana z przełączników będzie migać na diodzie LED 1 (PD6), zanim zostanie wyświetlona na diodach LED ekspandera portów. Powinieneś być w stanie śledzić program podczas jego działania za pomocą tych diod LED. Następnie będziemy pracować z ATmega168; pomiń tę sekcję, jeśli interesuje Cię tylko ATtiny2313. Nadal ze mną? Dobry. Przejdź do folderu TWI_I2C, zmień katalog roboczy na IO_Port, skompiluj i załaduj TWI_I2C_Port.c do ATmega168. Odłącz linie SDA i SCL od ATtiny2313 i podłącz je do ATmega168. Podłącz zasilanie i uziemienie i włącz zasilanie. Operacja powinna być taka sama! Graj, aż dreszczyk minie, potem spójrzmy na kod. Otwórz TWI_I2C_Port.c. Kod jest prawie identyczny, z wyjątkiem obsługi błędów i dostosowania sterowników sterowanych przerwaniami. Oto różnice: Zauważ, że zegar musi być ustawiony na 4 MHz, aby magistrala I2C działała poprawnie. Sei(); Instrukcja włącza przerwania po zainicjowaniu sterowników I2C. Aby sprawdzić błędy, testowany jest określony bit stanu. Podczas odczytu należy wywołać funkcję TWI_Read_Data_From_Buffer, aby przenieść odczytane dane do bufora wiadomości. Podczas zapisu należy użyć while (TWI_Transceiver_Busy()), aby upewnić się, że przesyłanie zostało zakończone przed sprawdzeniem błędów. Te dwie ostatnie funkcje zostały opisane powyżej w opisie sterowników. Poza tym kod jest prawie taki sam jak dla ATtiny2313. DEBUG działa tak samo, jeśli chcesz z tym poeksperymentować.

Krok 6: Korzystanie z pamięci I2C

Korzystanie z pamięci I2C
Korzystanie z pamięci I2C
Korzystanie z pamięci I2C
Korzystanie z pamięci I2C
Korzystanie z pamięci I2C
Korzystanie z pamięci I2C
Korzystanie z pamięci I2C
Korzystanie z pamięci I2C

Teraz, gdy nauczyliśmy się używać magistrali I2C do odczytu i zapisu ekspandera portów I/O, przejdźmy do używania pamięci I2C, zarówno RAM, jak i EEPROM. Główną różnicą jest to, że wiele bajtów można odczytać lub zapisać z pamięci za pomocą jednego polecenia I2C. Aby przygotować się do tych eksperymentów, musimy nieco zmodyfikować sprzęt i zbudować kilka nowych obwodów na płytce prototypowej. Zachowaj obwód ekspandera portów, ponieważ użyjemy go do wyświetlania niektórych wartości pamięci. Usuń przełączniki DIP z PCA8574A i umieść migające światła na tych pinach. Jeśli nie masz wystarczającej liczby migających świateł, przesuń te z P4 do P7 do P0 do P3. (Wartości do wyświetlenia są wystarczająco małe.) Teraz spójrz na schemat I2C Ram.pdf i podłącz PCF8570 do płytki stykowej. Spójrz również na zdjęcie. Pamiętaj, aby związać pin 7 z Vcc. Poprowadź przewody dla SDA i SCL z PCA8574A. Nie są wymagane żadne dodatkowe rezystory podciągające. Jeśli jesteś również zainteresowany EEPROM, zbuduj ten obwód również za pomocą I2C EEPROM.pdf dla 24C16, ale pamiętaj, że przykład używa ATmega168. Ten obwód jest naprawdę prosty. Jak omówiono powyżej, bity adresu powinny być ignorowane. Wystarczy podłączyć zasilanie i uziemienie. Nie podłączaj jeszcze SDA i SCL, ponieważ nie zakończyliśmy eksperymentów z pamięcią RAM. Zaczniemy nasze eksperymenty z pamięcią od ATtiny2313 podłączonego do ekspandera portów PCA8574A i do pamięci RAM PCF8570. Program zapisze kilka liczb do pamięci RAM, a następnie odczyta je z powrotem i wyświetli na ekspanderze portów. Zmień katalog roboczy na RAM pod USI I2C. Użyj pliku make, aby skompilować i pobrać plik USI_I2C_RAM.c. Zauważ, że pliki sterownika I2C są identyczne z tymi, których używaliśmy wcześniej. Podłącz zasilanie i powinieneś zobaczyć pojedyncze mignięcie diody LED 1 (PD6). Dane zostaną zapisane do pierwszych 4 bajtów pamięci. Naciśnij przycisk, a dwa bajty zostaną odczytane i wyświetlone. Powinieneś zobaczyć jedną diodę LED na ekspanderze portów (P0), dwie sekundy przerwy, a następnie dwie diody LED (P0 i P1). Kolejna dwusekundowa przerwa i diody LED powinny zgasnąć. Naciśnij przycisk ponownie, aby rozpocząć sekwencję od nowa. Debugowanie jest podobne do metody opisanej powyżej. Rzućmy okiem na kod. Otwórz USI_I2C_RAM.c. Powinien wyglądać podobnie do poprzedniego kodu. Główne różnice to szczegóły pamięci do czytania i pisania. Spójrz na sposób, w jaki bufor wiadomości jest ładowany przed wywołaniem, które faktycznie wykonuje zapis. Pierwszy bajt to adres urządzenia podrzędnego z odpowiednio ustawionym bitem odczytu/zapisu. Ale następny bajt to adres pamięci, pod którym należy rozpocząć zapisywanie danych. Następnie pojawiają się rzeczywiste bajty danych, które będą kolejno ładowane do pamięci, zaczynając od podanego adresu. Podajemy rozmiar wiadomości na 6. Zaczynamy więc pisać pod adresem 00 i zapisujemy wartości 01, 03, 02 i 06 w komórkach pamięci od 00 do 03. Aby odczytać dane z powrotem z pamięci musimy użyć funkcji USI_TWI_Start_Random_Read. Bufor wiadomości pobiera adres urządzenia podrzędnego w pierwszym bajcie i adres początkowy w drugim bajcie. Następnie wywołaj funkcję z rozmiarem komunikatu ustawionym na liczbę bajtów do odczytu plus 2. Zauważ, że bit odczytu/zapisu nie ma znaczenia, ponieważ odczyt zostanie wykonany niezależnie. Zwrócone dane rozpoczną się w drugiej lokalizacji w buforze wiadomości. Po wczytaniu dane są odwracane do wyświetlania na ekspanderze portów i zapisywane po jednym bajcie z przerwą między wartościami. Wreszcie, diody LED ekspandera portów są wyłączone. Zapisy do Port Expander są identyczne jak w poprzednich przykładach. Dla zabawy możesz odkomentować instrukcję #define DEBUG jak powyżej i zobaczyć wiele mrugających diod LED. Pełni podekscytowania po kolejnym udanym eksperymencie, przejdźmy do ATmega168 i pamięci EEPROM. Zmień katalog roboczy na EEPROM pod TWI I2C. Użyj pliku make, aby skompilować i pobrać TWI_I2C_EEPROM.c. Zauważ, że pliki sterownika I2C są identyczne z tymi, których używaliśmy wcześniej dla PCA8574A. Aby przetestować program, odłącz ATtiny2313 i podłącz ATmega168. Pozostaw magistralę I2C podłączoną do pamięci RAM i włącz zasilanie. Wyniki są inne, ponieważ teraz zapisujemy i odczytujemy więcej danych. Dioda LED 1 na PD7 powinna migać podczas inicjalizacji. Po naciśnięciu przycisku dane zostaną odczytane z pamięci i wyświetlone. Diody LED na PCA8574 powinny migać w następującej kolejności: P1, P0 i P2, (wszystkie wyłączone), P0 i P1, P1 i P2. Wreszcie diody LED portów powinny zgasnąć. Naciśnij przycisk ponownie, aby to powtórzyć. Och, ale czekaj, mówisz. Czy to nie jest program dla EEPROM? Ponieważ uzyskujemy dostęp do urządzenia pamięci pod tym samym adresem I2C, ten sam program działa zarówno dla pamięci RAM, jak i EEPROM. Wyłącz i przenieś SDA i SCL z pamięci RAM do pamięci EEPROM i ponownie uruchom program. Powinno działać dokładnie tak samo. Zauważ, że EEPROM i RAM nie mogą być podłączone do magistrali I2C w tym samym czasie, ponieważ mają ten sam adres. (Mądrzy spośród was mogą rozważyć zmianę programowalnych bitów adresu w pamięci RAM, ale to nadal nie zadziała. 24C16 używa całego bloku adresów, które można zaprogramować dla pamięci RAM.) OK, spójrzmy na ten ostatni program. Otwórz TWI_I2C_EEPROM.c. Pierwszą rzeczą, na którą należy zwrócić uwagę, jest to, że wskazałem, jak zaadresować całą pamięć EEPROM 24C16. Można uzyskać do niego dostęp w 256 bajtowych kawałkach pod 8 różnymi adresami I2C slave. Zobacz, jak MEMORY_ADDR jest zdefiniowany jako adres początkowy 50 szesnastkowo; dlatego Baran działał. Jeśli chcesz uzyskać dostęp do innych bloków 24C16, użyj innych adresów, jak wskazałem. Zobacz, jak ustawiłem zapisywanie w pamięci. Najpierw adres slave z ustawionym bitem odczytu/zapisu jest umieszczany w buforze, następnie adres początkowy 00, a następnie 16 bajtów danych. Funkcja TWI_Start_Read_Write jest wywoływana do zapisu danych (jak poprzednio) z rozmiarem wiadomości ustawionym na 18. Po naciśnięciu przycisku używamy TWI_Start_Random_Read i TWI_Read_Data_From_Buffer do odczytu danych z powrotem. Co trzeci bajt jest wyświetlany na diodach LED ekspandera portów. Wreszcie diody LED są wyłączane, aby czekać na kolejne naciśnięcie przycisku. Możesz się zastanawiać, dlaczego wybrałem napisanie 16 bajtów. Jeśli uważnie przeczytasz arkusz danych, zobaczysz, że 24C16 wykonuje cykl zapisu za każdym razem, gdy otrzyma 16 bajtów, nawet jeśli wysyłanych jest więcej bajtów. Wydawało się więc, że to fajna liczba do użycia. Jeśli zdecydujesz się go zwiększyć, będziesz musiał zmienić rozmiar MESSAGEBUF_SIZE. Będziesz także musiał zmienić wartość TWI_BUFFER_SIZE w TWI_Master.h. Dzieje się tak, ponieważ sterownik kopiuje dane z bufora komunikatów do użytku przez procedurę obsługi przerwań. Gratulacje! Teraz możesz już używać magistrali I2C we własnych projektach!

Krok 7: Zasoby internetowe

Oto linki do arkuszy danych części użytych do eksperymentów. Zdecydowanie powinieneś je zdobyć, jeśli nie masz nic innego. Port ExpanderRamEEPROMJako twórca I2C, NXP (Philips) ma mnóstwo świetnych rzeczy. (Lubią używać nawiasów kwadratowych w swoich adresach URL, więc nie mogę ich tutaj poprawnie uwzględnić. Przepraszam.] Aby przejść do obszaru I2C, wybierz Interfejs z listy Produkty. Będziesz mógł przejść do ich strony I2C i dostęp do wszystkich arkuszy danych i notatek aplikacji, które oferują. Opis magistrali I2C i szczegóły techniczne są tutaj. Pobierz arkusze danych ATtiny2313 i ATmega168 (książki danych?) z Atmel. Notatki dotyczące aplikacji Atmel są tutaj. Spójrz na AVR310 i AVR315. Chwyć także kod. Zajrzyj tutaj, aby uzyskać więcej informacji o I2C.

Krok 8: Uwagi dla geeków

Dla prawdziwych maniaków, którzy chcą poznać szczegóły, oto kilka rzeczy, o których należy pamiętać, jeśli spojrzysz na uwagi do aplikacji Atmel i kod sterownika: - Metoda adresowania i wydawania poleceń urządzeniu I2C nie jest częścią specyfikacji! Inne niż adres urządzenia podrzędnego i bit odczytu/zapisu, polecenia, tryby itp. nie są określone i są specyficzne dla danego urządzenia. Aby było to bardzo jasne, zauważ, że schemat zastosowany w przykładzie Atmela dotyczy tylko tego przykładu i jest w dużej mierze niestandardowy. Implementacja USI różni się od implementacji TWI pod kilkoma ważnymi względami. + Dzięki USI taktowanie zapewnia oprogramowanie; z TWI zapewnia go generator szybkości transmisji. + Metoda USI nie używa przerwań; TWI tak. Ma to pewien sens, ponieważ rodzina Mega (korzystająca z TWI) może robić wiele innych rzeczy i nie powinna być przejmowana przez transfery I2C. Wersja sterowana przerwaniami dla USI jest z pewnością możliwa, po prostu nie jest zaimplementowana w tym Instructable. + Sprzęt USI nie jest zoptymalizowany pod kątem I2C i obsługuje tylko transfery 8-bitowe. Oznacza to, że do wysłania dziewiątego bitu wymagane są dwa transfery (albo NACK lub ACK). Sprzęt TWI obsługuje to automatycznie. To sprawia, że implementacja sterownika USI jest nieco bardziej skomplikowana. + Wykrywanie błędów dla TWI jest obsługiwane sprzętowo. USI wymaga obsługi w oprogramowaniu, co nieco komplikuje sprawę. + Sprzęt TWI bezpośrednio kontroluje konfigurację portu. Sprzęt USI wymaga skonfigurowania bitów portu przed użyciem portu. Zobaczysz to w procedurze Master_Initialize dla USI. - Atmel twierdzi, że możliwe jest użycie podciągania portów AVR do podciągania magistrali I2C. Nie wymyśliłem sposobu, aby to podejście zadziałało. Użycie dwóch zewnętrznych rezystorów wydaje się dość prostym schematem, więc nie poświęciłem temu dużo czasu.

Zalecana: