Kurs podstawowy
Wejścia i wyjścia binarne

Jedną z najważniejszych cech mikrokontrolerów są porty wejść i wyjść. Bez nich mikrokontroler, wraz ze wszystkimi układami wewnętrznymi nie miałby żadnego praktycznego znaczenia. To dzięki nim, nasza kość posiada możliwość komunikowania się ze środowiskiem zewnętrznym oraz z użytkownikiem. Wyświetlacze, klawiatury, czujniki oraz inne układy przekazują i odbierają informacje, które mikrokontroler przetwarza. Ten artykuł jest omówieniem portów wejść i wyjść mikrokontrolerów AVR i sposobu korzystania z nich.

 

Mikrokontrolery AVR posiadają niezależnie programowalne dwukierunkowe piny, będące końcówkami ośmiobitowych portów wejścia/wyjścia oznaczonych symbolami PA, PB itd. Każdy pin może być niezależnie konfigurowany jako wejście lub wyjście.

 

Schemat pojedyńczego pinu portu wejścia/wyjścia.

Rys.1 Schemat pojedynczego pinu portu wejścia/wyjścia.

 

Na rysunku 1 widać, że piny mają dołączone w strukturze wewnętrznej mikrokontrolera diody zabezpieczające oraz programowo dołączany rezystor podciągający Rpu tzw. pull-up, który podciąga napięcie na pinie do Vcc. Rezystor podciągający można załączyć tylko w przypadku, gdy pin pracuje jako wejście. Bez załączonego rezystora podciągającego pin wejściowy pracuje w trybie wysokiej impedancji, co powoduje, że napięcie na pinie może przyjmować wartości od potencjału masy do Vcc. Taka sytuacja może być przyczyną nieprawidłowej pracy mikrokontrolera, gdyż nie można kontrolować stanu pinu i wartości napięć na nim są co najmniej przypadkowe. W przypadku, gdy nie musimy przejmować się zużyciem energii, należy na pinach wejściowych załączać wewnętrzne rezystory podciągające. Pozostawianie niewykorzystanych pinów nie jest zalecane z uwagi na zwiększony pobór prądu. Aby rozwiązać problem niewykorzystanych pinów można ustawić je jako wyjścia, podłączyć wewnętrzne rezystory podciągające lub dołączyć zewnętrzne rezystory podciągające do Vcc, bądź GND. Należy unikać bezpośredniego podłączania pinów wejścia wyjścia do Vcc lub GND, gdyż w przypadku ustawienia takich pinów jako wyjścia może popłynąć zbyt duży prąd i mikroprocesor może zostać uszkodzony.

 

Tabela konfiguracji pinów portu.

Rys. 2. Tabela konfiguracji pinów portu wejścia/wyjścia.

 

Każdy port wejścia/wyjścia posiada trzy rejestry dzięki którym można skonfigurować kierunek przepływu danych każdego z pinów portu, ustawiać poziomy na pinach, a także odczytywać ich stan. Rejestr DDRx odpowiada za kierunek przepływu danych. Rejestr PORTx pełni rolę w zależności od wartości zapisanych w rejestrze DDRx. Jeżeli birt rejestru DDRx ma wartość 0 (pin jest wejściem), a odpowiadający mu bit rejestru PORTx jest ustawiony, czyli zapisana jest do niego wartość 1, to załączony jest rezystor podciągający. Wartość 0 powoduje, że wejście jest w stanie wysokiej impedancji. Dla przypadku, gdy pin jest wyjściem (bit rejestru DDRx ma wartość 1), w rejestrze PORTx odpowiadający pinowi bit ma zapisaną wartość, krtóra wystawiana jest na pinie wyjściowym. Trzecim rejestrem jest rejestr PINx. Za pomocą tego rejestru odczytujemy stan pinów wejściowych.

Należy również zwrócić uwagę, że piny portów wejścia/wyjścia posiadają alternatywne funkcje w mikrokontrolerze. Zwykle używanie funkcji alternatywnej wyklucza możliwość korzystania  z pinu jako wejścia/wyjścia. Przykładem może być interfejs JTAG. Jeśli jest on aktywny,  to nie możemy używać pinów, z których korzysta ten interfejs.

Bierzemy pod lupę teraz nasz mikrokontroler ATmega32.

 

Rys. 3. Wyprowadzenia pinów mikrokontrolera ATmega32.

 

Mikrokontroler ten posiada cztery ośmiobitowe porty wejścia/wyjścia PA, PB, PC oraz PD. Każdy z portów zarządzany jest własnymi rejestrami DDR, PORT i PIN, Na przykładzie portu PA omówimy konfiguracje portów wejścia wyjścia.

 

Rys. 4. Stan rejestrów i pinów w momencie uruchomienia mikrokontrolera.

 

Rysunek 4 przedstawia stan rejestrów portu PA w pierwszej chwili po uruchomieniu mikrokontrolera. Stan taki występuje także w chwili trwania sygnału RESET. Wszystkie rejestry są wyzerowane, W odniesieniu do portów wejścia/wyjścia oznacza, że wszystkie piny są wyjściami bez podłączonych rezystorów podciągających. Wejścia są w stanie wysokiej impedancji, Widać to dokładnie na rysunku 4 przedstawiającym model portu PA. Zmienimy teraz zawartość rejestru DDRA w taki sposób, że piny PA0, PA1, PA2 i PA3 będą wejściami z załączonymi rezystorami podciągającymi, a piny od PA4 do PA7 będą wyjściami.

 

 

Rys. 5. Stan rejestrów i pinów po ich skonfigurowaniu.

 

Jak widać na rysunku 5, piny PA0, PA1, PA2, PA3 są wejściami z załączonymi rezystorami podciągającymi. Piny PA4, PA5, PA6, PA7 są ustawione jako wyjścia. Dla pinów wyjściowych dane zapisane w rejestrze PORTA zostały wystawione są na te piny. Stan czterech młodszych bitów rejestru PINA będzie zależał od stanu linii podłączonych do odpowiadających im pinów portu PA. Z uwagi na podciągnięcie tych pinów do Vcc cztery młodsze bity rejestru PINA będą ustawione do czasu pojawienia się na nich poziomu niskiego. Jeśli chodzi o cztery starsze bity rejestru PINA, to będzie zapisany do nich stan najstarszych bitów rejestru PORTA.

Wszystkie binarne porty wejścia/wyjścia wykorzystuje się w ten sam sposób. Czas na poznanie sposobów zapisywania danych do rejestrów portów wejścia wyjścia. Tym samym przechodzimy do kolejnego etapu, jakim jest programowanie mikrokontrolerów. Wszystkie przykłady będę prezentował w języku C++.

 

Manipulowanie bitami rejestrów.

Ustawmy rejestry DDRA oraz PORTA jak na rysunku 5.  Najpierw zajmiemy się rejestrem DDRA. Można zrobić to na kilka sposobów.

 

DDRA = 0b11110000; // zapisanie do rejestru DDRA bitów podanych w zapisie binarnym

DDRA = 0xF0; // zapisanie do rejestru DDRA bitów podanych w zapisie heksadecymalnym

 

Podane wyżej sposoby ustawiania są prawidłowe, ale ... No właśnie, chodzi o to, że generalnie nie wiadomo o co chodzi. Powinniśmy dbać o to, aby nasz kod był przejrzysty i zrozumiały dla innych. Ponadto stosowanie operatora przypisania = niesie za sobą pewne konsekwencje. Mianowicie do rejestru zapisuje podaną wartość, niszcząc jednocześnie zawartość poprzednią, Czasem może być to niebezpieczne. Powinniśmy w takich przypadkach zadbać o to, aby ustawiać konkretne bity, nie niszcząc innych. Sposób w jaki będziemy pisali nasz kod będzie miał znaczenie przy bardziej złożonych projektach. Musimy zadbać, aby nie był pisany w sposób chaotyczny. Zapewniam, że pisząc kod w sposób chaotyczny będziesz miał problem, gdy wrócisz do niego po dłuższym czasie. Sam nie będziesz mógł zrozumieć o co w nim chodzi. Język C daje nam wiele udogodnień, z których należy korzystać.

 

/* definicja stałych związanych z bitami i odpowiadającymi im pinami */
#define PA0 0
#define PA1 1
#define PA2 2
#define PA3 3
#define PA4 4
#define PA5 5
#define PA6 6
#define PA7 7

/* ustawienie poszczególnych bitów rejestru DDRA, piny PA4, PA5, PA6 PA7 będą wyjściami */
DDRA |= (1 << PA4) | (1 << PA5) | (1 << PA6) | (1 << PA7);

/* załączenie na pinach wejściowych PA0, PA1, PA2, PA3 rezystorów podciągających */
PORTA |= (1 << PA0) | (1 << PA1) | (1 << PA2) | (1 << PA3);

/* ustawienie stanu wysokiego na pinach wyjściowych PA5 i PA6 */
PORTA |= (1 << PA5) | (1 << PA6);

 

W ten sposób ustawiliśmy port PA identycznie jak na rysunku 5. Od razu po włączeniu zasilania mikrokontrolera wszystkie rejestry są wyzerowane, czyli wszystkie piny są wejściami w stanie wysokiej impedancji. W liniach od 2 do 9 zdefiniowałem sobie stałe o nazwach pinów mikrokontrolera i przypisałem im numery kolejnych bitów rejestrów. W ten sposób powiązałem sobie kod z rysunkiem wyprowadzeń mikrokontrolera. Uprości nam to dalszą pracę. W linii 12 ustawiamy piny PA4 do PA7 jako wyjścia. Skorzystałem z operatora przesunięcia bitowego <<. Jako operator przypisania użyłem  operatora sumy logicznej  | oraz operatora przypisania =. W ten sposób bezpiecznie ustawiłem poszczególne bity, nie zmieniając pozostałych. W linii 15 za pomocą przesunięć bitowych załączyłem rezystory podciągające ustawiając w rejestrze PORTA na bitach 3...0 wartości 1. Linia 18 to ustawienie na pinach PA5 i PA6 poziomu wysokiego. Gwarantuję, że taka konstrukcja kodu jest czytelna i nie sprawi kłopotu w przyszłości. Stosowana jest ona praktycznie we wszystkich programach. Warto sobie wyrobić nawyk jej stosowania.

Warto wspomnieć o wszystkich sposobach manipulacji portami. Podane niżej przykłady będą właściwe dla każdego rejestru mikrokontrolera.  Wszystkie przykładowe operacje wykonywać będę na pinie PA4

Ustawianie stanu wysokiego na pinie.

 

POORTA |= (1 << PA4);

 

Ustawianie stanu niskiego na pinie.

 

PORTA &= ~(1 << PA4);

 

Zmiana stanu na pinie na przeciwny.

 

PORTA ^= (1 << PA4);

 

Sprawdzanie stanu pinu wejściowego

 

if(!PA4) {
   /* reakcja na stan niski na pinie PA4 */
} else {
   /* reakcja na stan wysoki na pinie PA4 */
}

 

Na koniec zajmiemy się jeszcze jednym bardzo ważnym aspektem dotyczącym pinów wejścia wyjścia w mikrokontrolerach ATmega. Jest nim obciążalność pinów. Tutaj należy bezwzględnie przestrzegać informacji zawartych w dokumentacjach. Każdy mikrokontroler ma swoje parametry elektryczne. Kwestię obciążalności pinów omówię na podstawie mikrokontrolera ATmega32.

W tym celu powinniśmy zapoznać się z parametrami granicznymi mikrokontrolera.

 

Rys. 6. Parametry graniczne mikrokontrolera ATmega32.

 

Z tabeli z parametrami granicznymi wynika, że każdy pin wejścia/wyjścia możemy obciążać prądem do 40 mA. Jest to wartość maksymalna, której przekroczenie grozi trwałym uszkodzeniem mikrokontrolera. Ponadto ograniczeni jesteśmy prądem płynącym przez piny zasilania i masy, którego wartość maksymalna nie może przekroczyć 200 mA w przypadku mikrokontrolera w obudowie DIP i 400 mA w przypadku pozostałych obudów. W dokumentacji znajdziemy także zapis, że bezpieczną wartością prądu płynącego przez pin jest 20 mA przy napięciu zasilania 5V oraz 10 mA przy napięciu zasilania 3,3 V. Ale to nie wszystko, Mikrokontroler pobiera prąd o wartości zależnej od częstotliwości zegara taktującego.

 

Rys. 7. Pobór prądu w zależności od częstotliwości taktowania zakres od 0,1 do 1 MHz.

 

Rys. 8. Pobór prądu w zależności od częstotliwości taktowania zakres od 1 do 16 MHz.

 

Zależności poboru prądu od częstotliwości taktowania mikrokontrolera nie można także pominąć. W poprzednich artykułach zbudowaliśmy układ z mikrokontrolerem w obudowie DIP, który jest zasilany napięciem 5 V i taktowany zegarem 16 MHz. Z wykresu na rys. 8 wynika, że sam mikrokontroler pobierać będzie ok 23 mA. Przez każdy załączony rezystor podciągający także płynie prąd.

 

Rys. 9. Charakterystyka prądowa rezystora podciągającego .

 

Widać, że w skrajnym przypadku jest to 145 uA na każdy załączony rezystor podciągający. Niby mało, ale w skrajnym przypadku załączenia wszystkich rezystorów podciągających dale nam to ponad 4,5 mA. Przy zasilaniu bateryjnym walka jest o każdy pojedynczy uA.

Mamy teraz jasność, że nie wolno nam przekroczyć 200 mA patrząc od strony zasilania. Wynika stąd, że bezpośrednio podłączyć możemy maksymalnie po jednej diodzie do 8 pinów mikrokontrolera. Ograniczenie to możemy ominąć stosując układy buforujące. Wiemy również, że mikrokontroler składa się z ogromnej ilości tranzystorów. Każdy element ma swoją rezystancję i musi na nich powstawać spadek napięcia. W dokumentacji znajdują się również charakterystyki prądowe pinów.

 

Rys. 10. Charakterystyka prądowo-napięciowa pinu wejścia/wyjścia dla stanu wysokiego

 

.

Rys. 10. Charakterystyka prądowo-napięciowa pinu wejścia/wyjścia dla stanu niskiego

 

Charakterystyka prądowo-napięciowa pinu wyraźnie pokazuje, że pin wyjściowy ma stosunkowo dużą rezystancję wewnętrzną i zbytnie obciążanie go powoduje duży spadek napięcia. Przy prądzie równym 40 mA napięcie na pinie jest już o 1 V niższe od Vcc. Grozi to utratą stabilności naszej aplikacji, gdyż poziom napięcia na pinie może znaleźć się w paśmie zabronionym i urządzenia sterowane z tego pinu nie będą mogły rozpoznać stanu logicznego.

Przedstawione w tym artykule informacje będą wykorzystywane w każdym projekcie, jaki będziemy chcieli zrealizować. Dotyczą one wszystkich ośmio-bitowych mikrokontrolerów rodziny ATmega. Zwracam jednak uwagę, że za każdym razem należy posługiwać się dokumentacją mikrokontrolera, w której znajdują się wszelkie informacje dotyczące konfiguracji portów.

Autor: Orici
Wyświetleń: 751|Komentarzy: 0|Ocena: 0|Głosów: 0