|
Wyjście Spis treści Wstecz Dalej
Autor artykułu |
©2026 mgr Jerzy Wałaszek
|

If you use Microchip copyrighted material solely for educational (non-profit) purposes falling under the “fair use” exception of the U.S. Copyright Act of 1976 then you do not need Microchip’s written permission. For example, Microchip’s
permission is not required when using copyrighted material in:
https://www.microchip.com/about-us/legal-information/copyright-usage-guidelines
Ten rozdział opisuje różne pamięci w mikrokontrolerze ATmega48A/PA/88A/PA/168A/PA/328/P. Architektura AVR posiada dwie główne przestrzenie pamięciowe: przestrzeń pamięci danych (ang. data memory space) oraz przestrzeń pamięci programu (ang. program memory space). Dodatkowo mikrokontroler ATmega48A/PA/88A/PA/168A/PA/328/P jest wyposażony w nieulotną pamięć EEPROM (ang. Electrically Erasable and Programmable Read-Only Memory) na przechowywanie danych. Wszystkie przestrzenie pamięciowe są liniowe i regularne.
Trwałość pamięci FLASH wynosi co najmniej 10.000 cykli zapisu/kasowania. Licznik rozkazów (ang. Program Counter, PC) w ATmega48A/PA/88A/PA/168A/PA/328/P jest 11/12/13/14-bitowy, co pozwala mu na zaadresowanie 2048/4096/8192/16384 komórek pamięci programu. Działanie sekcji programu boot-loadera wraz z powiązanymi bitami blokującymi dla bezpieczeństwa oprogramowania jest opisane szczegółowo w rozdziale "Wsparcie boot-loadera, samoprogramowanie z opcją Read-While-Write".
W rozdziale "Programowanie pamięci" znajdziesz szczegółowy opis szeregowego ładowania programu do pamięci FLASH za pomocą końcówek interfejsu SPI (ang. Serial Programming Interface) lub trybu programowania równoległego.
Tablice ze stałymi mogą być umieszczane w całej przestrzeni adresowej pamięci programu (zobacz na opis instrukcji LPM).
Mapa pamięci
programu dla ATmega48A/48PA

Mapa pamięci
programu dla ATmega88A, ATmega88PA, ATmega168A, ATmega168PA,
ATmega328 i ATmega328P


Powyższy rysunek pokazuje sposób organizacji pamięci SRAM (ang. Static RAM – statyczna pamięć RAM) w mikrokontrolerze ATmega48A/PA/88A/PA/168A/PA/328/P.
Układ ATmega48A/PA/88A/PA/168A/PA/328/P jest złożonym mikrokontrolerem posiadającym więcej modułów we/wy niż można obsłużyć przy pomocy 64 komórek we/wy, dostęp do których został zarezerwowany w kodach operacyjnych instrukcji IN i OUT. W rozszerzonej przestrzeni we/wy od 0x60 do 0xff można używać tylko instrukcji ST/STS/STD i LD/LDS/LDD. Dolne 768/1280/1280/2303 komórki pamięci danych zawierają rejestry robocze. pamięć we/wy, rozszerzoną pamięć we/wy oraz wewnętrzną pamięć danych SRAM. Pierwsze 32 komórki są rejestrami roboczymi, następne 64 komórki są standardową pamięcią we/wy, dalej jest 160 komórek rozszerzonej pamięci we/wy, a kolejne 512/1024/1024/2048 komórek tworzy wewnętrzną pamięć danych SRAM.
Pięć różnych trybów adresowania pamięci danych pokrywa: adresowanie bezpośrednie (ang. Direct Addressing Mode), adresowanie pośrednie z przesunięciem (ang. Indirect with Displacement Addressing Mode), adresowanie pośrednie (ang. Indirect Addressing Mode), adresowanie pośrednie z predekrementacją (ang. Indirect with Pre-decrement Addressing Mode) oraz adresowanie pośrednie z postinkrementacją (ang. Indirect with Post-increment Addresing Mode). W zestawie rejestrów rejestry od R26 do R31 pełnią dodatkową funkcję rejestrów wskaźnikowych do pośredniego adresowania pamięci.
Adresowanie bezpośrednie obejmuje całą przestrzeń danych.
Adresowanie pośrednie z przesunięciem obejmuje 63 komórki od adresu bazowego danego w rejestrze Y lub Z.
Gdy jest używane pośrednie adresowanie z automatyczną predekrementacją lub postinkrementacją, rejestry adresowe X, Y lub Z są zwiększane lub zmniejszane.
Wszystkie te tryby adresowania w ATmega48A/PA/88A/PA/168A/PA/328/P pozwalają na dostęp do każdej lokacji w przestrzeni danych: do zestawu 32 rejestrów ogólnego przeznaczenia, 64 rejestrów we/wy, 160 rejestrów we/wy w obszarze rozszerzonej pamięci we/wy oraz 512/1024/1024/2048 bajtów wewnętrznej pamięci danych SRAM. Opis zestawu rejestrów znajdziesz w rozdziale "Zestaw rejestrów ogólnego przeznaczenia".
Dostęp do pamięci SRAM wykonywany jest w dwóch taktach clkCPU, co pokazuje poniższy rysunek:

Rejestry dostępu do EEPROM znajdują się w przestrzeni we/wy.
Czasy dostępu dla EEPROM są podane przy opisie rejestru sterującego pamięcią EEPROM, EECR (ang. EEPROM Control Register). Jednakże funkcja odmierzająca samoczynnie czas pozwala wykryć oprogramowaniu użytkownika, kiedy można zapisać następny bajt. Jeśli kod użytkownika zawiera instrukcje, które zapisują pamięć EEPROM, należy podjąć pewne środki ostrożności. W mocno filtrowanych źródłach zasilania napięcie VCC może wzrastać lub opadać wolno przy włączaniu/wyłączaniu. Powoduje to, iż mikrokontroler przez pewien okres czasu pracuje przy napięciu niższym od określonego jako minimalne dla używanej częstotliwości zegarowej. Zobacz do podrozdziału "Zapobieganie uszkodzeniu danych w EEPROM", gdzie znajdziesz więcej informacji o tym, jak unikać problemów w takich sytuacjach.
Aby zapobiec niezamierzonym zapisom w EEPROM, należy zastosować specjalną procedurę zapisu. Zobacz do opisu rejestru EECR.
Gdy odczytywana jest pamięć EEPROM, to mikroprocesor zostaje wstrzymany przez cztery takty zegarowe przed wykonaniem następnej instrukcji. Gdy zapisywana jest pamięć EEPROM, mikroprocesor jest wstrzymywany przez dwa takty zegara przed wykonaniem następnej instrukcji.
Przy wejściu w tryb uśpienia wyłączenia zasilania podczas aktywnej operacji zapisu EEPROM, operacja ta będzie kontynuowana aż do swojego zakończenia. Jednakże po zakończeniu operacji zapisu oscylator kontynuuje pracę i w konsekwencji mikrokontroler nie wejdzie w pełni w tryb wyłączenia. Dlatego zaleca się sprawdzenie zakończenia operacji zapisu EEPROM przed wejściem w ten tryb uśpienia.
Podczas okresów niskiego napięcia zasilającego VCC dane w EEPROM mogą ulec uszkodzeniu przy zapisie, ponieważ napięcie zasilające jest zbyt niskie na poprawne funkcjonowanie mikroprocesora oraz EEPROM. Problem ten jest taki sam jak w systemach z zewnętrznymi pamięciami EEPROM i te same rozwiązania powinny być stosowane.
Uszkodzenie danych w EEPROM może być spowodowane przez dwie sytuacje, gdy napięcie jest zbyt niskie. Po pierwsze normalna sekwencja zapisu do EEPROM wymaga minimalnego napięcia, aby zadziałać prawidłowo. Po drugie sam mikroprocesor może nieprawidłowo wykonywać instrukcje, jeśli napięcie zasilania jest zbyt niskie.
Uszkodzeniu danych w EEPROM można łatwo zapobiec, stosując następujące zalecenia projektowe:
Utrzymuj końcówkę AVR RESET w stanie aktywnym (niskim 0) podczas okresów niewystarczającego napięcia zasilania. Można to zrobić, przez uaktywnienie wewnętrznego detektora spadku napięcia (ang. Brown-out Detector, BOD). Jeśli poziom wykrywania wewnętrznego detektora BOD nie odpowiada wymaganemu poziomowi wykrywania, to można użyć zewnętrznego układu resetowania przy niskim napięciu VCC. Jeśli reset wystąpi podczas operacji zapisu, operacja ta zostanie dokończona o ile napięcie zasilania jest wystarczające.
Wszystkie układy we/wy ATmega48A/PA/88A/PA/168A/PA/328/P obsługiwane są poprzez rejestry w przestrzeni we/wy. Dostęp do wszystkich rejestrów we/wy wykonywany jest przez instrukcje LD/LDS/LDD i ST/STS/STD, przesyłające dane pomiędzy 32 rejestrami ogólnego przeznaczenia a przestrzenią we/wy. Rejestry we/wy o adresach w zakresie 0x00 – 0x1F są bezpośrednio dostępne bitowo przy pomocy instrukcji SBI i CBI. W rejestrach tych wartość pojedynczych bitów można sprawdzać instrukcjami SBIS i SBIC. Gdy są używane dedykowane instrukcje IN i OUT, należy używać adresów we/wy 0x00 – 0x3F. Gdy rejestry we/wy są adresowane w przestrzeni danych za pomocą instrukcji LD i ST, należy do tych adresów dodać 0x20.
Dla kompatybilności z przyszłymi mikrokontrolerami zarezerwowane bity powinny być zapisywane stanami 0 przy dostępie do rejestrów. Zarezerwowanych adresów w pamięci we/wy nie należy nigdy zapisywać.
Niektóre ze znaczników stanu są zerowane przez zapis w nich stanu 1. Zwróć uwagę, iż w przeciwieństwie do większości innych mikrokontrolerów AVR instrukcje CBI i SBI działają tylko na określonym bicie i można je z tego powodu używać na rejestrach zawierających takie znaczniki stanu. Instrukcje CBI i SBI pracują jedynie na rejestrach od 0x00 do 0x1F.
| Bit | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | |
| 0x22 (0x42) | – | – | – | – | – | – | EEAR9(1) | EEAR8(1) | EEARH |
| 0x21 (0x41) | EEAR7 | EEAR6 | EEAR5 | EEAR4 | EEAR3 | EEAR2 | EEAR1 | EEAR0 | EEARL |
| Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
| Zapis/Odczyt | O | O | O | O | O | O | Z/O | Z/O | |
| Zapis/Odczyt | Z/O | Z/O | Z/O | Z/O | Z/O | Z/O | Z/O | Z/O | |
| Wartość początkowa | 0 | 0 | 0 | 0 | 0 | 0 | X | X | |
| X | X | X | X | X | X | X | X |
Te bity są zarezerwowane w ATmega48A/PA/88A/PA/168A/PA/328/P i przy odczycie dają zawsze wartość 0.
Rejestry adresowe EEPROM – EEARH i EEARL – określają adres EEPROM (starszy i młodszy bajt adresu) w 256/512/512/1024-bajtowej przestrzeni pamięci EEPROM. Bajty EEPROM są adresowane liniowo od 0 do 255/511/511/1023. Początkowa zawartość rejestru EEAR jest niezdefiniowana. Właściwą wartość należy wpisać przed dostępem do pamięci EEPROM.
| Uwaga: | 1. | Bity EEAR9 i EEAR8 są nieużywane w ATmega 48A/48PA i muszą zawsze być zapisywane jako zero. |
| Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
| 0x20 (0x40) | EEDR7 | EEDR6 | EEDR5 | EEDR4 | EEDR3 | EEDR2 | EEDR1 | EEDR0 | EEDR |
| Zapis/Odczyt | Z/O | Z/O | Z/O | Z/O | Z/O | Z/O | Z/O | Z/O | |
| Wartość początkowa | X | X | X | X | X | X | X | X |
Dla operacji zapisu w EEPROM rejestr EEDR zawiera dane do zapisania pod adresem podanym przez rejestr EEAR. Dla operacji odczytu z EEPROM rejestr EEDR zawiera dane odczytane z komórki EEPROM o adresie podanym w rejestrze EEAR.
| Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
| 0x1F (0x3F) | – | – | EEPM1 | EEPM0 | EERIE | EEMPE | EEPE | EERE | EECR |
| Zapis/Odczyt | O | O | Z/O | Z/O | Z/O | Z/O | Z/O | Z/O | |
| Wartość początkowa | 0 | 0 | X | X | 0 | 0 | X | 0 |
Te bity są zarezerwowane w ATmega48A/PA/88A/PA/168A/PA/328/P i zawsze przy odczycie dają zero.
Ustawienie bitów trybu programowania EEPROM definiuje działanie programujące, które zostanie wyzwolone przy zapisie do bitu EEPE. Możliwy jest zapis w pojedynczej operacji atomowej (niepodzielnej) kasującej starz zawartość i programującej nową lub w dwóch oddzielnych operacjach kasowania i zapisu. Czasy programowania dla tych dwóch różnych trybów podaje poniższa tabelka. Gdy bit EEPE jest ustawiony, każdy zapis do bitów EEPMn zostanie zignorowany. Podczas resetu bity EEPMn są ustawiane na 0b00, o ile pamięć EEPROM nie jest zajęta programowaniem.
| EEPM1 | EEPM0 | Czas programowania | Operacja |
| 0 | 0 | 3,4ms | Kasowanie i zapis w jednej operacji atomowej. |
| 0 | 1 | 1,8ms | Tylko kasowanie. |
| 1 | 0 | 1,8ms | Tylko zapis. |
| 1 | 1 | – | Zarezerwowane do użytku w przyszłości. |
Wpisanie jedynki do bitu EERIE włącza przerwania przy gotowości EEPROM, jeśli bit I w rejestrze SREG jest ustawiony. Wpisanie zera do EERIE wyłącza te przerwanie. Przerwanie od gotowości EEPROM jest generowane ciągle, gdy bit EEWE jest wyzerowany.
Bit ten umożliwia zabezpieczenie EEPROM przed przypadkowym zapisem. Określa on, czy ustawienie bitu EEPE na jeden spowoduje zapis do EEPROM. Gdy bit EEMPE zostanie ustawiony, to ustawienie bitu EEPE w ciągu czterech taktów zegarowych spowoduje zapis danych do EEPROM pod wybranym adresem. Jeśli bit EEMPE ma wartość zero, to ustawienie bitu EEPE nie spowoduje żadnego efektu. Gdy bit EEMPE zostanie ustawiony na jeden programowo, to będzie on automatycznie wyzerowany po upływie czterech taktów zegarowych.
Bit EEPE jest strobem zapisu EEPROM. Gdy zostaną poprawnie ustawione adres i dane, to należy wpisać jedynkę do bitu EEPE, aby dane zapisać w pamięci EEPROM. Przed dokonaniem tego zapisu należy ustawić na jeden bit uaktywnienia zapisu EEMWE, w przeciwnym razie zapis do EEPROM nie zostanie wykonany. Należy zastosować poniższą procedurę (kolejność kroków 3 i 4 jest istotna):
Pamięć EEPROM nie może być programowana podczas zapisu przez mikroprocesor danych do pamięci FLASH. Program użytkownika musi sprawdzić, czy programowanie FLASH jest ukończone przed zainicjowaniem zapisu do EEPROM. Krok 2 jest tylko wtedy istotny, gdy oprogramowanie zawiera boot loader, który pozwala mikroprocesorowi programować FLASH. Jeśli pamięć FLASH nigdy nie jest uaktualniana przez mikroprocesor, krok 2 można pominąć. Zobacz do rozdziału "Wsparcie dla programu startowego – odczyt przy zapisie i samoprogramowanie".
Uwaga: przerwanie pomiędzy krokiem 5 a 6 spowoduje porażkę cyklu zapisu, ponieważ bit uaktywniający zapis EEPROM, EEMPE, straci ważność (zostanie wyzerowany sprzętowo po czterech taktach zegara). Jeśli procedura przerwania uzyskująca dostęp do EEPROM przerwie pracę innemu procesowi dostępu do EEPROM, to rejestr EEAR lub EEDR zostanie zmodyfikowany, powodując porażkę przerwanego procesu dostępu do EEPROM. Zaleca się wyzerowanie globalnego znacznika przerwań I w rejestrze SREG w celu uniknięcia tych problemów.
Gdy upłynie czas przeznaczony na zapis, bit EEPE jest zerowany sprzętowo. Program użytkownika może przeglądać zawartość tego bitu i czekać na zero przed zapisem kolejnego bajtu. Gdy bit EEPE został ustawiony, mikroprocesor zatrzymuje się na dwa cykle przed wykonaniem następnej instrukcji.
Bit EERE jest strobem odczytu EEPROM. Gdy został ustawiony poprawny adres w rejestrze EEAR, należy wpisać logiczną jedynkę do bitu EERE, aby wyzwolić odczyt EEPROM. Odczyt zajmuje jedną instrukcję i zażądane dane są dostępne natychmiast. Gdy jest odczytywana pamięć EEPROM, mikroprocesor zatrzymuje się na cztery cykle przed wykonaniem następnej instrukcji. Użytkownik powinien przeglądać stan bitu EEWE przed rozpoczęciem operacji odczytu. Jeśli trwa operacja zapisu, nie można odczytywać EEPROM ani zmieniać zawartości rejestru EEAR.
Do odmierzania czasu przy dostępie do EEPROM wykorzystywany jest kalibrowany oscylator. Poniższa tablica wymienia typowy czas programowania przy dostępie do EEPROM z poziomu mikroprocesora.
| Symbol | Liczba taktów kalibrowanego oscylatora RC | Typowy czas programowania |
| Zapis EEPROM (z mikroprocesora) | 26.368 | 3,3 ms |
Poniższe przykłady kodów pokazują po jednej funkcji w asemblerze i w języku C dla zapisu EEPROM. Przykłady zakładają globalne wyłączenie przerwań (wyzerowany bit I w rejestrze stanu SREG), aby żadne z przerwań nie wystąpiło podczas wykonywania tych funkcji. Założono również, iż oprogramowanie nie korzysta z boot-loadera. Jeśli kod programu ładującego jest obecny, to funkcja zapisu EEPROM musi również czekać na zakończenie każdego wykonywanego rozkazu SPM.
| Przykład w kodzie maszynowym |
EEPROM_write:
; Czekaj na zakończenie poprzedniego zapisu
sbic EECR,EEWE
rjmp EEPROM_write
; Ustaw adres (r18:r17) w rejestrze adresowym
out EEARH, r18
out EEARL, r17
; Zapisz dane (r16) do rejestru danych
out EEDR,r16
; Zapisz logiczną jedynkę w bicie EEMWE
sbi EECR,EEMWE
; Rozpocznij zapis EEPROM przez ustawienie EEWE
sbi EECR,EEWE
ret
|
| Przykład w języku C |
void EEPROM_write(unsigned int uiAddress, unsigned char ucData) { /* Czekaj na zakończenie poprzedniego zapisu */ while(EECR & (1<<EEWE)) ; /* Ustaw rejestry adresu i danych */ EEAR = uiAddress; EEDR = ucData; /* Zapisz logiczną jedynkę w bicie EEMWE */ EECR |= (1<<EEMWE); /* Rozpocznij zapis EEPROM przez ustawienie EEWE */ EECR |= (1<<EEWE); } |
Następne przykłady kodu pokazują funkcje w asemblerze i w języku C dla odczytu EEPROM. Przykłady zakładają globalne wyłączenie przerwań podczas wykonywania tych funkcji..
| Przykład w kodzie maszynowym |
EEPROM_read:
; Czekaj na zakończenie poprzedniego zapisu
sbic EECR,EEWE
rjmp EEPROM_read
; Ustaw adres (r18:r17) w rejestrze adresowym
out EEARH, r18
out EEARL, r17
; Rozpocznij odczyt EEPROM przez zapis bitu EERE
sbi EECR,EERE
; Odczytaj dane z rejestru danych
in r16,EEDR
ret
|
| Przykład w języku C |
unsigned char EEPROM_read(unsigned int uiAddress) { /* Czekaj na zakończenie poprzedniego zapisu while(EECR & (1<<EEWE)) ; /* Ustaw rejestr adresowy */ EEAR = uiAddress; /* Rozpocznij odczyt EEPROM przez zapis bitu EERE */ EECR |= (1<<EERE); /* Zwróć dane z rejestru danych */ return EEDR; } |
| Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
| 0x2B (0x4B) | MSB | LSB | GPIOR2 | ||||||
| Zapis/Odczyt | Z/O | Z/O | Z/O | Z/O | Z/O | Z/O | Z/O | Z/O | |
| Wartość początkowa | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
| 0x2A (0x4A) | MSB | LSB | GPIOR1 | ||||||
| Zapis/Odczyt | Z/O | Z/O | Z/O | Z/O | Z/O | Z/O | Z/O | Z/O | |
| Wartość początkowa | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
| 0x1E (0x3E) | MSB | LSB | GPIOR0 | ||||||
| Zapis/Odczyt | Z/O | Z/O | Z/O | Z/O | Z/O | Z/O | Z/O | Z/O | |
| Wartość początkowa | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
![]() |
Zespół Przedmiotowy Chemii-Fizyki-Informatyki w I Liceum Ogólnokształcącym im. Kazimierza Brodzińskiego w Tarnowie ul. Piłsudskiego 4 ©2026 mgr Jerzy Wałaszek |
Materiały tylko do użytku dydaktycznego. Ich kopiowanie i powielanie jest dozwolone pod warunkiem podania źródła oraz niepobierania za to pieniędzy.
Pytania proszę przesyłać na adres email:
Serwis wykorzystuje pliki cookies. Jeśli nie chcesz ich otrzymywać, zablokuj je w swojej przeglądarce.
Informacje dodatkowe.