asm avr jezyk


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 avr
Jezyk C dla mikrokontrolerow AVR Od podstaw do zaawansowanych aplikacji jcmikr
Jezyk C dla mikrokontrolerow AVR Od podstaw do zaawansowanych aplikacji jcmikr
JĘZYK SZTUKI OBRAZ JAKO KOMUNIKAT
Jezyk angielski arkusz I poziom podstawowy (5)
Język niemiecki dwujęzyczna arkusz II
Język angielski Owoce
2015 matura JĘZYK NIEMIECKI poziom rozszerzony TEST
jezyk ukrainski lekcja 03

więcej podobnych podstron