
Od kilku lat programuję 8-bitowe mikrokontrolery AVR i przez ten czas zdobyłem trochę wiedzy na ich temat. Poniżej znajduje się kilka ciekawostek o tych układach. Jeśli znacie jakieś inne interesujące informacje, to piszcie. Najnowsza wersja artykułu jest również dostępna na mojej stronie: Link.
1. Rozpoznawanie wersji (rewizji)
Wersja (rewizja) mikrokontrolera jest oznaczana jedną literą (zgodnie z porządkiem liter w alfabecie: "Rev. A" - oznacza pierwszą, "Rev. B" - drugą/nowszą wersję mikrokontrolera, itd.). Poznanie wersji posiadanego mikrokontrolera jest czasem potrzebne, bo w niektórych występują błędy (zwykle drobne), które są usuwane w nowszych wersjach układu. Błędy te są opisane w rozdziale "Errata" noty katalogowej danego modelu mikrokontrolera.
Wersja mikrokontrolera zwykle jest podana w postaci napisu na spodzie jego obudowy DIP. Nowe układy mają oznaczenie w formacie 354XXZ lub 355XXZ, a starsze 196XXZ, gdzie: XX - numer układu (może zawierać literę), Z - wersja układu (litera). W przypadku mikrokontrolerów w obudowach DIP8 nie ma na nich zbyt dużo miejsca, dlatego wersję układu oznacza się jedną literą (pierwszą w drugiej linii).
Na innych rodzajach obudów, wersja mikrokontrolera może nie być podana wprost i aby ją ustalić, należy kontaktować się z pomocą techniczną firmy Atmel/Microchip. Można też próbować określić wersję na podstawie 4-cyfrowego kodu, oznaczającego datę produkcji układu (YYWW, gdzie: YY - dwie ostatnie cyfry roku; WW - numer tygodnia), ale nie jest to pewny sposób.
Na poniższych zdjęciach są wyróżnione na czerwono litery, które oznaczają wersję danego modelu mikrokontrolera.
![]() ATtiny85 (20PU) |
![]() ATmega48 (20PU) |
![]() ATmega32A (PU) |
2. Stany przejściowe wejść/wyjść
Po włączeniu/resecie mikrokontrolera wszystkie jego piny są ustawione jako wejścia (IN) w stanie nieustalonym, czyli wysokiej impedancji (Z). Aby zmniejszyć pobór prądu i wyeliminować zakłócenia, które trafiają przez takie piny do mikrokontrolera, należy wymusić na nich ustalony stan logiczny (niski/wysoki). Najprościej można to zrobić programowo, włączając na tych pinach wewnętrzne rezystory podciągające Rpu (pull-up) lub ustawiając je, jako wyjścia (OUT) z niskim/wysokim stanem logicznym (L/H). Jednak te sposoby nie działają podczas i po włączeniu/resecie mikrokontrolera. Rozwiązaniem, które zawsze działa jest dodanie na tych pinach zewnętrznych rezystorów, podłączonych na stałe do plusa Vcc (pull-up) lub masy GND (pull-down) zasilania. Nie jest zalecane podłączanie nieużywanych pinów bezpośrednio do plusa lub masy zasilania, gdyż może to spowodować przepływ znacznego prądu, jeśli dany pin zostanie przypadkowo ustawiony jako wyjście.
Do programowej konfiguracji pinów w danym porcie PX, służą bity DDXn w rejestrze DDRX (Data Direction Register port X), bity PORTXn w rejestrze PORTX (PORT X data register) oraz bit PUD w rejestrze MCUCR (MicroController Unit Control Register), gdzie: X - litera oznaczająca dany port (np. A, B, C, D), n - numer konkretnego pinu w porcie X (0-7). Zapisanie "1" do bitu PUD w rejestrze MCUCR, spowoduje całkowite wyłączenie rezystorów podciągających (pull-up) na wszystkich pinach każdego portu mikrokontrolera.
Poniższa tabela przedstawia konfigurację danego pinu PXn w zależności od wartości, odpowiadających mu bitów DDXn/PORTXn w rejestrach DDRX/PORTX oraz bitu PUD w rejestrze MCUCR.

IN / OUT - pin skonfigurowany jako wejście/wyjście, (pu) - włączony rezystor podciągający,
L / H / X - niski/wysoki/dowolny stan logiczny, Z - stan nieustalony/wysokiej impedancji (Hi-Z).
Ponieważ o konfiguracji danego pinu PXn decydują 2 bity w rejestrach DDRX/PORTX, a jedną instrukcją w ciągu jednego cyklu zegarowego można zmienić wartość tylko jednego z tych bitów, to w tym czasie na konfigurowanym pinie PXn może pojawić się przejściowy stan logiczny. Poniższa tabela przedstawia, jakie stany przejściowe występują na pinie PXn w zależności, od kolejności zmian wartości bitów DDXn/PORTXn.

IN / OUT - pin skonfigurowany jako wejście/wyjście, (pu) - włączony rezystor podciągający,
L / H / X - niski/wysoki/dowolny stan logiczny, Z - stan nieustalony/wysokiej impedancji (Hi-Z).
3. Wyłączanie zbędnych modułów
Wyłączenie nie potrzebnych peryferiów mikrokontrolera nie tylko zmniejsza pobór prądu, ale redukuje też poziom generowanych przez nie szumów, co ma duże znaczenie np. przy wykonywaniu pomiarów wewnętrznym przetwornikiem analogowo-cyfrowym ADC.
Nowsze mikrokontrolery mają rejestr PRR (Power Reduction Register), który służy do zatrzymywania taktowania nieużywanych modułów mikrokontrolera (przetwornika ADC, timerów/liczników, czy interfejsów komunikacyjnych TWI/SPI/USART). W tym celu, należy zapisać "1" do bitu w rejestrze PRR, który odpowiada zatrzymywanemu modułowi. Niektóre modele z większą liczbą peryferiów mają dwa takie rejestry PRR0 i PRR1 (np. ATmega1284). Po zatrzymaniu taktowania aktualny stan modułu nie zmienia się, a jego rejestry przestają być dostępne do odczytu/zapisu. Wszystkie zasoby, których używał zatrzymany moduł pozostają zajęte. Dlatego przed zatrzymaniem taktowania danego modułu, powinno się go najpierw wyłączyć.
Poniższy rysunek przedstawia poszczególne moduły mikrokontrolera - te oznaczone ikoną "Power" można wyłączyć/zatrzymać według zamieszczonych opisów.
Aby wyłączyć timer WDT (Watch-Dog Timer), należy ustawić wartość fuse bitu WDTON na "1" oraz zapisać "0" do bitów: WDRF w rejestrze MCUSR (MicroController Unit Status Register), WDE i WDIE w rejestrze WDTCR (WatchDog Timer Control Register) - według procedury opisanej w nocie katalogowej. Domyślnie timer WDT jest wyłączony po włączeniu/resecie fabrycznie nowego mikrokontrolera.
Aby wyłączyć moduł monitorowania napięcia zasilania BOD (Brown-Out Detector), należy ustawić wartość fuse bitów BODLEVEL2-0 na "1". Domyślnie moduł ten jest wyłączony w fabrycznie nowym mikrokontrolerze.
Aby wyłączyć moduł debugowania dW (debugWire), należy ustawić wartość fuse bitu DWEN na "1". Domyślnie moduł ten jest wyłączony w fabrycznie nowym mikrokontrolerze.
Aby wyłączyć przetwornik analogowo-cyfrowy ADC (Analog to Digital Converter), należy zapisać "0" do bitu ADEN w rejestrze ADCSRA (ADC control and Status Register A) - spowoduje to całkowite odłączenie jego napięcia zasilania. Dopiero później można zapisać "1" do bitu PRADC w rejestrze PRR (jeśli mikrokontroler go posiada) - spowoduje to całkowite odłączenie jego zegara taktującego. W niektórych modelach zatrzymanie zegara przetwornika ADC, powoduje jednoczesne zatrzymanie pewnych obwodów komparatora analogowego, który nie może być używany w takiej sytuacji (np. ATtiny25/45/85, ATtiny261/461/861). Domyślnie przetwornik ADC jest wyłączony po włączeniu/resecie mikrokontrolera, ale jest taktowany zegarem.
Aby wyłączyć komparator analogowy AC (Analog Comparator), należy zapisać "1" do bitu ACD w rejestrze ACSR (Analog Comparator control and Status Register) - spowoduje to całkowite odłączenie jego napięcia zasilania. Domyślnie komparator analogowy jest włączony po włączeniu/resecie mikrokontrolera.
Aby wyłączyć cyfrowy bufor wejściowy DIB (Digital Input Buffer) na pinie ADCx przetwornika analogowo-cyfrowego lub ANx komparatora analogowego, należy zapisać "1" do odpowiadającego mu bitu ADCxD lub ANxD w rejestrze DIDR0/1 (Digital Input Disable Register 0/1). W przypadku modeli, w których drugą funkcją pinu AREF jest tylko funkcja cyfrowa, rejestr DIDR0 zawiera dodatkowo bit AREFD (np. ATtiny261/461/861).
Jeśli na wejściowy pin analogowy jest podawany sygnał o napięciu zbliżonym do wartości Vcc/2, to wtedy włączony na tym pinie cyfrowy bufor wejściowy pobiera znaczny prąd. Dlatego, aby zmniejszyć pobór prądu cyfrowe bufory wejściowe, powinny być zawsze wyłączone na wejściach analogowych. Domyślnie cyfrowe bufory wejściowe są włączone po włączeniu/resecie mikrokontrolera.
Aby wyłączyć wewnętrzne źródło napięcia odniesienia IBRV (Internal Bandgap Reference Voltage), należy wyłączyć moduł BOD (fuse bity BODLEVEL2-0=1) i przetwornik ADC (bit ADEN=0 w rejestrze ADCSRA) oraz odłączyć to źródło od komparatora analogowego (bit ACBG=0 w rejestrze ACSR). Domyślnie wewnętrzne źródło napięcia odniesienia jest wyłączone po włączeniu/resecie fabrycznie nowego mikrokontrolera.
Aby wyłączyć timer/licznik TCx (Timer/Counter x), należy zapisać "0" we wszystkich bitach CSx w rejestrze TCCRx (Timer/Counter Control Register x) - spowoduje to zatrzymanie działania licznika. Dopiero później można zapisać "1" do bitu PRTIMx w rejestrze PRR (jeśli mikrokontroler go posiada) - spowoduje to całkowite odłączenie jego zegara taktującego. Domyślnie timer/licznik TCx jest wyłączony po włączeniu/resecie mikrokontrolera, ale jest taktowany zegarem.
Aby wyłączyć moduł SPI (Serial Peripheral Interface), należy zapisać "0" do bitu SPE w rejestrze SPCR (SPi Control Register) - spowoduje to zatrzymanie działania interfejsu SPI. Dopiero później można zapisać "1" do bitu PRSPI w rejestrze PRR (jeśli mikrokontroler go posiada) - spowoduje to całkowite odłączenie jego zegara taktującego. Niektóre modele zamiast modułu SPI mają moduł USI, który może pracować w trybie SPI (np. ATtiny25/45/85, ATtiny261/461/861). Domyślnie moduł ten jest wyłączony po włączeniu/resecie mikrokontrolera, ale jest taktowany zegarem.
Aby wyłączyć moduł TWI (Two-Wire serial Interface), należy zapisać "0" do bitu TWEN w rejestrze TWCR (TWi Control Register) - spowoduje to zatrzymanie działania interfejsu TWI. Dopiero później można zapisać "1" do bitu PRTWI w rejestrze PRR (jeśli mikrokontroler go posiada) - spowoduje to całkowite odłączenie jego zegara taktującego. Niektóre modele zamiast modułu TWI mają moduł USI, który może pracować w trybie TWI (np. ATtiny25/45/85, ATtiny261/461/861). Domyślnie moduł ten jest wyłączony po włączeniu/resecie mikrokontrolera, ale jest taktowany zegarem.
Aby wyłączyć moduł USI (Universal Serial Interface), należy zapisać "0" do wszystkich bitów w rejestrze USICR (USI Control Register) - spowoduje to zatrzymanie działania interfejsu USI. Dopiero później można zapisać "1" do bitu PRUSI w rejestrze PRR (jeśli mikrokontroler go posiada) - spowoduje to całkowite odłączenie jego zegara taktującego. Moduł USI może pracować w trybie SPI/TWI i mają go tylko niektóre modele (np. ATtiny25/45/85, ATtiny261/461/861). Domyślnie moduł ten jest wyłączony po włączeniu/resecie mikrokontrolera, ale jest taktowany zegarem.
Aby wyłączyć moduł USARTx (Universal Synchronous/Asynchronous serial Receiver and Transmitter), należy zapisać "0" do bitów RXENx i TXENx w rejestrze UCSRxB (Usart Control and Status Register x B) - spowoduje to zatrzymanie działania interfejsu USARTx. Dopiero później można zapisać "1" do bitu PRUSARTx w rejestrze PRR (jeśli mikrokontroler go posiada) - spowoduje to całkowite odłączenie jego zegara taktującego. Niektóre modele nie mają modułu USART (np. ATtiny25/45/85, ATtiny261/461/861). Domyślnie moduł ten jest wyłączony po włączeniu/resecie mikrokontrolera, ale jest taktowany zegarem.
4. Pomiar rezystancji wewnętrznych rezystorów podciągających
Według not katalogowych rezystor podciągający Rpu (pull-up) na pinie I/O może mieć wartość 20-50k (na pinie RESET 30-60k). Jego dokładną rezystancję można zmierzyć przy użyciu multimetru. W tym celu dowolny pin mikrokontrolera, należy ustawić jako wejście z wysokim stanem (pull-up), wymuszonym włączeniem rezystora podciągającego (DDXn:0, PORTXn:1, PUD:0). Później mierzymy i zapamiętujemy dokładną wartośc napięcia zasilania Vcc mikrokontrolera. Następnie ustawiamy multimetr na najniższy zakres pomiaru prądu (np. do 2mA), mierzymy i zapamiętujemy dokładną wartość prądu Ix, płynącego między podciągniętym pinem mikrokontrolera, a masą zasilania. Wartość rezystora podciągającego można obliczyć ze wzoru: Rpu [Ohm] = Vcc [V] / Ix [A]. Zasada pomiaru jest przedstawiona na poniższym rysunku.
Przykładowo w moim ATtiny85 zasilanym napięciem Vcc=5.0V, prąd płynący między podciągniętym pinem PB0, a masą zasilania wynosił 0.138mA. Stąd, po obliczeniach: Rpu = 5V / 0.000138A = 36231.88 omów.
Wartości wewnętrznych rezystorów mogą być inne w różnych egzemplarzach tego samego modelu mikrokontrolera, ale są bardzo zbliżone do siebie na różnych pinach jednego układu. Rezystory te są prawdopodobnie wykonane na krzemie, jako tranzystory FET z długim cienkim kanałem. Zajmują mniej miejsca, są łatwiejsze i tańsze w produkcji niż tradycyjne rezystory, ale mają gorszą liniowość i stabilność temperaturową.
5. Pomiar częstotliwości wewnętrznego zegara taktującego
Można zmierzyć częstotliwość z jaką pracuje mikrokontroler przy użyciu miernika częstotliwości. W tym celu, należy ustawić wartość fuse bitu CKOUT na "0" (w fabrycznie nowym mikrokontrolerze CKOUT=1). Nie każdy model mikrokontrolera posiada ten fuse bit.
Po tej operacji na pinie CLKO, pojawi się częstotliwość pracy mikrokontrolera (inne funkcje tego pinu zostaną wyłączone). Jeśli mikrokontroler używa wewnętrznego dzielnika (prescaler), to na pinie CLKO pojawi się częstotliwość po podziale. Teraz wystarczy podłączyć do tego pinu miernik częstotliwości, aby sprawdzić z jaką rzeczywistą częstotliwością pracuje mikrokontroler.
To rozwiązanie jest dedykowane do taktowania zewnętrznych układów, współpracujących synchronicznie z mikrokontrolerem. Może również posłużyć do dokładnej, programowej kalibracji częstotliwości wewnętrznego oscylatora RC (za pomocą rejestru OSCCAL).
W niektórych modelach sygnał na pinie CLKO jest dostępny również podczas włączania/resetu mikrokontrolera (np. ATtiny48/88, ATmega48/88/168/328, ATmega164/324/644/1284). W przypadku modeli, w których drugą funkcją pinu CLKO jest XTAL2, nie można wtedy używać rezonatorów kwarcowych/ceramicznych (np. ATtiny25/45/85, ATtiny261/461/861).
6. Pomiar napięcia wewnętrznego źródła odniesienia
Można zmierzyć wartość wewnętrznego napięcia odniesienia przy użyciu woltomierza. W tym celu, należy włączyć przetwornik analogowo-cyfrowy ADC (bit ADEN=1 w rejestrze ADCSRA) oraz tak ustawić bity REFSx w rejestrze ADMUX (ADc MUltipleXer selection register), aby wybrać wewnętrzne źródło napięcia odniesienia z zewnętrznym kondensatorem na pinie AREF ("Internal x.xV Voltage Reference with external capacitor at AREF pin"). Nie każdy model mikrokontrolera pozwala na taką konfigurację.
Po tej operacji na pinie AREF, pojawi się napięcie referencyjne Vref z wewnętrznego źródła odniesienia. Teraz wystarczy podłączyć do tego pinu woltomierz o dużej rezystancji wejściowej (np. 10M), aby sprawdzić jaką rzeczywistą wartość ma to napięcie.
Źródło wewnętrznego napięcia odniesienia ma bardzo dużą rezystancję wyjściową, a więc zapewnia bardzo małą wydajność prądową. Dlatego do pinu AREF powinno podłączać się tylko obciążenia pojemnościowe (np. kondensator filtrujący 100nF). Wszystkie obciążenia rezystancyjne (rezystory pull-up/pull-down) powinny zostać odłączone od tego pinu.
7. Maksymalny prąd wewnętrznych diod zabezpieczających
Każdy pin mikrokontrolera posiada dwie diody zabezpieczające (clamping diodes) o spadku napięcia 0.5V, które chronią układ przed za wysokim/niskim napięciem wejściowym Vin w stosunku do jego napięcia zasilania Vcc. Utrzymują one wszystkie sygnały trafiające do mikrokontrolera w zakresie jego maksymalnych napięć wejściowych (od GND-0.5V do Vcc+0.5V), wymienionym w nocie katalogowej. Wewnętrzna budowa pinu mikrokontrolera jest przedstawiona na poniższym rysunku.
Podanie napięcia Vin o wartości wyższej niż Vcc+0.5V, spowoduje przepływ prądu przez górną diodę zabezpieczającą Dup do plusa zasilania, a w rezultacie zmniejszenie napięcia Vin do wartości Vcc+0.5V. Z kolei podanie napięcia Vin o wartości niższej niż GND-0.5V, spowoduje przepływ prądu przez dolną diodę zabezpieczającą Ddn do masy zasilania, a w rezultacie zmniejszenie napięcia Vin do wartości GND-0.5V.
Jedynym ograniczeniem jest zalecany maksymalny prąd płynący przez wewnętrzne diody zabezpieczające, który nie powinien przekroczyć wartości 1mA. Większy prąd może spowodować uszkodzenie diody zabezpieczającej, a następnie pinu/portu mikrokontrolera.
Wynika z tego, że stosując odpowiednio dużą wartość rezystancji wejściowej Rin, na pin mikrokontrolera można podać napięcie wejściowe Vin, o wartości znacznie przekraczającej jego maksymalny zakres podany w nocie katalogowej (od GND-0.5V do Vcc+0.5V).
Przy rezystorze Rin=1M na pin mikrokontrolera można podać napięcie ujemne/dodatnie Vin=1000V, bez obawy o jego uszkodzenie. Jest to dokładnie opisane w nocie aplikacyjnej "AVR182: Zero Cross Detector" firmy Atmel/Microchip.
8. Wewnętrzny oscylator PLL
Mikrokontrolery ATtiny25/26/45/85/261/461/861 zawierają wewnętrzny oscylator PLL (Phase Locked Loop). Na jego wyjściu uzyskuje się sygnał o częstotliwości 64 MHz (8x częstotliwość wewnętrznego oscylatora RC 8MHz) lub 32MHz (8x 4MHz). Sygnał ten może służyć do asynchronicznego taktowania timera/licznika 1 (32/64MHz) lub do taktowania samego mikrokontrolera po podziale przez 4 (8/16 MHz).
9. Programowa instrukcja XCHG (eXCHanGe two registers)
Lista instrukcji 8-bitowych mikrokontrolerów AVR nie zawiera żadnej instrukcji, która służy do wymiany zawartości dwóch rejestrów, np. Raa i Rbb (Raa, Rbb = R0-R31). Najprostszym rozwiązaniem problemu jest wykorzystanie trzeciego rejestru tymczasowego Rxx:
mov Rxx,Raa
mov Raa,Rbb
mov Rbb,Rxx
Jednak nie zawsze jest do dyspozycji taki wolny rejestr tymczasowy. Jak się okazuje zadanie to można wykonać również bez niego (oba rozwiązania mają jednakową liczbę, rozmiar i czas wykonywania instrukcji):
eor Raa,Rbb
eor Rbb,Raa
eor Raa,Rbb
10. Maksymalna częstotliwość taktowania
Maksymalna częstotliwość taktowania mikrokontrolera jest bezpośrednio zależna od jego napięcia zasilania: im mniejsze napięcie, tym niższa częstotliwość. W notach aplikacyjnych (np. ATtiny25/45/85, ATmega48/88/168/328) znajdują się wykresy ilustrujące tą zależność, jednak bez podanych konkretnych wartości napięcia/częstotliwości. Poniższy wykres przedstawia w dokładny sposób, zależność maksymalnej częstotliwości taktowania Fmax mikrokontrolera od jego napięcia zasilania Vcc. Jest to tzw. bezpieczny obszar działania (Safe Operating Area) co oznacza, że producent gwarantuje pracę mikrokontrolera przy podanych wartościach napięcia/częstotliwości.

Cool? Ranking DIY