Elektronika analogowa - Kurs asemblera dla AVR w przykładach
forum
szukaj
książki
linki
artykuły
teoria
dla początkujących
schematy
elektronika retro
mikrokontrolery
MikrokontroleryKurs asemblera dla AVR w przykładachWprowadzenie do języka asembler dla mikrokontrolerów AVR
Co to jest asembler? - Elementy języka asembler - Dyrektywy - Funkcje i operatory w wyrażeniach - Instrukcje asemblera - Lista rozkazów mikrokontrolerów AVR
Panuje powszechna opinia, że asembler jest trudny do nauki - też tak do niedawna myślałem. Przeciwnicy pisania programów w asemblerze twierdzą, że przy istniejących językach wysokiego poziomu (BASCOM i C)), które przyspieszają proces pisania programu, nie jest to uzasadnione ekonomicznie. Zwolennicy natomiast twierdzą, że tylko w asemblerze da się napisać zoptymalizowany np. pod względem zależności czasowych program - pisząc to samo w C czy Bascomie nie zawsze da się zapanować nad kodem wynikowym. Każdy ma swoje racje. Nie będę tego wątku tutaj rozwijał gdyż wybór zależy od Ciebie, a skoro czytasz te słowa to znaczy, że temat Cię zainteresował.
Najlepszym argumentem z jakim się spotkałem przemawiającym za nauką asemblera, to ten który przeczytałem na stronie internetowej www.avr-asm-tutorial.net:
"Assembler or other languages, that is the question. Why should I learn another language, if I already learned other programming languages? The best argument: while you live in France you are able to get through by speaking english, but you will never feel at home then, and life remains complicated. You can get through with this, but it is rather inappropriate. If things need a hurry, you should use the country's language."
Tak więc wybór zostawiam Tobie Powyżej widnieje spis elementów języka asembler (w postaci listy odnośników), z którymi należy się zapoznać przed przystąpieniem do praktycznych ćwiczeń - wystarczy kliknąć w wybrany odnośnik aby przenieść się do właściwego miejsca.
Co to jest asembler?
Aby odpowiedzieć na to pytanie najpierw trzeba odpowiedzieć na pytanie, co to jest program dla mikrokontrolera. [4] Program jest to ciąg instrukcji danego procesora wykonywanych jeden po drugim w określonej przez programistę kolejności. Ciąg ten zapisany w formie symbolicznej (czyli z użyciem symbolicznych nazw instrukcji) stworzony przez programistę nazywa się programem źródłowym. Ten sam program przetworzony przez kompilator do postaci kodów dla mikroprocesora nazywamy programem binarnym lub programem wykonywalnym. Ten podział spowodowany jest tym, że mikrokontrolery nie mogą wykonywać programów źródłowych, ponieważ oczekują one ciągu zer i jedynek będących kodami instrukcji. Z drugiej strony człowiek nie może poruszać się w programie binarnym, ponieważ jest on dla niego kompletnie nieczytelny. Stosowany do przetwarzania z zapisu źródłowego na postać binarną program jest kompilatorem, czyli programem tłumaczącym jedną postać na drugą. Dla uniknięcia problemów z interpretacją zapisów w programach stworzony jest specjalny język programowania. Takim językiem jest asembler (jako podstawowy i elementarny język programowania). Oprócz asemblera są stosowane inne języki programowania, wśród których największą popularnością cieszy się język C.
Język programowania należy uważać za sformalizowany system reguł służących do opisu czynności jakie ma wykonać program. Sformalizowanie oznacza jednoznaczne określenie składni języka i zdefiniowanie pewnego zbioru słow (w sensie wyrazów) o ściśle określonym znaczeniu.
W programie używa się symbolicznych nazw instrukcji, wskazuje się poprzez nazwy używane zmienne, miejsca w programie. Każda nazwa (nazwa instrukcji, nazwa zmiennej) występująca w programie musi być kompilatorowi nazwą znaną (przykładowo wszystkie nazwy zdefiniowane w opisie języka). Wprowadzenie przez programistę nowych nazw jest związane z jednoznacznym określeniem jej znaczenia. W pewnych sytuacjach użycie nowej nazwy musi być poprzedzone jej definicją, która informuje kompilator o jej znaczeniu (przykładem mogą być nazwy zdefiniowane dyrektywami .equ, .def ). W wielu przypadkach dopuszcza się używanie nowych nazw bez ich wcześniejszego określenia (jak nazw etykiet jako miejsc w programie), które muszą być określone w obrębie programu. Kompilator po napotkaniu końca programu źródłowego sprawdzi, czy wszystkie użyte w programie nazwy są jednoznacznie określone. Jednoznaczność oznacza, że nie może być przykładowo w programie umieszczona jakaś etykieta w dwóch różnych miejscach.
Proces kompilacji (tłumaczenia z przykładowo języka asemblera na postać akceptowaną przez mikrokontrolery) może przebiegać w różny sposób (jest kilka programów różnych producentów będących kompilatorem języka asembler). Kompilator dostarczony przez firmę ATMEL jest programem, który tłumaczy i linkuje program (linkowanie programu oznacza określenie adresów wszystkich elementów występujących w programie). Wynikiem działania tego kompilatora jest gotowy do uruchomienia program. W innych rozwiązaniach kompilatorów proces tłumaczenia i linkowania jest rozdzielony. Kompilator przetwarzając tekst programu generuje postać częściowo skompilowaną (postać, w której instrukcje są zamienione na odpowiednie kody ale występują jeszcze symboliczne odwołania do zmiennych lub procedur). W procesie tworzenia programu dla mikrokontrolera występuje dodatkowy składnik, jakim jest oddzielny program do linkowania. Linker składa wszystkie fragmenty częściowo skompilowane w jedną całość uzupełniając wszystkie wzajemne powiązania między występującymi jeszcze nazwami symbolicznymi.
Elementy języka asembler
[4] Program źródłowy napisany w języku asemblera składa się z:
• instrukcji zapisanych w postaci symbolicznej,
• etykiet,
• dyrektyw,
• stałych liczbowych,
• napisów oraz nazw zdefiniowanych przez programistę.
Ich format zapisu jest określony i jednoznaczny. Jako nazwę (nazwę o szerokim znaczeniu) należy rozumieć każdy zapis, czyli ciąg znaków składający się liter, cyfr oraz znaku podkreślenia "_" zaczynający się od litery lub znaku podkreślenia. Stosuje się je do szeroko pojętego rozróżniania wszystkich części składowych programu (nazwy zmiennych, procedur, etykiet). Liczby to są zapisy składające się cyfr (oraz liter od "a" do "f" w przypadku liczb w zapisie szesnastkowym). Mogą być one zapisane w systemie dziesiętnym, szesnastkowym (hex) lub dwójkowym (binarnym). Do rozpoznania systemu zapisu liczb używane są pewne prefiksy poprzedzające samą liczbę, są to:
• 0x (zero i x) lub znak $ dla liczb zapisanych szesnastkowo,
• 0b (zero i b) dla liczba zapisywanych dwójkowo.
Jeżeli liczba nie jest poprzedzona żadnym prefiksem określającym system zapisu, to przyjmowane jest, że liczba zapisana w systemie dziesiętnym. Przykłady liczb:
• 10 – liczba w zapisie dziesiętnym,
• 255 – liczba w zapisie dziesiętnym,
• 0x0A – liczba w zapisie szesnastkowym,
• $FF – liczba w zapisie szesnastkowym,
• 0b11010011 – liczba w zapisie dwójkowym.
Napisy są to stałe tekstowe, które zapisywane są jako ciąg dowolnych znaków ujęty w apostrofy. Każdy znak z napisu jest zamieniany na liczbę wynikającą z przyporządkowania znakom określonych kodów liczbowych zgodnie z powszechnie obowiązującą normą ISO.
Komentarz w języku asemblera zaczyna się od znaku ";" (średnik) i obowiązuje do końca wiersza. W komentarzu mogą być zawarte dowolne znaki. Kompilator nie analizuje informacji zawartych w komentarzu.
[5] Każda linijka programu może zawierać maksymalnie 120 znaków. Każda linijka programu napisanego w asemblerze może mieć jedną z poniższych postaci:
[etykieta:] dyrektywa [argumenty] [komentarz]
[etykieta:] instrukcja [argumenty] [komentarz]
komentarz
pusta linia
gdzie [komentarz] ma postać ; [tekst]
Przykłady:
etykieta: .EQU var1=100 ; var1 przyjmuje wartość 100 (dyrektywa)
.EQU var2=200 ; var2 przyjmuje wartość 200
test: rjmp test ; nieskończona pętla (instrukcja)
; linia komentarza
; inny komentarz
Dyrektywy
[4] [5] Dyrektywy w języku asembler spełniają dwie funkcje: są zapisami sterującymi pracą kompilatora oraz definiują dodatkowe elementy programu (jak stałe, napisy, makra itp.). Różne kompilatory przyjmują zapis tych dyrektyw w różnej formie. Przykładowo kompilator języka asembler związany z programem AVR STUDIO wymaga zapisu nazwy dyrektywy ze znakiem kropki bezpośrednio przed dyrektywą, kompilatory dostarczane przez firmę IAR wymagają innego zapisu. Poniższy opis dotyczy oprogramowania oferowanego przez firmę ATMEL jako oprogramowania bezpłatnego (czyli dyrektywy w zapisie z kropką, pisownia małymi lub wielkimi literami na ma znaczenia). Z lewej strony widnieje wykaz dyrektyw z krótkim opisem, pełny opis każdej dyrektywy znajdziesz w pliku pomocy w AVR Studio [5] (w języku angielskim) lub "klikając" w nazwę dyrektywy przejdziesz do opisu na tej stronie.
BYTE
Dyrektywa BYTE rezerwuje zasoby w pamięci SRAM. Może być używana jedynie w segmencie danych (DSEG). BYTE wymaga jednego argumentu określającego wielkość rezerwowanych zasobów dla zmiennej określonej w etykiecie, która musi poprzedzać dyrektywę BYTE. Wielkość definiowanej zmiennej może być zapisana w postaci wyrażenia arytmetycznego (w wyrażeniu mogą wystąpić bezpośrednio liczby lub
rezerwuje zasoby w SRAM
BYTE
początek segmentu kodu
CSEG
wprowadza stałe 1 bajtowe
DB
nadaje rejestrowi inną nazwę
DEF
określa typ mikrokontrolera
DEVICE
początek segmentu danych
DSEG
wprowadza stałe 2 bajtowe
DW
koniec definicji makroinstrukcji
ENDMACRO
ENDM
definiowanie stałych
EQU
początek segmentu EEPROM
ESEG
koniec kompilacji pliku
EXIT
dołączenie wskazanego pliku
INCLUDE
tworzenie raportu z kompilacji
LIST
raport z kompilacji z makro
LISTMAC
definicja makroinstrukcji
MACRO
wyłączenie raportu z kompilacji
NOLIST
początek adresacji segmentu
ORG
przypisanie wartości wyrażenia
SET
identyfikatory wcześniej zdefiniowanych stałych liczbowych), którego wartość musi być wyliczalna przez kompilator.
Składnia:
etykieta: .BYTE wyrażenie
Przykład:
.DSEG
RSBufor: .BYTE 16 ; rezerwuje 16 bajtów dla RSBufor
CSEG
Dyrektywa CSEG oznacza, że wszystkie dalsze zapisy (instrukcji, danych włączonych do kodu itp.) dotyczą pamięci programu (pamięć FLASH). Miejsce (w sensie adresowym) umieszczenia generowanego przez kompilator kodu wynika z dyrektywy ORG. Kolejne zapisy powodują automatyczne zwiększanie adresu. Jeżeli w programie nie wystąpi żadna dyrektywa określająca rodzaj segmentu, to kompilator wszystko umieści w segmencie CSEG. W obrębie tego segmentu nie mogą występować dyrektywy przewidziane do deklaracji zmiennych. Brak wystąpienie dyrektywy ORG implikuje adresację od adresu o wartości 0 (zero). Dyrektywa nie zawiera żadnego argumentu.
Składnia:
.CSEG
Przykład:
.CSEG
Main: sbi PORTB,0 ; PORTB.0 = 1
DB, DW
Dyrektywy DB i DW rezerwują zasoby w pamięci programu lub pamięci EEPROM. Dyrektywy te muszą być poprzedzone etykietą i wymagają argumentów, które mogą być w postaci listy wyrażeń (co najmniej jedno wyrażenie). Etykieta określa adres inicjowanych zasobów pamięci, wyrażenie dla DB to wartość bajtowa, a dla DW dwubajtowa. Dyrektywa DB wprowadza stałe o strukturze bajtowej (liczby stałe bajtowe oraz napisy), dyrektywa DW wprowadza stałe o strukturze dwubajtowej (liczby stałe 16-bitowe, adresy zmiennych i etykiet w programie). W przypadku użycia dyrektywy DB należy pamiętać, że obszar wprowadzany tą dyrektywą zostanie uzupełniony bajtem o wartości zero gdy jego wielkość będzie nieparzysta. W dyrektywach tych pod symbolem lista wyrażeń należy rozumieć listę wyrażeń rozdzielonych przecinkami. Długie listy stałych w dyrektywach można przenosić do następnego wiersza (pamiętając o tym, by przerwać listę po parzystej liczbie bajtów) poprzez ponowne użycie tej samej dyrektywy ale bez etykiety (łącznie z dwukropkiem). W przypadku użycia dyrektywy DW dodatkowego komentarza wymaga kolejność umieszczonych bajtów. W pierwszej kolejności zapisany jest bajt będący młodszą częścią stałej oraz następnie bajt będący starszą częścią stałej.
Składnia:
etykieta: .DB lista wyrażeń
etykieta: .DW lista wyrażeń
Przykłady:
Function: .DB 0x0D,0x0A,"System kontroli.",0x0D,0x0A
.DB "Wersja sprzętu: 1.00",0x0D,0x0A
CodeArr: .DB '0' , '1'
.DB '2' , '3'
w każdym przypadku lista stałych zawiera parzystą liczbę bajtów,
CmmSrvArr: .DW Cmm0Service
.DW Cmm1Service
.DW Cmm2Service
gdzie wszystkie stałe wypisane przy dyrektywie DW są nazwami etykiet w programie.
DEF
Dyrektywa DEF pozwala nadać rejestrowi inną nazwę, którą następnie można używać w instrukcjach - nadal należy pamiętać, że wprowadzona nazwa tak naprawdę jest rejestrem.
Składnia:
.DEF definiowana nazwa = symbol rejestru
Przykład:
.DEF acc = r16
określa, że nazwa ‘acc’ występująca jako argument w instrukcji jest rejestrem r16. Taki zabieg znacznie zwiększa czytelność programu.
DEVICE
Dyrektywa DEVICE służy do poinformowania kompilatora na jaki model mikrokontrolera ma być generowany kod programu. Kompilator musi znać tą informację, czyli w każdym programie musi wystąpić ta dyrektywa jeden raz. W programie poprzez dyrektywę INCLUDE dołącza się do programu jeden z plików definiujących środowisko mikrokontrolera i między innymi zawarta tam jest ta dyrektywa. Te pliki definiujące dostarcza producent mikrokontrolerów, dla AT90S2313 taki plik ma nazwę 2313def.inc, a znajduje się w przypadku zainstalowanego AVR-Studio 4.09 w katalogu C:\Program Files\Atmel\AVR Tools\AvrAssembler\Appnotes - można sobie pod notatnikiem otworzyć taki plik i przeanalizować wszystkie definicje.
Składnia:
.DEVICE symbol mikrokontrolera
Przykład:
.DEVICE AT90S2313
DSEG
Dyrektywa DSEG oznacza, że wszystkie dalsze zapisy definiują zmienne. Adres, na jakim zostanie umieszczona zmienna może być zmieniany dyrektywą ORG. Brak dyrektywy ORG w obszarze przewidzianym na zmienne oznacza, że kompilator zacznie adresować je od adresu 60 hex. W obrębie segmentu danych nie mogą wystąpić żadne zapisy wymuszające określone wartości (np. nie można utworzyć zmiennej, która ma określoną wartość początkową, należy ją utworzyć jako typową zmienną i w programie zawrzeć instrukcje, które nadadzą tej zmiennej określoną wartość).
Składnia:
.DSEG
Przykład:
.DSEG
var: .BYTE 1
co oznacza zarezerwowanie jednego bajtu pamięci dla zmiennej var.
ENDMACRO, ENDM
Dyrektywa ENDMACRO lub ENDM oznacza koniec definicji makroinstrukcji zapoczątkowanej dyrektywą MACRO. Nie wymaga żadnych argumentów.
Składnia:
.ENDMACRO
lub
.ENDM
Przykład:
.MACRO ldz ; początek definicji makroinstrukcji
. ;
. ; definicja makroinstrukcji
. ;
.ENDMACRO ; koniec definicji makroinstrukcji
EQU
Dyrektywa służy do definiowania stałych, przydziela ona jakiemuś identyfikatorowi (nazwie) określoną wartość (może to być wyrażenie), która może być później użyta w jakimś wyrażeniu. Tak zdefiniowana stała nie może być zmieniana czy też redefiniowana.
Składnia:
.EQU nazwa = wyrażenie
Przykład:
.EQU x1 = 'x'
.EQU x2 = 145
W powyższych przykładach przyporządkowana jest identyfikatorowi x1 taka wartość bitowa, która odpowiada małej literze x, w drugim przypadku identyfikator x2 ma wartość liczbową 145.
ESEG
Dyrektywa ESEG oznacza, że wszystkie dalsze zapisy odnoszą się do pamięci EEPROM. W segmencie zapoczątkowanym przez dyrektywę ESEG znajdują się tylko dyrektywy DB i DW. Adresacja zmiennych jest określona przez dyrektywę ORG (brak specyfikacji ORG w obrębie pamięci EEPROM oznacza wartość początkowa równą zero). W tym segmencie możliwe jest, oprócz powołania do istnienia zmiennej, nadanie jej określonej wartości początkowej. W strukturze postaci wynikowej programu (najczęściej w formacie heksadecymalnym) jest przewidziane na to miejsce i programator (w trakcie programowania mikrokontrolera) umieści w tej pamięci określone wartości początkowe. Nie oznacza to jednak, że program w czasie pracy nie może zmienić wartości tych zmiennych. Każde następne uruchomienie programu w zmiennych tych będzie zawierać wartość ostatnio zapisaną (zmienne same nigdy nie zmienią swej wartości).
Składnia:
.ESEG
Przykład:
.ESEG
CodeArr: .DB '0' , '1'
EXIT
Dyrektywa EXIT oznacza zakończenie kompilacji z danego pliku. Podczas normalnej pracy kompilacja trwa do końca pliku jeżeli jednak w dołączonym przez dyrektywę INCLUDE pliku pojawi się dyrektywa EXIT to kompilator zakończy kompilację dołączonego pliku i będzie kontynuował pracę od linii następnej po dyrektywie INCLUDE.
Składnia:
.EXIT
Przykład:
.EXIT ; koniec kompilacji
INCLUDE
Dyrektywa INCLUDE włącza do kompilacji wskazany plik. Kompilacja trwa do końca pliku lub do napotkania dyrektywy EXIT. Dołączony przez dyrektywę INCLUDE plik również może zawierać dyrektywy INCLUDE. Nazwa dołączanego pliku powinna być umieszczona między znakami " ".
Składnia:
.INCLUDE "nazwa pliku "
Przykład:
.INCLUDE "2313def.inc" ; dołączenie pliku definiującego
; mikrokontroler AT90S2313
LIST
Dyrektywa LIST informuje kompilator o konieczności stworzenia raportu z kompilacji.
Składnia:
.LIST
Przykład:
.NOLIST ; wyłączenie raportu z kompilacji
.INCLUDE "2313def.inc" ; dołączenie pliku
.LIST ; ponowne załączenie raportu
; z kompilacji
LISTMAC
Dyrektywa LISTMAC informuje kompilator o konieczności dołączenia do raportu z kompilacji informacji z kompilacji makroinstrukcji.
Składnia:
.LIST
Przykład:
.NOLIST ; wyłączenie raportu z kompilacji
.INCLUDE "2313def.inc" ; dołączenie pliku
.LIST ; ponowne załączenie raportu
.LISTMAC ; dołączenie informacji
; o makroinstrukcji
MACRO
Dyrektywa MACRO oznacza początek definicji makroinstrukcji. Dyrektywa wymaga argumentu w postaci nazwy makroinstrukcji.
Składnia:
.MACRO nazwa makroinstrukcji
Przykład:
.MACRO ldz ; początek definicji makroinstrukcji
ldi r30, low(@0)
ldi r31, high(@0)
.ENDMACRO ; koniec definicji makroinstrukcji
Przy okazji warto zauważyć, że makroinstrukcje mogą zawierać parametry. Wyjaśnia to pojawienie się w powyższym przykładzie tajemniczego zapisu low(@0) czy high(@0). Dla przypomnienia: @0 oznacza pierwszy parametr, @9 oznacza dziesiąty parametr. Liczba parametrów makroinstrukcji jest limitowana do 10.
NOLIST
Dyrektywa NOLIST informuje kompilator o konieczności wyłączenia raportu z kompilacji.
Składnia:
.NOLIST
Przykład:
.NOLIST ; wyłączenie z raportu z kompilacji
.INCLUDE "2313def.inc" ; dołączonego pliku AT90S2313def.inc
ORG
Dyrektywa ORG służy do określenia miejsca (w sensie adresu), gdzie kompilator rozpocznie umieszczanie generowanych bajtów (jeżeli dyrektywa ORG jest użyta w obrębie CSEG) lub określa początek adresacji przyszłych zmiennych (jeżeli dyrektywa jest użyta w obrębie DSEG). Dyrektywa ta wymaga użycia argumentu w postaci wyrażenia określającego adres. W obrębie segmentu kodu programu dyrektywa używana jest do "usztywnienia" ściśle określonych miejsc w programie (głównie do wskazania początków obsługi przerwań, na które reakcja jest ściśle określona w adresacji programu). W segmencie danych (DSEG) dyrektywy tej można użyć do "poinformowania" kompilatora asemblera o użyciu przykładowo dodatkowej pamięci RAM przyłączonej na zewnątrz (przykładowo mikrokontroler AT90S8515 może obsługiwać zewnętrzną pamięć).
Składnia:
.ORG wyrażenie
gdzie wyrażenie wskazuje adres w pamięci
Przykład:
.DSEG
Int_RAM_Variable1: .BYTE 1
Int_RAM_Variable2: .BYTE 1
.
.
.
.ORG 0x8000
Ext_RAM_Variable1: .BYTE 1
Ext_RAM_Variable2: .BYTE 1
Zgłoszenie dyrektywą DSEG (jeżeli jest pierwsze) oznacza, że zgłoszone zmienne (Int_RAM_Variable1 i kolejne) będą umieszczane w pamięci wewnętrznej RAM poczynając od adresu 60 hex. Użycie dyrektywy ORG spowodowało przestawienie pozycji, na jakiej będą umieszczane zmienne na adres 8000 hex. Kompilator będzie nadawał kolejnym zmiennym adresy z przestrzeni zewnętrznej pamięci RAM. Używając zewnętrznych pamięci RAM (dotyczy to wszystkich dołączanych na zewnątrz pamięci i portów) należy pamiętać, że w przypadku zbudowania dekodera adresowego o niepełnym dekodowaniu, może okazać się, że pewne komórki są umieszczone w przestrzeni adresowej wielokrotnie.
SET
Dyrektywa SET przypisuje wartość wyrażenia jakiemuś identyfikatorowi. Identyfikator może być później użyty w jakimś innym wyrażeniu.
Składnia:
.SET nazwa = wyrażenie
Przykład:
.SET io_offset = 0x23
.SET portA = io_offset + 2
Funkcje i operatory w wyrażeniach
[4] W zapisach instrukcji i dyrektyw języka asembler mogą występować wyrażenia, które w swoim zapisie mogą używać funkcji.
Wśród dopuszczalnych funkcji są następujące:
• LOW(wyrażenie) - funkcja, której wynikiem jest najmłodszy bajt (bity
od b0 do b7) wartości wyrażenia - przykładowo LOW(0x1234) daje
w wyniku liczbę $34 (zapis szesnastkowy),
• HIGH(wyrażenie) - funkcja, której wynikiem jest drugi bajt (bity od b8
do b15) wartości wyrażenia - przykładowo HIGH(0x1234) daje
w wyniku liczbę $12,
• BYTE2(wyrażenie) - funkcja tożsama z funkcją HIGH,
• BYTE3(wyrażenie) - funkcja, której wynikiem jest trzeci bajt (bity od
b16 do b23) wartości wyrażenia - przykładowo BYTE3(0x654321) daje
w wyniku liczbę $65,
• BYTE4(wyrażenie) - funkcja, której wynikiem jest czwarty bajt (bity od
b24 do b31) wartości wyrażenia - przykładowo BYTE4(0x87654321
daje w wyniku liczbę $87,
• LWRD(wyrażenie) - funkcja, której wynikiem jest młodsze słowo
dwubajtowe (bity od b0 do b15) wartości wyrażenia,
• HWRD(wyrażenie) - funkcja, której wynikiem jest starsze słowo
dwubajtowe (bity od b16 do b31) wartości wyrażenia,
• PAGE(wyrażenie) - funkcja, której wynikiem jest liczba będąca kodem
strony (bity od b16 do b21) wartości wyrażenia,
• EXP2(wyrażenie) - funkcja, której wynikiem jest liczba będąca
odpowiednią potęgą liczby 2 (2 do potęgi wartość wyrażenia),
• LOG2(wyrażenie) - funkcja, której wynikiem jest liczba będąca częścią
całkowitą logarytmu przy podstawie 2 z wartości wyrażenia.
Operatory mogące występować w wyrażeniach:
Symbol
Funkcja
Znaczenie
!
Logiczny operator
negacji
Jednoargumentowy operator zwracający wartość 1 jeżeli wartość wyrażenia jest równa zero; w przeciwnym wypadku zwracana jest wartość 0
~
Bitowy operator
negacji
Jednoargumentowy operator zwracający wartość zanegowaną logicznie (odwrócone wszystkie bity)
-
Operator minus
Jednoargumentowy operator zwracający wartość z arytmetycznie zmienionym znakiem
*
Operator mnożenia
Dwuargumentowy operator zwracający wartość arytmetycznego iloczynu
/
Operator dzielenia
Dwuargumentowy operator zwracający wartość arytmetycznego ilorazu (część całkowitą)
+
Operator sumowania
Dwuargumentowy operator zwracający wartość arytmetycznej sumy
-
Operator odejmowania
Dwuargumentowy operator zwracający wartość arytmetycznej różnicy
<<
Operator przesunięcia w lewo
Dwuargumentowy operator zwracający wartość będącą wynikiem przesunięcia w lewo (ilość pozycji o ile należy przesunąć jest drugim argumentem)
>>
Operator przesunięcia w prawo
Dwuargumentowy operator zwracający wartość będącą wynikiem przesunięcia w prawo (ilość pozycji o ile należy przesunąć jest drugim argumentem)
<
Operator porównania (mniejsze)
Dwuargumentowy operator zwracający 1 jeżeli wartość wyrażenia po lewej stronie jest mniejsza niż wartość wyrażenia po prawej stronie; w przeciwnym wypadku zwracana jest wartość 0
<=
Operator porównania (mniejsze lub równe)
Dwuargumentowy operator zwracający 1 jeżeli wartość wyrażenia po lewej stronie jest mniejsza lub równa niż wartość wyrażenia po prawej stronie; w przeciwnym wypadku zwracana jest wartość 0
>
Operator porównania (większe)
Dwuargumentowy operator zwracający 1 jeżeli wartość wyrażenia po lewej stronie jest większa niż wartość wyrażenia po prawej stronie; w przeciwnym wypadku zwracana jest wartość 0
>=
Operator porównania (większe lub równe)
Dwuargumentowy operator zwracający 1 jeżeli wartość wyrażenia po lewej stronie jest większa lub równa niż wartość wyrażenia po prawej stronie; w przeciwnym wypadku zwracana jest wartość 0
==
Operator porównania (równe)
Dwuargumentowy operator zwracający 1 jeżeli wartość wyrażenia po lewej stronie jest równa z wartością wyrażenia po prawej stronie; w przeciwnym wypadku zwracana jest wartość 0
!=
Operator porównania (nie równe)
Dwuargumentowy operator zwracający 1 jeżeli wartość wyrażenia po lewej stronie nie jest równa z wartością wyrażenia po prawej stronie; w przeciwnym wypadku zwracana jest wartość 0
&
Operator logicznego iloczynu
Dwuargumentowy operator zwracający wartość logicznego iloczynu (logiczne and)
^
Operator logicznej exclusive or
Dwuargumentowy operator zwracający wartość logicznej sumy Å.
|
Operator logicznej sumy
Dwuargumentowy operator zwracający wartość logicznej sumy (logiczne or)
W ogólnym wypadku w wyrażeniu mogą występować wcześniej zdefiniowane stałe oraz zmienna (jedna). Należy pamiętać, że wartością zmiennej występującej w wyrażeniu jest jej adres (nie zawartość).
Przykłady użycia funkcji:
.equ
x1
= exp2(eewe)
; eewe jest stałą o wartości
; 1 (zobacz bity rejestru; sterującego pracą EEPROM)
.equ
x2
= 0x02
;
oba powyższe zapisy w sumie dają tę samą wartość;
ldi
r16,low((var<<1)+7+x2)
powyższy zapis oznacza, że do rejestru r16 należy wpisać liczbę będącą młodszą częścią z wyrażenia - adres zmiennej var należy przesunąć w lewo o jedną pozycję do tego dodać stałą o wartości 7 i wynik wyrażenia x2;
ldi
r16,!0xf0
wpisz do rejestru r16 stałą o wartości 0 - wartość wyrażenia !0xf0 jest równa 0
ldi
r16,~0xf0
wpisz do rejestru r16 stałą o wartości 0x0f - wartość wyrażenia ~0xf0 jest równa 0x0f;
ldi
r16,-1
wpisz do rejestru r16 stałą o wartości 0xff - wartość wyrażenia -1 dla słowa jednobajtowego wynosi 0xff;
ldi
r16,eewe+eemwe
wpisz do rejestru r16 stałą o wartości 3 (wartość eewe=1 i eemwe=2);
ldi
r16,(1<<eewe)+(1<<eemwe)
wpisz do rejestru r16 stałą o wartości 0x06 (wartość (1<<eewe)=0x02 i (1<<eemwe)=0x04 co w sumie daje 0x06);
ldi
r16,(1<<eewe)&(1<<eemwe)
wpisz do rejestru r16 stałą o wartości 0 (wartość (1<<eewe)=0x02 i (1<<eemwe)=0x04 co w iloczynie logicznym daje wynik równy zero).
Instrukcje asemblera
[4] Instrukcje języka asembler stanowią symboliczny zapis ich kodów wraz z ewentualnymi jej operandami (argumentami).Instrukcje w ogólnym przypadku mają następujący zapis:
etykieta:
instrukcja
[argumenty]
;komentarz
Gdzie występujące w zapisie elementy mają następujące znaczenie:
• etykieta jest symbolicznym określeniem miejsca w programie
(przykładowo jako miejsca, do którego może być wykonany skok)
kompilator tłumacząc program z języka asembler na postać binarną
przyporządkowuje etykiecie określoną wartość liczbową będącą jej adresem, etykieta nie jest obowiązkowym elementem w zapisie instrukcji,
• instrukcja (wraz z jej ewentualnym lub ewentualnymi operandami)
jest symbolicznym zapisem kodu instrukcji, jaka ma być w danym
miejscu wykonana przez mikrokontroler, w przypadku użycia
wcześniej zdefiniowanej makroinstrukcji kompilator zamieni ją na ciąg,
instrukcji mikrokontrolera zgodnie z jej definicją,
• komentarz jako dowolny ciąg znaków zaczynający się od znaku
średnika ";" nie jest analizowany przez kompilator, programista może
w komentarzu zawrzeć dowolne swoje uwagi lub notatki,
komentarz obowiązuje do końca wiersza.
W instrukcji (łącznie z makroinstrukcją) mogą występować operandy przewidziane dla danej instrukcji. W niektórych instrukcjach operandem jest symboliczne oznaczenie rejestru roboczego (od R0 do R31). Istnieje grupa instrukcji, w której operand jest symbolicznym odwołaniem do zmiennej. Zmienne są identyfikowane przez swój adres (jako liczba określająca jej położenie w przestrzeni pamięci RAM). W ogólnym przypadku jako adres zmiennej może być użyte dowolne wyrażenie arytmetyczne z użyciem jej adresu (tylko jednej zmiennej).
Przykłady:
.dseg
;
variable:
.byte
1
; zmienna o nazwie variable
; o wielkości jednego bajtu o jakimś adresie (obliczonym przez kompilator); wynikającym z wszystkich dotychczas występujących zmiennych oraz; z ewentualnego użycia dyrektywy .org
.cseg
;
lds
r16,variable
; ta instrukcja spowoduje
; przepisanie bajtu z pamięci RAM o adresie symbolicznym variable; (kompilator wstawi do generowanego kodu liczbę będącą rzeczywistym; adresem zmiennej w pamięci) rejestru o symbolicznej nazwie r16
ldi
r16,low(variable)
; ta instrukcja oznacza wpisanie
; do rejestru r16 liczby będącej młodszą częścią adresu zmiennej variable
ldi
r16,high(variable)
; ta instrukcja oznacza wpisanie
; do rejestru r16 liczby będącej starszą częścią adresu zmiennej variable
Teraz pozostało jeszcze zapoznać się z listą rozkazów mikrokontrolerów AVR i można przystąpić do pisania pierwszego programu w asemblerze.
Lista instrukcji (rozkazów) mikrokontrolerów AVR
Przedstawiona tutaj lista instrukcji i komentarz wprowadzający do niej zostały opracowane na podstawie materiałów zawartych w karcie katalogowej AT90S2313 i w książkach "Mikrokontrolery AVR w praktyce" [1], "Mikrokontrolery rodziny AVR - AT90S2313" [6] oraz materiałów jakie otrzymałem od Gawła [4]. Pełny opis rozkazów wraz z odpowiednimi przykładami zastosowania można znaleźć na ok. 200 stronach wyżej wymienionej książki J. Dolińskiego "Mikrokontrolery AVR w praktyce" [1] - polecam.
Listę instrukcji języka asembler mikrokontrolerów z rodziny AVR można podzielić na następujące grupy:
• instrukcje arytmetyczne i logiczne
• instrukcje skoków
• instrukcje przesyłania danych
• instrukcje operacji bitowych
• instrukcje kontroli pracy jednostki centralnej (MCU)
W grupie instrukcji arytmetycznych znajdują się wszystkie instrukcje dodawania oraz dodawania z przeniesieniem, instrukcje odejmowania oraz odejmowania z przeniesieniem, instrukcje sumy logicznej "lub" (ang. or), instrukcje iloczynu logicznego "i" (ang. and) oznaczanej symbolem &, sumy logicznej "albo" (ang. exclusive or) oznaczanej symbolem Å, instrukcje negacji logicznej (ang. not) instrukcji mnożenia arytmetycznego, instrukcje zwiększania i zmniejszania o jeden. W grupie instrukcji skoków można wyróżnić instrukcje skoków bezwarunkowych oraz skoków warunkowych. Instrukcje skoków bezwarunkowych to takie instrukcje, w których sterowanie w programie zostaje przeniesione w nowe miejsce bezwarunkowo. Instrukcje skoków warunkowych, to takie instrukcje, w których sterowanie w programie zostanie przeniesione w nowe miejsce tylko w pewnych ściśle określonych warunkach, jeżeli warunek nie jest spełniony wykonanie programu przechodzi do następnej instrukcji. Do instrukcji skoku należy jeszcze zaliczyć instrukcje wywołania procedury oraz instrukcje powrotu z procedury. Specyfiką instrukcji wywołania procedury jest to, że ta instrukcja przed wykonaniem skoku (lista instrukcji procesorów z rodziny AVR nie zawiera instrukcji warunkowego wywołania procedury) zawsze zapamiętuje miejsce powrotu. Instrukcja powrotu z procedury jest instrukcją skoku bezwarunkowego do miejsca zapamiętanego przez instrukcję wywołania. W obrębie grupy instrukcji przesyłania danych występują instrukcje, których zadaniem jest przesyłanie zawartości określonych rejestrów do innych rejestrów, wymiany danych pomiędzy rejestrami roboczymi i wewnętrzną pamięcią RAM oraz zewnętrzną pamięcią RAM (jeżeli dany model mikrokontrolera ma takie możliwości techniczne). Do instrukcji operujących na bitach należą instrukcje pozwalające modyfikować stany pojedynczych bitów, instrukcje przesunięć logicznych i cyklicznych. W grupie instrukcji kontroli pracy mikrokontrolera jest instrukcja pusta, instrukcja zerowania watchdoga i instrukcje sterujące przejściem do stanów obniżonego poboru prądu. Przed omówieniem poszczególnych instrukcji niezbędne jest wyjaśnienie kilku istotnych pojęć. Jednym z takich jest operand instrukcji, czyli określenie zasobu jaki bierze udział w wykonaniu instrukcji (przykładowo wskazanie na rejestr z puli wszystkich rejestrów) lub szeroko rozumiana stała (stała jako adres skoku, stała jako wartość do wpisania do rejestru).
W tabeli prezentującej instrukcje użyte są symbole operandów, których znaczenie jest wyjaśnione obok. Szczególną uwagę należy zwrócić na przyjęte oznaczenie rejestrów. Wynikają one z ich ograniczonego zasięgu działania. Obok zostały również wyjaśnione przyjęte zapisy symboliczne używane w opisie rozkazów jak również oznaczenie zachowania się znaczników (flag) po wykonaniu rozkazu.
Ze względu na to, że działanie rozkazów mikrokontrolera (µC) jest silnie związane z jego architekturą, wszystkie wątpliwości należy wyjaśniać posługując się odpowiednimi kartami katalogowymi dla danego µC.
W µC można wyróżnić trzy rejestry, które maja wpływ na przebieg programu, są to:
• 16-bitowy rejestr PC - licznik programu (ang. Program Counter)
zawierający adres pamięci programu, spod którego jest pobierany
kod rozkazu wykonywanego w kolejnym kroku,
• 8-bitowy (dla AT90S2313) lub 16-bitowy rejestr wskaźnika stosu - SP
(ang. Stack Pointer), zawierający adres pamięci SRAM, pod który
będzie zapisywany np. adres powrotu z podprogramu (adres
następnego rozkazu po rozkazie wywołania podprogramu),
• 8-bitowy rejestr znaczników (flag) - SREG (ang. Status Register),
zawierający znaczniki mogące mieć wpływ na przebieg programu
(wykorzystywane np. w rozkazach skoków warunkowych).
Ze względu na szczególne znaczenie tych rejestrów w opisie rozkazów uwzględniony został sposób ich modyfikacji przez poszczególne rozkazy.
Poniżej przedstawione są w tabelach poszczególne grupy rozkazów (instrukcji). Na pytanie czy warto się uczyć tej listy rozkazów można odpowiedzieć w dwojaki sposób. Tak, ponieważ wpływa to na pisanie programów w sposób zapewniający optymalne wykorzystanie zasobów mikrokontrolera. Nie, bo asembler w swojej "czystej" postaci jest coraz mniej wykorzystywany ustępując językom wysokiego poziomu takim jak C czy Bascom. Jednak wszystkim, którzy zaczynają swoją przygodę z AVRami polecam zapoznanie się z ich listą rozkazów, ponieważ ułatwia to zrozumienie budowy i działania mikrokontrolera.
W poniższych tabelach wiersze zaznaczone tłem różowym oznaczają, że opisywany rozkaz nie jest zaimplementowany w AT90S2313 (może dotyczyć to także innych mikrokontrolerów), tło szare świadczy o tym, że dany rozkaz nie jest zaimplementowany we wszystkich mikrokontrolerach. Szczegółowo jest to wyjaśnione w kartach katalogowych.
Znaczenie symboli z tabeli instrukcji
Rejestr źródła lub rejestr przeznaczenia (R30...R31)
-
Rd
Rejestr źródła (R30...R31)
-
Rs
Rejestr górny (R16...R31)
-
Rh
Rejestr przeznaczenia z zakresu rejestrów górnych
-
Rhd
Rejestr źródła z zakresu rejestrów górnych
-
Rhs
Rejestr środkowy (R16...R23)
-
Rm
Rejestr przeznaczenia z zakresu rejestrów środkowych
-
Rmd
Rejestr źródła z zakresu rejestrów środkowych
-
Rms
Para rejestrów(r24=R25:R24, r27=R27:R26, r28=R29:R28, r30=R31:R30)
-
RR
Rejestry indeksowe (X=R27:R26, Y=R29:R28, Z=R31:R30)
-
Rxyz
Rejestry indeksowe z przemieszczeniem (Y=R29:R28, Z=R31:R30)
-
Ry
Stała wskaźnikowa (0...63)
-
c63
Stała używana jako parametr określający zakres skoku warunkowego (-64...63)
-
c127
Stała 8-bitowa (0...255)
-
c255
Stała używana jako parametr określający zakres skoku względnego (-512...511)
-
c1024
Stała określająca 16-bitowy adres (0...65535)
-
adr
Stała określająca względne przemieszczenie w obrębie ±2k
-
adr2k
Stała określająca 16-bitowy adres
-
adr64k
Stała określająca 16-bitowy adres (0...$FFFF) w obrębie bieżącego segmentu
-
adr65535
Stała określająca 22-bitowy adres (0...$3FFFFF)
-
adr4M
Pozycja bitu (0...7)
-
b
Numer portu (rejestru) należącego do obszaru we/wy (0...63=$00...$3F)
-
P
Adres portu (rejestru) należącego do dolnej strony obszaru we/wy (0...31=$00...$1F)
-
Pl
Dodawanie arytmetyczne
-
+
Odejmowanie arytmetyczne
-
–
Suma logiczna
-
Ú
Iloczyn logiczny
-
Ù
Suma modulo 2 (Ex-OR)
-
Å
Zawartość 8-bit. rejestru Ri
-
Ri
Zawartość 16-bitowego rejestru złożonego z rejestrów Rj (starszy) i Ri (młodszy)
-
Rj:Ri
Komórka pamięci adresowana przez rejestr Ri
-
(Ri)
Bit b rejestru Ri
-
Ri(b)
Bity od i do j rejestru Rk, np. R1(3...0) - młodsze 4 bity rejestru R1
-
Rk(j...i)
Implikacja logiczna(jeżeli a, to b)
-
a => b
Przypisanie b do a(np. wpisanie wartości b do rejestru a)
-
a ¬ b
Flaga ustawiana zgodnie z wynikiem operacji
-
«
Flaga zerowana ("0")
-
0
Flaga ustawiana ("1")
-
1
Flaga pozostaje bez zmian
-
–
Instrukcje arytmetyczne i logiczne [1][6]
Mnemonika
Operandy
Opis
Operacje
Zmieniane flagi
Liczba cykli
ADD
Rd,Rs
Dodaj zawartość dwóch rejestrów
Rd ¬ Rd + Rs
Z,C,N,V,H,S
1
ADC
Rd,Rs
Dodaj zawartość dwóch rejestrów z przeniesieniem
Rd ¬ Rd + Rs + C
Z,C,N,V,H,S
1
ADIW
RR,c63
Dodaj bezpośrednio stałą do słowa
RRh:RRl ¬ RRh:RRl + c63
Z,C,N,V,S
2
SUB
Rd,Rs
Odejmij zawartość dwóch rejestrów
Rd ¬ Rd - Rs
Z,C,N,V,H,S
1
SUBI
Rh,c255
Odejmij stałą od zawartości rejestru
Rh ¬ Rh - c255
Z,C,N,V,H,S
1
SBIW
RR,c63
Odejmij bezpośrednio stałą do słowa
RRh:RRl ¬ RRh:RRl - c63
Z,C,N,V,S
2
SBC
Rd,Rs
Odejmij zawartość dwóch rejestrów z przeniesieniem
Rd ¬ Rd - Rs - C
Z,C,N,V,H,S
1
SBCI
Rh,c255
Odejmij stałą z przeniesieniem od zawartości rejestru
Rh ¬ Rh - c255 - C
Z,C,N,V,H,S
1
AND
Rd,Rs
Iloczyn logiczny zawartości rejestrów
Rd ¬ Rd Ù Rs
Z,N,V,S
1
ANDI
Rh,c255
Iloczyn logiczny zawartości rejestru i stałej
Rh ¬ Rh Ù c255
Z,N,V,S
1
OR
Rd,Rs
Suma logiczna zawartości rejestrów
Rd ¬ Rd Ú Rs
Z,N,V,S
1
ORI
Rh,c255
Suma logiczna zawartości rejestru i stałej
Rh ¬ Rh Ú c255
Z,N,V,S
1
EOR
Rd,Rs
Suma Exclusive OR zawartości rejestrów
Rd ¬ Rd Å Rs
Z,N,V,S
1
COM
Rd
Uzupełnienie do jedności (negacja bitów)
Rd ¬ $FF - Rd
Z,C,N,V,S
1
NEG
Rd
Uzupełnienie do dwóch
Rd ¬ $00 - Rd
Z,C,N,V,H,S
1
SBR
Rh,c255
Ustaw bity(y) w rejestrze
Rh ¬ Rh Ú c255
Z,N,V,S
1
CBR
Rh,c255
Zeruj bit(y) w rejestrze
Rh ¬ Rh Ù c255
Z,N,V,S
1
INC
Rd
Zwiększ o 1 zawartość rejestru
Rd ¬ Rd + 1
Z,N,V,S
1
DEC
Rd
Zmniejsz o 1 zawartość rejestru
Rd ¬ Rd - 1
Z,N,V,S
1
TST
Rd
Sprawdź zero lub minus
Rd ¬ Rd Ù Rd
Z,N,V,S
1
CLR
Rd
Zeruj wszystkie bity rejestru
Rd ¬ Rd Å Rd
Z,N,V,S
1
SER
Rh
Ustaw wszystkie bity rejestru
Rh ¬ $FF
¾
1
MUL
Rd,Rs
Mnożenie bez znaku zawartości rejestrów
R1:R0 ¬ Rd · Rs
Z,C
2
MULS
Rhd,Rhs
Mnożenie ze znakiem zawartości rejestrów
R1:R0 ¬ Rhd · Rhs
Z,C
2
MULSU
Rhd,Rhs
Mnożenie zawartości rejestrów (jeden ze znakiem, drugi bez znaku)
R1:R0 ¬ Rhd · Rhs
Z,C
2
FMUL
Rd,Rs
Mnożenie liczb ułamkowych bez znaku
R1:R0 ¬ (Rd · Rs) << 1
Z,C
2
FMULS
Rd,Rs
Mnożenie liczb ułamkowych ze znakiem
R1:R0 ¬ (Rd · Rs) << 1
Z,C
2
FMULSU
Rd,Rs
Mnożenie liczby ułamkowej ze znakiem z liczbą ułamkową bez znaku
R1:R0 ¬ (Rd · Rs) << 1
Z,C
2
Instrukcje skoków [1][6]
Mnemonika
Operandy
Opis
Operacje
Zmieniane flagi
Liczba cykli
RJMP
adr2k
Skok względny
PC ¬ PC + adr2k + 1
¾
2
IJMP
Skok pośredni określony zawartością rejestru indeksowego Z
PC ¬ Z
¾
2
EIJMP
Rozszerzony skok pośredni określony zawartością rejestru indeksowego Z
PC(15...0)) ¬ Z
PC(21...16)) ¬ EIND
¾
2
JMP
adr4M
Skok bezpośredni
PC ¬ adr4M
¾
3
RCALL
c1024
Względne wywołanie podprogramu
(SPL) ¬ PC + 1
SPL ¬ SPL - 2
PC ¬ PC + 1024 + 1
¾
3
ICALL
Pośrednie wywołanie podprogramu określone zawartością rejestru indeksowego Z
(SPL) ¬ PC + 1
SPL ¬ SPL - 2
PC ¬ Z
¾
3
EICALL
Rozszerzone, pośrednie wywołanie podprogramu określone zawartością rejestru Z oraz EIND
(SPL) ¬ PC + 1
SPL ¬ SPL - 3
PC(15...0) ¬ Z
PC(21...16) ¬ EIND
¾
4
CALL
adr4M
Rozszerzone, pośrednie wywołanie podprogramu określone zawartością rejestru Z oraz EIND
(SPL) ¬ PC + 1
SPL ¬ SPL - 3
PC(15...0) ¬ Z
PC(21...16) ¬ EIND
¾
4
RET
Powrót z podprogramu
PC ¬ (SPL)
SPL ¬ SPL + 2
¾
4
RETI
Powrót z procedury obsługi przerwania
PC ¬ (SPL)
SPL ¬ SPL + 2
I
4
CPSE
Rd,Rs
Porównaj, skocz jeśli równe
(Rd=Rs) => PC ¬ PC + 2
lub 3
¾
1 lub 2
CP
Rd,Rs
Porównaj zawartość rejestrów
Rd - Rs
Z,C,N,V,H,S
1
CPC
Rd,Rs
Porównaj zawartość rejestrów z przeniesieniem
Rd - Rs - C
Z,C,N,V,H,S
1
CPI
Rh,c255
Porównaj zawartość rejestru ze stałą
Rh - c255
Z,C,N,V,H,S
1
SBRC
Rs,b
Przeskocz jeśli bit w rejestrze jest wyzerowany
Rs(b) = 0 => PC ¬ PC + 2Rs(b) = 1 => PC ¬ PC + 1
¾
1, 2 lub 3
SBRS
Rs,b
Przeskocz jeśli bit w rejestrze jest ustawiony
Rs(b) = 1 => PC ¬ PC + 2Rs(b) = 0 => PC ¬ PC + 1
¾
1, 2 lub 3
SBIC
Pl,b
Przeskocz jeśli bit w rejestrze we/wy jest wyzerowany
Pl(b) = 0 => PC ¬ PC + 2Pl(b) = 1 => PC ¬ PC + 1
¾
1, 2 lub 3
SBIS
Pl,b
Przeskocz jeśli bit w rejestrze we/wy jest ustawiony
Pl(b) = 1 => PC ¬ PC + 2Pl(b) = 0 => PC ¬ PC + 1
¾
1, 2 lub 3
BRBS
b,c127
Skok względny jeśli flaga w rejestrze SREG jest ustawiona
SREG(b) = 1 => PC ¬ PC + c127 + 1SREG(b) = 0 => PC ¬ PC + 1
¾
1 lub 2
BRBC
b,c127
Skok względny jeśli flaga w rejestrze SREG jest wyzerowana
SREG(b) = 0 => PC ¬ PC + c127 + 1SREG(b) = 1 => PC ¬ PC + 1
¾
1 lub 2
BREQ
c127
Skok względny jeśli równe (gdy Z=1)
Z = 1 => PC ¬ PC + c127 + 1Z = 0 => PC ¬ PC + 1
¾
1 lub 2
BRNE
c127
Skok względny jeśli nie równe (gdy Z=0)
Z = 0 => PC ¬ PC + c127 + 1Z = 1 => PC ¬ PC + 1
¾
1 lub 2
BRCS
c127
Skok względny jeśli flaga przeniesienia jest ustawiona (gdy C=1)
C = 1 => PC ¬ PC + c127 + 1C = 0 => PC ¬ PC + 1
¾
1 lub 2
BRCC
c127
Skok względny jeśli flaga przeniesienia jest wyzerowana (gdy C=0)
C = 0 => PC ¬ PC + c127 + 1C = 1 => PC ¬ PC + 1
¾
1 lub 2
BRSH
c127
Skok względny jeśli większy lub równy (gdy C=0, dotyczy liczb bez znaku)
C = 0 => PC ¬ PC + c127 + 1C = 1 => PC ¬ PC + 1
¾
1 lub 2
BRLO
c127
Skok względny jeśli mniejszy (gdy C=1, dotyczy liczb bez znaku)
C = 1 => PC ¬ PC + c127 + 1C = 0 => PC ¬ PC + 1
¾
1 lub 2
BRMI
c127
Skok względny jeśli wartość ujemna (gdy N=1)
N = 1 => PC ¬ PC + c127 + 1N = 0 => PC ¬ PC + 1
¾
1 lub 2
BRPL
c127
Skok względny jeśli wartość dodatnia(gdy N=0)
N = 0 => PC ¬ PC + c127 + 1N = 1 => PC ¬ PC + 1
¾
1 lub 2
BRGE
c127
Skok względny jeśli większy lub równy (gdy N albo V=0, dotyczy liczb ze znakiem)
(N Å V)=0 => PC ¬ PC+c127+1(N Å V) = 1 => PC ¬ PC + 1
¾
1 lub 2
BRLT
c127
Skok względny jeśli mniejszy niż zero (gdy N albo V=1, dotyczy liczb ze znakiem)
(N Å V)=1 => PC ¬ PC+c127+1(N Å V) = 0 => PC ¬ PC + 1
¾
1 lub 2
BRHS
c127
Skok względny jeśli flaga przeniesienia pomocniczego ustawiona (gdy H=1)
H = 1 => PC ¬ PC + c127 + 1H = 0 => PC ¬ PC + 1
¾
1 lub 2
BRHC
c127
Skok względny jeśli flaga przeniesienia pomocniczego wyzerowana (gdy H=0)
H = 0 => PC ¬ PC + c127 + 1H = 1 => PC ¬ PC + 1
¾
1 lub 2
BRTS
c127
Skok względny jeśli flaga T ustawiona(gdy T=1)
T = 1 => PC ¬ PC + c127 + 1T = 0 => PC ¬ PC + 1
¾
1 lub 2
BRTC
c127
Skok względny jeśli flaga T wyzerowana(gdy T=0)
T = 0 => PC ¬ PC + c127 + 1T = 1 => PC ¬ PC + 1
¾
1 lub 2
BRVS
c127
Skok względny jeśli flaga przepełnienia jest ustawiona (gdy V=1)
V = 1 => PC ¬ PC + c127 + 1V = 0 => PC ¬ PC + 1
¾
1 lub 2
BRVC
c127
Skok względny jeśli flaga przepełnienia jest wyzerowana (gdy V=0)
V = 0 => PC ¬ PC + c127 + 1V = 1 => PC ¬ PC + 1
¾
1 lub 2
BRIE
c127
Skok względny jeśli przerwanie jest odblokowane (gdy I=1)
I = 1 => PC ¬ PC + c127 + 1I = 0 => PC ¬ PC + 1
¾
1 lub 2
BRID
c127
Skok względny jeśli przerwanie jest zablokowane (gdy I=0)
I = 0 => PC ¬ PC + c127 + 1I = 1 => PC ¬ PC + 1
¾
1 lub 2
Instrukcje przesyłania danych [1][6]
Mnemonika
Operandy
Opis
Operacje
Zmieniane flagi
Liczba cykli
MOV
Rd,Rs
Przepisanie zawartości rejestru Rs do Rd
Rd ¬ Rs
¾
1
MOVW
Rd+1:Rd,Rs+1;Rs
Przepisanie zawartości pary rejestrów Rs i Rs+1 do
pary rejestrów Rd i Rd+1
Rd+1:Rd ¬ Rs+1:Rs
¾
1
LDI
Rd,c255
Ładuj rejestr Rd bezpośrednio wartością stałej z zakresu 0...255
Rd ¬ c255
¾
1
LD
Rd,X
Ładuj rejestr Rd pośrednio daną z pamięci SRAM znajdującą się pod adresem wskazanym przez rejestr indeksowy X
Rd ¬ (X)
¾
2
LD
Rd,X+
Ładuj rejestr Rd pośrednio daną z pamięci SRAM znajdującą się pod adresem wskazanym przez rejestr indeksowy X z postinkrementacją rejestru X
Rd ¬ (X)X ¬ X + 1
¾
2
LD
Rd,-X
Ładuj rejestr Rd pośrednio daną z pamięci SRAM znajdującą się pod adresem wskazanym przez rejestr indeksowy X z predekrementacją rejestru X
X ¬ X - 1Rd ¬ (X)
¾
2
LD
Rd,Y
Ładuj rejestr Rd pośrednio daną z pamięci SRAM znajdującą się pod adresem wskazanym przez rejestr indeksowy Y
Rd ¬ (Y)
¾
2
LD
Rd,Y+
Ładuj rejestr Rd pośrednio daną z pamięci SRAM znajdującą się pod adresem wskazanym przez rejestr indeksowy Y z postinkrementacją rejestru Y
Rd ¬ (Y)Y ¬ Y + 1
¾
2
LD
Rd,-Y
Ładuj rejestr Rd pośrednio daną z pamięci SRAM znajdującą się pod adresem wskazanym przez rejestr indeksowy Y z predekrementacją rejestru Y
Y ¬ Y - 1Rd ¬ (Y)
¾
2
LDD
Rd,Y+c63
Ładuj rejestr Rd pośrednio daną z pamięci SRAM znajdującą się pod adresem wskazanym przez rejestr indeksowy Y z uwzględnieniem przemieszczenia o wartość z zakresu 0...63
Rd ¬ (Y + c63)
¾
2
LD
Rd,Y
Ładuj rejestr Rd pośrednio daną z pamięci SRAM znajdującą się pod adresem wskazanym przez rejestr indeksowy Z
Rd ¬ (Z)
¾
2
LD
Rd,Y+
Ładuj rejestr Rd pośrednio daną z pamięci SRAM znajdującą się pod adresem wskazanym przez rejestr indeksowy Z z postinkrementacją rejestru Z
Rd ¬ (Z)Z ¬ Z + 1
¾
2
LD
Rd,-Z
Ładuj rejestr Rd pośrednio daną z pamięci SRAM znajdującą się pod adresem wskazanym przez rejestr indeksowy Z z predekrementacją rejestru Z
Z ¬ Z - 1Rd ¬ (Z)
¾
2
LDD
Rd,Z+c63
Ładuj rejestr Rd pośrednio daną z pamięci SRAM znajdującą się pod adresem wskazanym przez rejestr indeksowy Z z uwzględnieniem przemieszczenia o wartość z zakresu 0...63
Rd ¬ (Z + c63)
¾
2
LDS
Rd,adr65535
Ładuj rejestr Rd bezpośrednio daną z pamięci SRAM znajdującą się pod adresem wskazanym przez stałą z zakresu 0...65535
Rd ¬ (adr65535)
¾
2
ST
X,Rs
Zachowaj pośrednio zawartość rejestru Rs w pamięci SRAM pod adresem wskazanym przez rejestr indeksowy X
(X) ¬ Rs
¾
2
ST
X+,Rs
Zachowaj pośrednio zawartość rejestru Rs w pamięci SRAM pod adresem wskazanym przez rejestr indeksowy X z postinkrementacją rejestru X
(X) ¬ RsX ¬ X + 1
¾
2
ST
-X,Rs
Zachowaj pośrednio zawartość rejestru Rs w pamięci SRAM pod adresem wskazanym przez rejestr indeksowy X z predekrementacją rejestru X
X ¬ X - 1(X) ¬ Rs
¾
2
ST
Y,Rs
Zachowaj pośrednio zawartość rejestru Rs w pamięci SRAM pod adresem wskazanym przez rejestr indeksowy Y
(Y) ¬ Rs
¾
2
ST
Y+,Rs
Zachowaj pośrednio zawartość rejestru Rs w pamięci SRAM pod adresem wskazanym przez rejestr indeksowy Y z postinkrementacją rejestru Y
(Y) ¬ RsY ¬ Y + 1
¾
2
ST
-Y,Rs
Zachowaj pośrednio zawartość rejestru Rs w pamięci SRAM pod adresem wskazanym przez rejestr indeksowy Y z predekrementacją rejestru Y
Y ¬ Y - 1(Y) ¬ Rs
¾
2
STD
Y+c63,Rs
Zachowaj pośrednio zawartość rejestru Rs w pamięci SRAM pod adresem wskazanym przez rejestr indeksowy Y z uwzględnieniem przemieszczenia o wartość z zakresu 0...63
(Y + c63) ¬ Rs
¾
2
ST
Z,Rs
Zachowaj pośrednio zawartość rejestru Rs w pamięci SRAM pod adresem wskazanym przez rejestr indeksowy Z
(Z) ¬ Rs
¾
2
ST
Z+,Rs
Zachowaj pośrednio zawartość rejestru Rs w pamięci SRAM pod adresem wskazanym przez rejestr indeksowy Z z postinkrementacją rejestru Z
(Z) ¬ RsZ ¬ Z + 1
¾
2
ST
-Z,Rs
Zachowaj pośrednio zawartość rejestru Rs w pamięci SRAM pod adresem wskazanym przez rejestr indeksowy Z z predekrementacją rejestru Z
Z ¬ Z - 1(Z) ¬ Rs
¾
2
STD
Z+c63,Rs
Zachowaj pośrednio zawartość rejestru Rs w pamięci SRAM pod adresem wskazanym przez rejestr indeksowy Z z uwzględnieniem przemieszczenia o wartość z zakresu 0...63
(Z + c63) ¬ Rs
¾
2
STS
adr,Rs
Zachowaj pośrednio zawartość rejestru Rs w pamięci SRAM pod adresem wskazanym przez stałą adr
(adr) ¬ Rs
¾
2
LPM
Ładuj zawartość bajtu z pamięci programu o adresie określonym zawartością rejestru indeksowego Z do rejestru R0
R0 ¬ (Z)
¾
3
LPM
Rd,Z
Ładuj zawartość bajtu z pamięci programu o adresie określonym zawartością rejestru indeksowego Z do rejestru Rd
Rd ¬ (Z)
¾
3
LPM
Rd,Z+
Ładuj zawartość bajtu z pamięci programu o adresie określonym zawartością rejestru indeksowego Z do rejestru Rd z postinkrementacją rejestru Z
Rd ¬ (Z)Z ¬ Z + 1
¾
3
ELPM
Ładuj zawartość bajtu z pamięci programu o adresie określonym zawartością rejestru indeksowego Z i rejestru RAMPZ do rejestru R0
R0 ¬ (RAMPZ:Z)
¾
3
ELPM
Rd,Z
Ładuj zawartość bajtu z pamięci programu o adresie określonym zawartością rejestru indeksowego Z i rejestru RAMPZ do rejestru Rd
Rd ¬ (RAMPZ:Z)
¾
3
ELPM
Rd,Z
Ładuj zawartość bajtu z pamięci programu o adresie określonym zawartością rejestru indeksowego Z i rejestru RAMPZ do rejestru Rd z postinkrementacją rejestrów Z i RAMPZ
Rd ¬ (RAMPZ:Z)Z ¬ Z + 1RAMPZ ¬ RAMPZ + 1
¾
3
SPM
Zapisanie zawartości pary rejestrów R1:R0 do
pamięci programu w miejscu określonym zawartością rejestru indeksowego Z i RAMPZ
(RAMPZ:Z) ¬ R1:R0
¾
-
IN
Rd,P
Przepisanie zawartości rejestru z przestrzeni adresowej I/O o adresie P do rejestru Rd
Rd ¬ P
¾
1
OUT
P,Rs
Przepisanie zawartości rejestru Rs do rejestru z przestrzeni adresowej I/O o adresie P
P ¬ Rs
¾
1
PUSH
Rs
Przepisanie zawartości rejestru Rs na szczyt stosu
(SPL) ¬ RsSPL ¬ SPL - 1lub(SPH:SPL) ¬ RsSPH:SPL ¬ SPH:SPL - 1
¾
2
POP
Rd
Przepisanie zawartości szczytu stosu do rejestru Rd
SPL ¬ SPL + 1Rd ¬ (SPL)lubSPH:SPL ¬ SPH:SPL + 1Rd ¬ (SPH:SPL)
¾
2
Instrukcje operacji bitowych [1][6]
Mnemonika
Operandy
Opis
Operacje
Zmieniane flagi
Liczba cykli
SBI
PL,b
Ustaw bit b w rejestrze we/wy o adresie Pl
Pl(b) ¬ 1
¾
2
CBI
PL,b
Zeruj bit b w rejestrze we/wy o adresie Pl
Pl(b) ¬ 0
¾
2
LSL
Rd
Przesunięcie logiczne w lewo zawartości rejestru Rd
Rd(n+1) ¬ Rd(n)Rd(0) ¬ 0
Z,C,N,V,H
1
LSL
Rd
Przesunięcie logiczne w lewo zawartości rejestru Rd
Rd(n+1) ¬ Rd(n)Rd(0) ¬ 0
Z,C,N,V,H
1
LSR
Rd
Przesunięcie logiczne w prawo zawartości rejestru Rd
Rd(n) ¬ Rd(n+1)Rd(7) ¬ 0
Z,C,N,V
1
To nie wszystko - już wkrótce dalszy ciąg listy rozkazów ...
Literatura:
[1] "Mikrokontrolery AVR w praktyce" - J. Doliński
[2] www.atmel.com - strona producenta mikrokontrolerów AVR
[3] AVR-Assembler-Tutorial - www.avr-asm-tutorial.net by Gerhard Schmidt
[4] materiały od użytkownika forum o nicku "gaweł"
[5] AVRASM.chm - plik pomocy z AVR Studio4
[6] "Mikrokontrolery rodziny AVR - AT90S2313" - A. Krysiak
UWAGA: Wszystkie umieszczone schematy, informacje i przykłady mają służyć tylko do własnych celów edukacyjnych i nie należy ich wykorzystywać do żadnych konkretnych zastosowań bez przeprowadzenia własnych prób i doświadczeń, gdyż nie udzielam żadnych gwarancji, że podane informacje są całkowicie wolne od błędów i nie biorę odpowiedzialności za ewentualne szkody wynikające z zastosowania podanych informacji, schematów i przykładów.Wszystkie nazwy handlowe, nazwy produktów oraz znaki towarowe umieszczone na tej stronie są zastrzeżone dla ich właścicieli.Używanie ich tutaj nie powinno być uważane za naruszenie praw właściciela, jest tylko potwierdzeniem ich dobrej jakości.
All trademarks mentioned herein belong to their respective owners.They aren't intended to infringe on ownership but only to confirm a good quality.
Strona wygląda równie dobrze w rozdzielczości 1024x768, jak i 800x600.
Optymalizowana była pod IE dlatego polecam przeglądanie jej w IE5.5 lub nowszych przy rozdzielczości 1024x768.
© Copyright 2001-2005 Elektronika analogowa
_uacct = "UA-1314346-1";
urchinTracker();
Wyszukiwarka
Podobne podstrony:
asm avrJezyk C dla mikrokontrolerow AVR Od podstaw do zaawansowanych aplikacji jcmikrJezyk C dla mikrokontrolerow AVR Od podstaw do zaawansowanych aplikacji jcmikrJĘZYK SZTUKI OBRAZ JAKO KOMUNIKATJezyk angielski arkusz I poziom podstawowy (5)Język niemiecki dwujęzyczna arkusz IIJęzyk angielski Owoce2015 matura JĘZYK NIEMIECKI poziom rozszerzony TESTjezyk ukrainski lekcja 03więcej podobnych podstron