Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Atmega8 Przerwanie z T0 [asembler]

Tymsal 25 Wrz 2005 09:37 2705 8
  • #1 25 Wrz 2005 09:37
    Tymsal
    Poziom 11  

    Chciałbym wykorzystać przerwanie z licznika T0 lub T1 do cyklicznej zmiany stanu diody LED. Posiadam przykład z strony http://www.avrbeginners.net/ o obsłudze przerwania z licznika T1. Moja prośba jest taka by ktoś opisał mi co poszczególne komendy wykonują i całościowy opis programu.

    Code:

    .org 0x0000
    rjmp reset
    .org 0x0005
    rjmp led_off
     
    reset:
    ldi r16, low(RAMEND)
    out SPL, r16
     
    ldi r16, high(0xF0BE)
    out TCNT1H, r16
    ldi r16, low(0xF0BE)
    out TCNT1L, r16
     
    ldi r16, 0b00000101
    out TCCR1B, r16
     
    ldi r16, 0b10000000
    out TIMSK, r16
    sei
     
    sbi DDRB, 4
    cbi PortB, 4
     
    loop:
    rjmp loop
     
    led_off:
    push r16
    in r16, SREG
    push r16
     
    ldi r16, 0
    out TCCR1B, r16
    sbi PortB, 4
     
    pop r16
    out SREG, r16
    pop r16
    reti

    Dziękuję

    0 8
  • Pomocny post
    #2 25 Wrz 2005 12:30
    Dexter77
    Poziom 28  

    Ale o co konkretnie Ci chodzi ?? Wogole nie wiesz co robia instrukcje czy jak ? Co do programu to jest malo przejrzyscie napisany. Jesli to jest kurs dla poczatkujacych to proponuje poszukac innego. Sam patrzac na to cos z poczatku zglupialem i musialem sie wgapic zeby zrozumiec o co chodzi.
    Do meritum:
    Na poczatku sa sa dwie dyrektywy org ktore mowia od ktorego miejsca w pamieci kompilator ma umiescic nastepne instrukcje. Pierwsze kilkanascie bajtow pamieci programu w procesorach jest przeznaczone na TABLICE WEKTOROW PRZERWAN. Tutaj wykorzystane jest tylko jedno przerwanie od licznika. Jest tez standardowy wektor pod adresem 0x0000 pod ktory procesor skacze gdy nastapi reset. Pod tym adresem jest skok do etykiety reset. Pierwsze wlasnie co robi procesor to tam skacze (instrukja rjmp). Tu nastepuje inicjalizacja stosu (2 instrukcje) oraz konfiguracja timera, zreszta bledna. Gosciu wlaczyl preskaler i globalne przerwania ale nie wlaczyl zadnego przerwania od timera. nie no nie mo co sie wzorowac na tym przykladzie bo jest do d..... albo to wogole nie jest na Atmege8
    Pozdro
    Dexter

    0
  • Pomocny post
    #3 25 Wrz 2005 13:14
    GienekS
    Poziom 32  

    Code:
    .org 0x0000 
    
    rjmp reset           ;skok do początku programu
    .org 0x0005
    rjmp led_off        ;wyskok z wektora 5 do procedury obsługi
     
    reset:
    ldi r16, low(RAMEND)
    out SPL, r16         ;ustawienie wskaźnika stosu
     
    ldi r16, high(0xF0BE)
    out TCNT1H, r16   ;ustawienie wartosci H timera T1
    ldi r16, low(0xF0BE)
    out TCNT1L, r16   ;ustawienie wartosci L timera T1
     
    ldi r16, 0b00000101
    out TCCR1B, r16  ;nie pamiętam, musidz spojżeć do pdf-a ATMEGI co te bity robią
     
    ldi r16, 0b10000000
    out TIMSK, r16    ;chyba maska przerwań, patrz jak wyżej
    sei                      ;uaktywnienie przerwań
     
    sbi DDRB, 4         ;PORTB4 na OUT
    cbi PortB, 4          ;PORTB4 na 0
     
    loop:
    rjmp loop             ;pętla bez końca
     
    led_off:
    push r16
    in r16, SREG
    push r16               ;SREG na stos
     
    ldi r16, 0
    out TCCR1B, r16   ;wyzerowanie tego rejestro (patrz do pdf-a)
    sbi PortB, 4           ;PORTB4 = 1
     
    pop r16                ;odtworzenie SREG ze stosu
    out SREG, r16
    pop r16
    reti                      ;powrót z przerwania

    0
  • #4 25 Wrz 2005 13:23
    Tymsal
    Poziom 11  

    Dziękuję za odpowiedźi, mój poziom znajomości asemblera nie jest za wysoki ale znam i potrafię wykorzystać podstawowe procedury. Z przerwaniami spotykam się po raz pierwszy i nie znam przeznaczenia niektórych rejestrów np. TCNT1, TCCR1B, TIMSK, SREG. Oczywiście korzystam z dokumentacji atmega8 i innych, firmy atmel ale mam problemy z zrozumieniem całego procesu ustawienia T0 i skierowania go by po przyjęciu przerwania wykonał odpowiedni podprogram. Jeżeli to jest zły przykład to gdzie mogę znaleźć dobry kurs asemblera na procesory AVR ?

    0
  • #5 25 Wrz 2005 13:35
    GienekS
    Poziom 32  

    A tak na marginesie ty pisze o T0 a w programie jest T1. Sprawdź czy masz właściwe adresy wektora.

    0
  • Pomocny post
    #6 25 Wrz 2005 14:12
    soft.sc
    Poziom 16  

    Code:
    .org 0x0000    ; ustawia adres w pamięci programu
    
    rjmp reset       ; skocz do etykiety ...
    ; wektor przerwania timer 1
    .org 0x0005
    rjmp led_off       ; skocz do obsługi przerwania

    ; w tym przykładzie początek programu głównego 
    reset:
    ; Jako pierwsze ustawienia stosu (w asemblerze jest to
    ; bardzo ważna operacja i programista nie może o tym zapomnieć).
    ; W rodzinie AVR stos jest dekrementowany (zmniejszany), dlatego
    ; wskaźnik stosu (spl) ustawiamy na koniec RAM)
    ldi r16, low(ramend)   ; do r16 stała wartość (tu adres
                            ; ostatniego bajtu RAM)
    out spl, r16       ; ustawia adres stosu na koniec RAM.

    ; konfiguracja timera 1.
    ; zapis wartości do 16-to bitowego licznika "timer 1" 
    ldi r16, high(0xf0be)   ; zapis 0xf0
    out tcnt1h, r16    ; starszy bajt
    ldi r16, low(0xf0be)   ; zapis 0xbe
    out tcnt1l, r16    ; mlodszy bajt
    ; ustawia źródło zegara (tu zegar systemowy z preskalerem
    ; ustawionym na wartość podziału = 1024) 
    ldi r16, 0b00000101
    out tccr1b, r16
    ; włączenie przerwania dla licznika 1 (dla at90s2313). Jeśli
    ; chcesz użyć innego procesora wstaw odpowiednią wartość
    ; lub dopasuj odpowiedni rejestr
    ldi r16, 0b10000000
    out timsk, r16
    ; globalne zezwolenie na przerwania. Bit I w rejestrze SREG
    sei
    ; Konfiguracja portu. Konfiguracja jest konieczna dla
    ; rodziny AVR. Utrudnia trochę pisanie programów,
    ; lecz daje większe możliwości portu   
    sbi ddrb, 4    ; bit 4 portu B jako wyjście push-pull
    cbi portb, 4    ; stan niski
    ; wieczna pętla w której nie wykonujemy żadnego programu
    ; gdyż głównym zadaniem jest obciążone przerwanie 
    loop:
    rjmp loop

    ; obsługa przerwania timera 1 
    led_off:
    push r16    ; zapamiętaj na stosie r16
    ; w tym przykładzie nie konieczne, ale to dobry zwyczaj
    ; zapamiętywania pierwotnych wartości rejestrów używanych
    ; w przerwaniach. Mamy pewność, że nie zmienimy żadnej
    ; wartości w programie głównym
    in r16, sreg    ; przepisz do r16 SREG
    push r16    ; zapamiętaj SREG na stosie
     
    ldi r16, 0    ; zeruj r16
    out tccr1b, r16   ; wyłącz timer 1
    sbi portb, 4    ; ustaw pin 4 portu B
     
    pop r16    ; zdejmij ze stosu wartość SREG
    out sreg, r16    ; odtwórz SREG (włącz Timer 1)
    pop r16    ; odtwórz pierwotną wartość r16
    reti       ; powróć z obsługi przerwania

    Tak napisany program zmieni stan diody tylko raz. (W przerwaniu tylko sbi portb, 4). Aby zmiany następowały cyklicznie należy trochę skomplikować jego budowę. Np. tak:
    Code:
     led_off: 
    
    ;....
    ; zamiast sbi portb, 4

    sbic portb,4   ; jeżeli portb.4 = 0 pomija następną instrukcję
    rjmp zeruj
    sbi portb,4   ; ustaw portb.4
    rjmp koniec
    zeruj:
    cbi portb, 4   ; zeruj portb.4
    koniec:
    ;...

    albo tak po zastosowaniu jednego rejestru więcej:
    Code:
    led_off:
    
    ;....
    in r16,portb   ; zaladuj wartosć rejestru PORTB
    ldi r17,4   ; do rejestru pomocniczego numer pinu (4))
    eor r16,r17   ; wykonaj EXOR PORTB i 4
    out portb,r16   ; Przywróć PORTB
    ;....

    0
  • Pomocny post
    #7 25 Wrz 2005 14:18
    zumek
    Poziom 39  

    A w pliku "m8def.inc" stoi:

    Code:

    .equ   INT0addr=$001   ; External Interrupt0 Vector Address
    .equ   INT1addr=$002   ; External Interrupt1 Vector Address
    .equ   OC2addr =$003   ; Output Compare2 Interrupt Vector Address
    .equ   OVF2addr=$004   ; Overflow2 Interrupt Vector Address
    .equ   ICP1addr=$005   ; Input Capture1 Interrupt Vector Address
    .equ   OC1Aaddr=$006   ; Output Compare1A Interrupt Vector Address
    .equ   OC1Baddr=$007   ; Output Compare1B Interrupt Vector Address
    .equ   OVF1addr=$008   ; Overflow1 Interrupt Vector Address
    .equ   OVF0addr=$009   ; Overflow0 Interrupt Vector Address
    ...


    Piotrek

    0
  • Pomocny post
    #8 25 Wrz 2005 14:31
    Dexter77
    Poziom 28  

    Wszystko ladnie tlumaczycie tylko ze nie posilkowaliscie sie nota katalogowa i ten program nie bedzie dzialal.
    ldi r16,0b10000000
    out TIMSK,r16
    Jesli spojrzec do noty to siodmy bit w TIMSK to OCIE2, czyli nic nie ma wspolnego z T1 czy T0. Mowilem ze ten program jest ZUPELNIE nie czytelny.
    Na samym pczatku juz kicha jest:
    .org 0x0005
    to wektor od Timer1 Capture Event zamiast od Timer1 Overflow. Powinno byc:

    Code:

    .include "m8def.inc"

    .org OVF1addr
      rjmp LedOff

    ldi r16,(1<<CS12)|(1<<CS10)
    out TCCR1B,r16  ;wlacz licznik zegar=CPU/1024
    ldi r16,(1<<TOIE1)
    out TIMSK,r16    ;zezwol na przerwanie od przepelnienia T1
    sei    ;zezwolenie globalne na przerwania

    Taki kod jest bardziej czytelny i jest 1000 razy mniejsza szansa na pomylke. Proponuje od samego poczatku przyzwuczajac sie do takiego zapisywania zmiennych stalych. Unikac jak ognia wszelkich cyferek typu 0b1000000,0b00000101 bo to nic nie mowi a jak przyjdzie do zmian w programi ktory ma kilka tysieci linijek i takie stale sa wywolywane kikanascie razy to tylko usiasc i sie zaplakac. Po to sa dyrektywy .EQU .SET #define zeby sobie zycie ulatwic.
    Pozdro
    Dexter

    0
  • #9 25 Wrz 2005 14:31
    Tymsal
    Poziom 11  

    Odpowiedź „soft.sc” jest w 100% taka jaką oczekiwałem. Dziękuję bardzo wszystkim którzy zainteresowali się moim problemem. Mam nadzieje że w przyszłości będę mógł liczyć na równie profesjonalną pomoc na elektrodzie.
    Temat uważam za zamknięty.
    Robert

    0