AVR Asembler. Opis architektury AT90S8515.

AVR Asembler. Opis architektury AT90S8515.

Pierwszy rzut oka na instrukcję programowania mikrokontrolera z rodziny AVR w języku asembler nieco przeraża. Dziesiątki zupełnie niezrozumiałych poleceń to dla wielu przeszkoda nie do przebycia. Niestety – taki jest urok programowania w asemblerze. Tutaj proste z pozoru operacje dodawania czy mnożenia muszą zawierać się w kilku czy kilkunastu poleceniach. Cykl artykułów będzie próbą wprowadzenia Czytelnika w świat programowania w języku asemblera AVR. Będzie też próbą pokazania, że nie taki diabeł straszny...

Jak zacząć?

Programowanie w języku asembler wymaga od programisty dogłębnej znajomości środowiska: nie tylko zasobów wewnętrznych używanego mikrokontrolera lecz również jego otoczenia ze szczególnym uwzględnieniem dołączonych elementów zewnętrznych. Wszystkie elementy architektury mikrokontrolera, których istnienia nie zawsze jest świadomy programista piszący aplikację w języku wysokiego poziomu (C, Bascom itp.), muszą być doskonale znane programiście używającemu asemblera. Ten pierwszy nie musi dla przykładu wiedzieć, że w wyniku odejmowania dwóch liczb może być ustawiany znacznik przeniesienia: zwalnia go od tego kompilator.
Aplikacje tworzone w asemblerze wymagają przeciętnie około 2 razy więcej czasu na napisanie oraz kilka razy więcej czasu na usunięcie błędów, aniżeli równoważne im programy pisane w językach wysokiego poziomu. Zwłaszcza ten drugi aspekt jest bardzo często pomijany w dyskusjach przez programistów. A co w zamian? Dobrze napisany program w asemblerze zajmuje tylko tyle miejsca w pamięci ile jest niezbędne na realizację danych funkcji sterowania czy kontroli. W związku z tym dobry programista może stworzyć maksymalnie efektywną aplikację, działającą szybko i niezawodnie. Nie bez znaczenia jest również fakt, że większość kompilatorów asemblera przeznaczonych dla mikrokontrolerów jest udostępniana przez producentów mikrokontrolerów za darmo. Coś za coś – czas niezbędny na stworzenie aplikacji i jej uruchomienie w zamian za szybkość i efektywność wykorzystania zasobów mikrokontrolera. Obserwując trendy na rynkach narzędzi dla programistów stwierdzam, że ten pierwszy czynnik przeważa. Przemawia za nim wzrost szybkości mikrokontrolerów oraz rozmiarów ich pamięci a także efektywności narzędzi i łatwość ich stosowania. Mimo wszystko uważam, że warto znać asembler.

Budowa mikrokontrolera z serii AVR: AT90S8515.

Moim zdaniem najbardziej typowym reprezentantem rodziny AVR jest – niestety wycofywanym już z produkcji i zastępowanym przez ATMega8535 – mikrokontroler AT90S8515. Elementy jego architektury odnaleźć możemy zarówno w maleńkich ATTiny jak i w bogatszych w zasoby ATMega. Przyjrzyjmy się jego zasobom wewnętrznym, rejestrom i wskaźnikom, portom wejścia / wyjścia, sposobom w jaki można ich użyć we własnej aplikacji.

Wewnętrzne zasoby mikrokontrolera.

AT90S8515 zbudowany jest w oparciu o architekturę Harvard. Oznacza to, że poszczególne przestrzenie adresowe pokrywają się a rodzaj pamięci (RAM, ROM itp.) rozróżniany jest przez sygnały pochodzące z dekodera. Niektóre z tych sygnałów wyprowadzone są na zewnątrz (magistrala adresowa, ALE, RD, WR) umożliwiając identyfikację sytuacji, w której aplikacja żąda dostępu do zasobów zewnętrznych. Mikrokontroler posiada wbudowane w strukturę ma 8kB pamięci FLASH przeznaczonych aplikację użytkownika. W praktyce programów tworzonych w asemblerze to bardzo dużo. Pamięć programu może być zapisywana nie tylko z wykorzystaniem programatora równoległego ale również przez interfejs SPI. Dodatkowo producent wyposażył ten mikrokontroler w 512 bajtów pamięci FLASH wykonanej w innej, droższej technologii, z przeznaczeniem na dane użytkownika (np. nastawy). Pamięć ta dostępna jest z poziomu aplikacji po ustawieniu bitów w rejestrach kontrolnych. Metodami zapisu i odczytu tejże zajmiemy się w dalszej części kursu.  AT90S8515 wyposażony jest w 608 bajtów pamięci RAM. W obszarze tym znajdują się rejestry robocze i stos mikrokontrolera (zajmują one łącznie 96 bajtów pozostawiając do dyspozycji 512 bajtów), tam też definiować będziemy większość zmiennych wykorzystywanych przez naszą aplikację.
Wewnętrzna pamięć RAM jest podzielona na pewne specyficzne obszary (rysunek 1). Od adresu 0 do 1FH (32 dziesiętnie) znajduje się obszar przeznaczony na rejestry robocze lub inaczej – rejestry ogólnego przeznaczenia – o oznaczeniu od R0 do R31. Prawie wszystkie rozkazy asemblera umożliwiają wykonywanie na nich operacji arytmetyczno – logicznych. Wyjątkiem są SBCI, SUBI, CPI, ANDI, ORI oraz LDI z argumentem bezpośrednim, wykorzystujące R16..R31. Za wyjątkiem opisywanej sytuacji, pomiędzy rejestrami ogólnego przeznaczenia, nie ma różnic. Wynika z tego fakt braku jednego, wyróżnionego (jak w architekturze ST6 czy MCS51-52) akumulatora. Przyznam, że jest to bardzo wygodne dla programisty.

pamiec

Rys. 1. Organizacja pamięci AT90S8515

Powyżej rejestrów roboczych, umieszczony jest obszar rejestrów wejścia / wyjścia (I/O Registers). Są to 64 bajty (od 20H do 5FH) związane z obsługą urządzeń peryferyjnych wbudowanych w strukturę mikrokontrolera. Dostęp do tej przestrzeni zarezerwowany jest dla rozkazów IN oraz OUT. Polecenia te nie używają argumentów bezpośrednich. Będzie to dobrze widoczne w przytoczonym dalej przykładzie programowania. Od adresu 60H do 25F (907 dziesiętnie) rozciąga się obszar pamięci RAM ogólnego zastosowania. Może nie jest to zbyt dobre określenie, ale jest to obszar, w którym lokować można adresowane pośrednio zmienne (z wykorzystaniem rejestrów indeksowych) oraz stos programowy mikrokontrolera.  Pamięć RAM może być w prosty sposób rozszerzona przez dołączenie zewnętrznych układów pamięci. Obszar dołączonej z zewnątrz pamięci RAM „dodaje się” wówczas do wewnętrznej i stanowi ciągły blok. Ze względu na ograniczenie magistrali adresowej, do AT90S8515 można dołączyć maksymalnie 64kB pamięci statycznej RAM.
Wyposażenie w dodatkowe urządzenia sprzętowe nie jest zbyt imponujące. W strukturze znajdziemy 8- i 16-bitowy układ odmierzania czasu (timer) o licznych trybach pracy. Zajmiemy się nimi szczegółowo w dalszej części kursu, jako że są to układy ze wszech miar bardzo użyteczne. Każdy z układów odmierzania czasu posiada własny, programowalny dzielnik częstotliwości zegarowej tu traktowanej jako wzorcowa. W strukturze AT90S8515 znajduje się również komparator analogowy umożliwiający porównywanie dwóch napięć i przez to budowę wielu pożytecznych układów, interfejsy szeregowe UART i SPI służące do komunikacji z otoczeniem, układ Watchdog pomocny, gdy aplikacja z jakiś powodów przestaje działać poprawnie oraz generator zegarowy.
Większość rozkazów wykonywana jest w czasie pojedynczego cyklu zegara. Oznacza to w praktyce, że w przypadku użycia rezonatora kwarcowego 8MHz, AT90S8515 wykonuje 8 milionów poleceń w ciągu 1 sekundy (8 MIPS). Czy oznacza to, że jest to mikrokontroler szybszy od typowego reprezentanta z rodziny MCS51? I tu zdania pomiędzy programistami są bardzo podzielone. Mikrokontrolery AVR używają zredukowanej listy rozkazów. W praktyce oznacza to, że czasami trzeba użyć kilku rozkazów w miejsce pojedynczego wykonywanego przez 8x51. Nie chciałbym w tym miejscu wywoływać jakiejś polemiki, zostawmy spory teoretykom dobierając odpowiedni mikrokontroler do aplikacji a nie odwrotnie.

Porty wejścia / wyjścia.

AT90S8515 ma cztery 8-bitowe, dwukierunkowe porty, co oznacza 32 linie wejścia wyjścia. Porty te oznaczane są literami od A do D (PORTA, PORTB, PORTC, PORTD). Każda z linii portu może być programowana indywidualnie, to znaczy dla każdej z nich można ustalić odrębnie tryb pracy jako wejściowa, wyjściowa z dołączonym lub odłączonym rezystorem zasilającym (z angielskiego: pull-up). Steruje tym rejestr kierunku oznaczany jako DDRx (Data Direction Register), gdzie literce „x” odpowiada A, B, C lub D w zależności od ustawianego portu. Rejestr PORTx ustawia stan wyjściowy bitu, natomiast do odczytu służy rejestr PINx. Nieco to skomplikowane – podsumujmy więc:
- rejestr kierunku sterujący załączaniem wewnętrznych rezystorów pull-up: DDRx,
- rejestr wyjściowy sterujący ustawianiem stanu wyjściowego portu: PORTx,
- PINx nie jest rejestrem a rodzajem bufora umożliwiającego aplikacji dostęp do fizycznego stanu doprowadzenia PORTx.
Jak więc widać z powyższego wykazu, na tryb pracy linii portu wejścia / wyjścia w głównej mierze będą wpływać wartości wpisane do PORTx i DDRx.
Tyle słowem krótkiego wstępu. Oczywiście wąskie ramy artykułu nie pozwalają na wyczerpanie wszystkich aspektów architektury. Wszystkim zainteresowanym rozszerzeniem swojej wiedzy polecam znakomitą książkę Jarosława Dolińskiego „Mikrokontrolery AVR w praktyce”.

Zawartość DDRx

Zawartość PORTx

Tryb pracy

Rezystor zasilający

Uwagi

0

0

Jako wejście

X

Stan wysokiej impedancji

0

1

Jako wejście

Tak

Odpowiada dołączeniu rezystora pull-up ale zewnętrzne zwarcie linii do „0” logicznego spowoduje przepływ prądu

1

0

Jako wyjście

X

Wyprowadzenie stanu „0”

1

1

Jako wyjście

X

Wyprowadzenie stanu „1”

Tab. 1. Wpływ nastaw rejestrów konfiguracji portów wejścia – wyjścia.

 

Zanim przystąpimy do pracy

Zanim zacznę omawiać konkretne przykłady aplikacji AVR, chcę udzielić jeszcze kilku wskazówek. Każdorazowo przy zmianie środowiska czy języka programowania zachodzi konieczność nauczenia się pewnych nowych umiejętności oraz przyswojenia sobie nowej wiedzy. Przy jednoczesnym pożądaniu szybkiego efektu, może to doprowadzić do frustracji. Jak najprościej i najszybciej nauczyć się pisać programy dla AVR?
Jedną z możliwych metod jest czytanie wszelkich materiałów na ten temat: danych mikrokontrolerów ze strony producenta, różnego rodzaju opracowań i książek, listy rozkazów i tym podobnych. Osobiście jednak wielokrotnie uczyłem się nowych języków programowania sprawdzoną nie tylko przeze mnie metodą: wyszukiwałem jak najwięcej pracujących i sprawdzonych programów napisanych w języku, którego chciałem się nauczyć – bardzo pomocni w tej sytuacji byli ludzie, którzy już posiadali umiejętności, których ja dopiero chciałem się nauczyć, „studiowałem” zdobyte programy próbując zrozumieć jak działają i jak skonfigurowany jest mikrokontroler w konkretnej aplikacji, uruchamiałem program na płytce testowej, wprowadzałem modyfikacje, sprawdzałem jak działają – stąd już tylko krok do samodzielnie napisanych programów.
Uważam dokumentację ze stron internetowych producentów za bardzo cenne źródło informacji, jednak gdy mam na przykład na ekranie lub w rękach dokument PDF na temat mikrokontrolera ATMega128 liczący około 350 stron, to ogarnia mnie uczucie lekkiego przerażenia. Nie dosyć, że wydrukowanie go mojej starej drukarce laserowej zajmuje mnóstwo czasu, to na przestudiowanie będę musiał poświęcić około 2 tygodni. I tak za każdym razem? Nauczyłem się być mądrzejszym i oszczędzać swój czas. Tak naprawdę nie są mi przecież potrzebne szczegółowe informacje jak działa osobno każdy z bitów urządzeń, których pewnie nie użyję, jaka jest gama obudów itp. Poszukuję więc grup informacji zawierających istotne dla mnie parametry:
- pierwszej strony zawierająca skrócony opis opcji,
- strony zawierającej szkic obudowy oraz opis wyprowadzeń,
- początkowych najczęściej stron dokumentu zawierających opis architektury,
- opisu funkcjonowania przerwań,
- opisu sposobu podziału i funkcjonowania pamięci,
- opisu sposobu dołączenia układów zewnętrznych,
- opisu rejestrów sterujących mikrokontrolera,
- opisu zestawu rozkazów asemblera (pamiętajmy, że poszczególne modele AVR różnią się pomiędzy sobą ilością poleceń asemblera),
Do reszty tekstu zaglądam rzadko lub prawie wcale. Przeważnie odwołuję się do niego już w momencie implementacji konkretnej funkcji obsługującej na przykład przetwornik A/D czy korzystającej ze specyficznego układu peryferyjnego, w który wyposażony jest mikrokontroler.
Dodatkowymi materiałami niezbędnymi dla potrzeb kursu są:
- AvrStudio (do pobrania ze strony http://www.atmel.com/),
- dokumentacja mikrokontrolera AT90S8515 (http://www.atmel.com/atmel/acrobat/0841s.pdf)
- lista rozkazów mikrokontrolerów AVR (http://www.atmel.com/atmel/acrobat/doc0856.pdf)

Przykład programowania: kopiowanie stanu z wejścia na wyjście

Poniższy przykład programowania zawierać będzie odczyt stanu linii wejściowej PORTA.0 i przepisanie go na pracującą jako wyjściowa linię PORTA.1. W układzie testowym dołączyłem przycisk do wyprowadzenia PORTA.0 oraz do PORTA.1 katodę diody LED, której anoda połączona jest z +5V przez rezystor 470Ω. Na listingu 1 pokazano przykład implementacji rozwiązania problemu.
Początek programu zawiera dołączenie definicji rejestrów mikrokontrolera AT90S8515. W ten sposób będzie się zaczynał niemalże każdy z prezentowanych tu przykładów programów. Jako następna pojawia się definicja zmiennej o nazwie temp. Jest to przyporządkowanie rejestrowi R16 nazwy temp. Od tego momentu wszystkie odwołania do temp są równoważne operacjom wykonywanym na R16. Przyporządkowanie nazwy wprowadzone jest tutaj wyłącznie dla zwiększenia przejrzystości aplikacji. Na zmienną temp wybrałem rejestr R16, ponieważ można na nim wykonać wszystkie operacje arytmetyczno – logiczne (od R16 do R32).
Dalej na listingu umieszczona jest tablica wektorów przerwań. Jej początek to adres 0H. Jest on stały i nie może ulegać zmianie. Moim zdaniem, do dobrego stylu programowania należy, aby za każdym razem, bez względu na ilość wykorzystywanych fizycznie przerwań, znajdowała się ona w programie w całości. Nie tylko czyni to aplikację bardziej czytelną ale również pozwala uniknąć pomyłek związanych z zamianą (przestawieniem) pozycji w tabeli. Rzadko w praktyce zdarza się sytuacja, aby tablica wektorów przerwań nie mieściła się w całości w pamięci programu.
CPU mikrokontrolera otrzymując sygnał przerwania wykonuje rozkaz znajdujący się w pamięci programu odpowiadający adresem danemu źródłu przerwania. Czyli sygnał RESET zawsze spowoduje wykonanie rozkazu znajdującego się pod adresem 0, zewnętrzne przerwanie INT0 zawsze wywoła rozkaz spod adresu 2 i tak dalej. Tak więc położenia wektorów wskazań do funkcji obsługi w tabeli przerwań są ściśle ustalone i muszą się znajdować zawsze na tej samej pozycji. Wynika z tego fakt, że offset pomiędzy nimi również jest ustalony i wynosi 2 bajty. W związku z tym, że rozmiar rozkazu rjmp czy reti to również 2 bajty, umieszczenie pojedynczego rozkazu na pozycji wektora jest wystarczające do ustalenia właściwego offsetu. Również z tego faktu wynika ograniczenie, że rozmiar wektora wskazania nie może przekraczać 2 bajtów. Pamiętajmy: tablica wektorów przerwań musi być umieszczona w aplikacji od adresu 0H!

 

List. 1. Przykład aplikacji kopiującej stan PA.0 na PA1

;Kopiowanie stanu wejścia PORTA.0 na wyjście PORTA.1
.include "8515def.inc"
.def      temp = R16
;---------------------------------------------
;wektory obsługi przerwań
;---------------------------------------------
    rjmp    RESET             ;po Reset
    reti                      ;External Interrupt 0
    reti                      ;External Interrupt 1
    reti                      ;T/C1 Capture Event
    reti                      ;T/C1 Compare Match A
    reti                      ;T/C1 Compare Match B
    reti                      ;T/C1 Overflow
    reti                      ;T/C0 Overflow
    reti                      ;SPI Transfer Complete
    reti                      ;UART Rx Complete
    reti                      ;UART Data Register Empty
    reti                      ;UART Tx Complete
    reti                      ;Analog Comparator

;---------------------------------------------
;program główny
;---------------------------------------------
RESET:

    ldi    temp,low(RAMEND)   ;ustawienie wskaźnika stosu
    out    SPL,temp
    ldi    temp,high(RAMEND)
    out    SPH,temp
    ldi    temp,2             ;wszystkie linie jako wejściowe
    out    DDRA,temp          ;oprócz bitu 1 pracującego jako wyjście
loop:
    in     temp,PINA          ;odczyt stanu wyprowadzeń portu A
    lsl    temp               ;przesunięcie w lewo o 1 bit
    andi   temp,2             ;maskowanie bitów linii wejściowych
    out    PORTA,temp         ;wyprowadzenie odczytanej wartości
    rjmp   loop               ;skok do funkcji testowania

Program główny zaczyna się od etykiety RESET. Początek, to ustawienie adresu stosu, które w tym przypadku może nie jest konieczne, ponieważ nie są używane żadne rozkazy wywołań podprogramów, ale należy do dobrego nawyku programowania. Nasz program nie używa stosu, więc nastawa wykonywana jest tylko pro forma. 2-bajtowy rejestr SP znajduje się w obszarze pamięci I/O. W związku z tym dostęp do niego możliwy jest wyłącznie z wykorzystaniem rozkazów OUT (zapis do rejestru) oraz IN (odczyt rejestru). Na liście rozkazów AT90S8515 brak jest poleceń przesyłających bezpośrednio liczbę do lokalizacji I/O. Konieczne jest wykorzystanie „pośrednika”. W tym przypadku rolę tą pełni zmienna temp (rejestr r16). Wartość stała najpierw zapisywana jest do zmiennej a dopiero ta przesyłana jest do lokalizacji I/O. Wartość RAMEND jest predefiniowana w zbiorze „8515def.inc”. Jest to najwyższy adres w pamięci RAM mikrokontrolera (stała ma wartość 607 dziesiętnie). Od niej to „w dół” układany jest stos. Każdy rozkaz CALL czy też PUSH powoduje zmniejszenie wskaźnika stosu (rejestr SP) o liczbę zapamiętywanych na nim bajtów. Rozkaz CALL może więc pomniejszyć wskaźnik stosu o 2 lub 3, pojedynczy rozkaz PUSH o 1. Odwrotnie działają rozkazy (odpowiednio) RET oraz POP zwiększając wskaźnik SP. Również rejestry DDRA, PINA i PORTA znajdują się w obszarze rejestrów I/O. Dostęp do nich odbywa się identycznie jak do rejestru wskaźnika stosu SP z wykorzystaniem rejestru pośredniczącego.
Za wyjątkiem bitu numer 1, cały port ustawiany jest jako wejściowy. Do wyprowadzenia PORTA.1 dołączona jest dioda LED, więc ten pracuje jako wyjściowy. Pojedynczy rozkaz zapisujący DDRA (zgodnie z tabelą 1) ustawia kierunek pracy portu. Od etykiety loop rozpoczyna się sekwencja testująca wejście. Polecenie in temp,PINA odczytuje stan portu A i zapamiętuje go w zmiennej temp. Następnie zmienna ta przesuwana jest w lewo o 1 pozycję oraz wykonywane jest zerowanie (maskowanie) bitów o numerach 0 oraz 2 do 7, aby następny rozkaz zapisujący zmienną temp do rejestru danych PORTA zmienił stan linii wyjściowej (bitu numer 1). Rozkaz skoku bezwarunkowego rjmp powoduje powrót do początku sekwencji testującej i przez to powtórne wykonanie programu.

Konfiguracja przerwań w mikrokontrolerze AT90S8515

Przerwania to funkcja kontrolna zaimplementowana w większości znanych mikrokontrolerów. W aplikacji, w której jednostka centralna prowadzi interakcję z otoczeniem, wiele zjawisk zachodzi w tym samym czasie bądź też w niewielkich jego odstępach. Są to najczęściej zjawiska nie zsynchronizowane i nie powiązane ze sobą, aczkolwiek mogą być zależne.  Na przykład: użytkownik nacisnął klawisz, interfejs UART odebrał kompletne słowo danych, została pobrana próbka przez przetwornik analogowo – cyfrowy oraz inne. Jednostka centralna zamiast angażować czas w odpytywanie urządzeń czy potrzebują one obsługi, czy też nie, może wbudowany mechanizm umożliwiający urządzeniom peryferyjnym sygnalizację konieczności obsługi. Mechanizm ten nosi nazwę „przerwań” jako, że urządzenie zewnętrzne przerywa bieżące zadanie realizowane przez CPU żądając obsługi. Po jej wykonaniu, normalna praca aplikacji może być kontynuowana.
W mikrokontrolerze AT90S8515 źródłami przerwań mogą być urządzenia wbudowane w jego strukturę: układy timerów, przetwornik analogowo – cyfrowy, sprzętowe interfejsy UART i SPI. Przerwania mogą być również generowane przez urządzenia zewnętrzne. Do zgłoszenia żądania przez nie obsługi, służą dwa wejścia oznaczone jako INT0 i INT1 (bity 2 i 3 portu D). W tym przykładzie programowania zajmę się przerwaniem zewnętrznym pochodzącym z wejścia INT0. Zagadnienia związane z wykorzystaniem przerwania od INT0 we własnej aplikacji podzielić można na 4 podstawowe tematy:
- właściwe umieszczenie wektora wskazującego do obsługi przerwania w tablicy wektorów przerwań,
- właściwe ustawienie bitów kontrolnych sterujących akceptacją obsługi przerwań w rejestrze GIMSK,
- dokonanie właściwych nastaw w rejestrze MCUCR sterującym „wrażliwością” wejść przerwań zewnętrznych,
- ustawienie bitu zezwalającego na globalną obsługę przerwań w rejestrze SREG.
Przejdźmy do konkretnego przykładu aplikacji.

Przykład programowania: budowa licznika binarnego

W kolejnym przykładzie wyjaśnię w jaki sposób funkcjonują przerwania oraz zbuduję licznik binarny z wykorzystaniem przerwania zewnętrznego pochodzącego od wejścia INT0. Dodatkowo informacja o stanie licznika zostanie wyprowadzona w postaci 8 bitowej zmiennej na dołączone do portu A diody LED (jak poprzednio przez rezystor 470Ω włączony pomiędzy diodę a +5V).
Na listingu 2 przedstawiono przykład implementacji realizacji licznika binarnego. Początek programu to dobrze znane z poprzedniego przykładu dołączenie definicji rejestrów mikrokontrolera oraz definicja wektorów przerwań. Nowością jest dyrektywa .org upewniająca, że nic nie znajdzie się przed tablicą wektorów przerwań. Dyrektywa ta służy do umieszczenie części kodu pod konkretnym, podanym jako argument, adresem w pamięci programu. W tablicy wektorów przerwań oprócz wskazania do programu wykonywanego po sygnale reset, znajduje się również wskazanie do funkcji obsługi przerwania po sygnale INT0.
Za tablicą od etykiety RESET rozpoczyna się program główny. Tak, jak poprzednio – od inicjalizacji stosu. W tym programie jest ona niezbędna aby aplikacja umiała „odnaleźć się” wracając z funkcji obsługi przerwania. Dalej w rejestrze GIMSK zostaje ustawiona wartość pozwalająca na akceptację zewnętrznego przerwania od INT0. Nastawy MCUCR powodują (patrz dokumentacja mikrokontrolera), że przerwanie zgłaszane jest przy opadającym zboczu sygnału. To, co jeszcze pozostało do zrobienia, to ustawienie trybu pracy portu D jako wejściowy z załączonymi rezystorami zasilającymi (pull-up), portu A jako wyjściowy. Nie wykorzystujemy pozostałych bitów, więc operacje wykonywane są globalnie, dla całego portu. Upraszcza to program i ułatwia jego opis.
Polecenie sei ustawia bit 7 w rejestrze SREG umożliwiając tym samym przyjmowanie przerwań. Od tego momentu zaczyna się pętla programu, w której stan zmiennej temp, która przyjęła rolę licznika, wyprowadzany jest na zewnątrz sterując stanem diod LED dołączonych do portu A. Dioda zapalona oznacza stan niski, zgaszona stan wysoki.
Funkcja obsługi przerwania jest bardzo krótka. Zawiera praktycznie 2 polecenia. Pierwsze z nich zwiększa stan zmiennej temp, drugi powoduje powrót o wywołania (reti).

 

List. 2. Realizacja licznika binarnego zliczającego impulsy na INT0

;Licznik binarny
.include "8515def.inc"
.def      temp = R16
.org      0
;---------------------------------------------
;wektory obsługi przerwań
;---------------------------------------------
    rjmp    RESET             ;po Reset
    rjmp    IRQ_Int0          ;External Interrupt 0
    reti                      ;External Interrupt 1
    reti                      ;T/C1 Capture Event
    reti                      ;T/C1 Compare Match A
    reti                      ;T/C1 Compare Match B
    reti                      ;T/C1 Overflow
    reti                      ;T/C0 Overflow
    reti                      ;SPI Transfer Complete
    reti                      ;UART Rx Complete
    reti                      ;UART Data Register Empty
    reti                      ;UART Tx Complete
    reti                      ;Analog Comparator

;---------------------------------------------
;program główny
;---------------------------------------------
RESET:
    ldi    temp,low(RAMEND)   ;ustawienie wskaźnika stosu
    out    SPL,temp
    ldi    temp,high(RAMEND)
    out    SPH,temp
;konfiguracja reakcji na przerwanie
    ldi    temp,(1<<INT0)     ;ustawienie bitu odpowiedzialnego za akceptcję
    out    GIMSK,temp         ;przerwania INT0 w rejestrze GIMSK
;nastawa "wrażliwości" przerwania
    ldi    temp,$03           ;opadające zbocze na INT0 będzie generować
    out    MCUCR,temp         ;przerwanie
;konfiguracja portu D
    ldi    temp,0             ;w tym przykładzie wszystkie linie portu D
    out    DDRD,temp          ;pracują jako wejściowe
    ser    temp               ;teraz do linii portu D dołączamy rezystory
    out    PORTD,temp         ;zasilające pull-up (wewnętrzne)
;konfiguracja portu A
    out    DDRA,temp          ;port A jako wyjściowy (temp zawiera $FF)
    out    PORTA,temp         ;wyprowadzenie stanu wysokiego
;temp będzie licznikiem
    ldi    temp,0
    sei                       ;zezwolenie na przyjmowanie przerwań
;główna pętla programu
loop:

    out    PORTA,temp         ;wyprowadzenie zmiennej temp przez port A
    rjmp   loop               ;program główny "kręci się" w pętli i oczekuje
                              ;na przerwania od INT0
;---------------------------------------------
;obsługa przerwania od INT0
;---------------------------------------------
IRQ_Int0:
    inc    temp               ;zwiększenie wartości temp o 1
    reti                      ;powrót z obsługi przerwania

 

Jacek Bogusz
jacek.bogusz@easy-soft.net.pl

http://www.tomaszbogusz.blox.pl/

Odpowiedzi

AVR Asembler. Opis architektury AT90S8515. @ easy-soft |

Thanks for one's marvelous posting! I definitely enjoyed reading
it, you're a great author.I will be sure to bookmark your blog
and definitely will come back from now on. I want to encourage you to definitely continue your great job, have a nice evening!

AVR Asembler. Opis architektury AT90S8515. @ easy-soft |

Hi there I am so excited I found your blog, I really found
you by accident, while I was looking onn Aol for something else, Nonetheless
I am here now annd would just like to say thanks a lot for a tremendous
post and a all round interesting blog (I also love the theme/design), I
don't have time to look over it all at thhe minute but I have book-marked it and also included your RSS feeds, so when I have time I will
be back to read a lot more, Please do keep up the excellent work.

avr

Potrzebuje pomocy mikrokontroler AVR ATMEGA 128 program ma kopiować zawartość pamięci ROM do RAM w assemblerze i mówi mi wykładowca że na necie jest wszystko żle. Nie miałem kursu wprowadzającego. Nie wiem jak zainicjalizować rejestr x,y,z itd..

AVR Asembler. Opis architektury AT90S8515. @ easy-soft |

I just done mine and that i was seeking for a few design suggestions and
you afflicted me with a few.

AVR Asembler. Opis architektury AT90S8515. @ easy-soft |

Woah! I'm really loving the template/theme oof this site.
It's simple, yet effective. A lot of times it's
hard to get that "perfect balance" between user friendliness and visual appeal.
I must say that you've done a great job with this.

Additionally, thee blog loads super quick for me on Internet
explorer. Superb Blog!

AVR Asembler. Opis architektury AT90S8515. @ easy-soft |

I am actually happy to read this weblog posts which consists of
tons of useful data, thanks for providing such statistics.

AVR Asembler. Opis architektury AT90S8515. @ easy-soft |

I every time spent my half an hour to read this web site's
articles all the time along with a cup of coffee.

AVR Asembler. Opis architektury AT90S8515. @ easy-soft |

I every time spent my half an hour to read this web site's articles all the time
along with a cup of coffee.

AVR Asembler. Opis architektury AT90S8515. @ easy-soft |

Hi there I am so excited I found your blog, I really found you
by accident, while I was looking on Aol for something else, Nonetheless I am here
now and would just like to say thanks a lot for a tremendous posat and a all round interesting blog (I also love the theme/design),
I don't have time to look over it all at the minute but I have book-marked it and also included your
RSS feeds, so when I have time I will be back tto
read a lot more, Please do keep up the excellent work.

AVR Asembler. Opis architektury AT90S8515. @ easy-soft |

I read this article completely concerning the difference of newest and earlier technologies, it's remarkable article.

Dodaj nowy komentarz

Zawartość pola nie będzie udostępniana publicznie.