logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[Attiny2313][Asm] Synchronizacja przerwań i skalowanie czasu

Lukaszek_69 11 Mar 2010 00:04 1640 7
REKLAMA
  • #1 7812660
    Lukaszek_69
    Poziom 13  
    Witam!
    Zbudowałem prosty układ i chciałbym na nim nauczyć się dobrze obsługiwać i synchronizować przerwania. Jego głównym założeniem będzie liczenie co jedną sekundę do 99 na dwóch wyświetlaczach siedmiosegmentowych(obsługa "multipleksacją") z dodatkowymi opcjami(odebrać coś z komputera itp). Pisałem w C a z assemblerem dopiero zaczynam dlatego proszę o pomoc w poniższym programie:
    
    .include "tn2313def.inc"
    
    ;-----definicje---------------------
    .def tmp = r16
    .def tmp2 = r17
    
    ;-----wektory przerwan--------------
    
    .cseg
    .org 0x00
    rjmp reset
    .org 0x04
    rjmp timer1_compA
    .org 0x0D
    rjmp timer0_compA
    
    
    ;-----------------------------------
    
    reset:
    	ldi tmp, 0x72
    	out DDRD, tmp
    	ldi tmp, 0xFF
    	out DDRB, tmp		;konfiguracja PORTB i PORTD
    	ldi tmp, 0x10
    	out PORTD, tmp		;wstepne ustawienie multipleksacji
    	
    	ldi tmp, RAMEND
    	out SPL, tmp		;ustawienie stosu
    
    	ldi tmp, 0x01
    	out TCCR0B, tmp
    	out TCCR1B, tmp		;preskaler
    
    	ldi tmp, 0x41
    	out TIMSK, tmp		;wlaczenie przerwania compA dla obu timerow
    
    	ldi tmp, 0x06
    	out OCR0A, tmp		;comp0A = 6
    
    	ldi tmp, 0xD0
    	out OCR1AL, tmp
    	ldi tmp, 0x03
    	out OCR1AH, tmp		;comp1A = 976
    
    	sei
    
    end:
       	rjmp end
    
    ;-----------------------------------
    
    timer0_compA:
    	ldi tmp, 0x00
    	out TCNT0, tmp
    	in tmp, PORTD
    	ldi tmp2, 0x30
    	eor tmp, tmp2
    	out PORTD, tmp
    	reti
    
    timer1_compA:
    	ldi tmp, 0x00
    	out TCNT1H, tmp
    	out TCNT1L, tmp
    	in tmp,PORTB
    	ldi tmp2, 0xFF
    	eor tmp, tmp2
    	out PORTB, tmp
    	reti
    


    Debugowałem powyższy program i nie wiem jak poradzić sobie ze zsynchronizowaniem przerwań. Puki co zasada ma być prosta PD4 i PD5 ma się zmieniać z 0 -> 1 z częstotliwością ok 150Hz(nie posiadam oscyloskopu żeby się przekonać czy tyle naprawdę jest) zaś cały PORTB ma zmieniać swoją wartość na przeciwną co jedną sekundę. Problem w tym że gdy jestem w jednym przerwaniu drugie jest ignorowane. Jak temu zaradzić tak żeby wszystko się ładnie wykonało?

    I jeszcze jedno... Aby otrzymać przerwanie timer1_compA co jedną sekundę policzyłem tak:

    fosc/preskaler = 1000000/1024 = 976Hz
    daje to czas ok 1.024m/s
    1.024 * 976 = 1sek <- w przybliżeniu
    Dlatego zrobiłem takie przypisanie:
    
    	ldi tmp, 0xD0
    	out OCR1AL, tmp
    	ldi tmp, 0x03
    	out OCR1AH, tmp
    


    Niestety zmiana stanu następuje zdecydowanie szybciej. Dlaczego? Czyżbym przeoczył coś w nocie katalogowej?
  • REKLAMA
  • Pomocny post
    #2 7813804
    robson_s-ec
    Poziom 15  
    Lukaszek_69 napisał:
    Problem w tym że gdy jestem w jednym przerwaniu drugie jest ignorowane. Jak temu zaradzić tak żeby wszystko się ładnie wykonało?


    System przerwań jest automatycznie blokowany po wejściu do obsługi dowolnego przerwania.
    Cytat:
    When an interrupt occurs, the Global Interrupt Enable I-bit is cleared and all interrupts are disabled.
    The user software can write logic one to the I-bit to enable nested interrupts. All enabled
    interrupts can then interrupt the current interrupt routine. The I-bit is automatically set when a
    Return from Interrupt instruction – RETI – is executed.


    Właściwie to pozostałe przerwania nie są ignorowane a obsługiwane po zakończeniu obsługi pierwszego zgłoszonego.
  • REKLAMA
  • Pomocny post
    #3 7813898
    Nawigator
    Poziom 33  
    Nie wnikając w cały kod wpis do rejestrów 16-bitowych powinien być odwrotnie - najpierw H potem L. Odczyt napierw L potem H.
    Czyli:
    ldi tmp, 0x03
    out OCR1AH, tmp
    ldi tmp, 0xD0
    out OCR1AL, tmp

    N.
  • REKLAMA
  • Pomocny post
    #4 7813971
    wojtek8-7
    Poziom 13  
    Jeśli chcesz aby w trakcie jednego przerwania zostało obsłużone drugie, ważniejsze, dopisz w przerwaniu SEI. Wchodząc do przerwania flaga I jest zerowana i są wyłączane przerwania, rozkaz RETI ponownie ustawia flagę I.
  • #5 7815585
    Lukaszek_69
    Poziom 13  
    Właśnie problem w tym że przy debugowaniu po zakończeniu jednego przerwania kolejne nie było wykonane(chyba że coś źle zinterpretowałem)... Tak czy inaczej jutro spróbuje to zasymulować jeszcze raz bo dziś mam napięty dzień i o efektach poinformuje.

    Puki co priorytet przerwań nie ma większego znaczenia tak więc nie daje sei w przerwaniu.

    Dzięki za wskazówkę dotyczącą wpisów do rejestrów! Przyda się.

    A co myślicie o skalowaniu zegara tak żeby otrzymać żądaną jedna sekundę(1 Hz)?
    Korzystam ze złego sposobu? Dodam że zegara nie przestawiałem i jest domyślny 1MHz.
  • Pomocny post
    #6 7815936
    JarekC
    Poziom 32  
    Witam,

    Kilka uwag:

    1. nie skonfigurowałeś trybu pracy timerów (rejestry TCCRxA, TCCRxB)
    Po resecie timery pracują w trybie "Normal", natomiast w twoim przypadku znacznie lepszy byłby tryb "CTC"

    2. ustawiłeś prescaler a 1 a nie na 1024

    3. brak zachowania stanu PSW i rejestrów w przerwaniach. W twoim konkretnym przykładzie nie spowoduje to błędu ale już np. zaproponowane odblokowanie przerwania spowoduje problemy.

    Poczytaj sobie o trybie CTC pracy timerów.

    Pozdrawiam
    JarekC
  • Pomocny post
    #7 7816063
    grysek
    Poziom 19  
    To proste:

    Aby odczekać sekundę to przy zegarze 1Mhz musisz odczekać 1 000 000 cykli. Możesz użyć do tego preskalera (1,8,64,256,1024). Jesli chcesz odmierzyć sekundę to musisz użyć preskalera 64 (256 i 1024 nie wchodzi w gre ponieważ jeśli podzielimy 1 000 000 przez te liczby to nie wychodzi liczba całkowita).

    I tak przy preskalerze 64 timer musi zliczyć do 15625 (64 * 15625 = 1000000) aby to trwało 1 sekundę. I tą watrość możesz wsadzić do rejestru np OCR1A i puścić Timer w trybie CTC - czyli normalnego zliczania lecz po osiągnięciu tej wartości zawartość TCNT1 będzie kasowana i Timer bedzie zliczał od zera. Albo mozesz też wpisać wartość 0xFFFF - 15625 do TCNT1 bezpośrednio i ustawić Timer w trybie normalnego zliczania wtedy to za każdym przerwaniem musisz ładować tą wartość od nowa.

    Spójrz tu :arrow: http://www.wkretak.pl/readarticle.php?article_id=3

    Pozdrawiam :P
  • REKLAMA
  • #8 7888011
    Lukaszek_69
    Poziom 13  
    Niestety nie miałem możliwości wcześniej wszystkiego posprawdzać, ale zrobiłem to teraz i wszystko ładnie działa. Dziękuję wszystkim za zainteresowanie, uwagi były pomocne aczkolwiek układ nie działał w dużej mierze przed moją częstą nieuwagę.

    Poniżej przedstawiam działający kod. Mam nadzieje że się komuś przyda.
    
    .include "tn2313def.inc"
    
    ;-----definicje---------------------
    .def tmp = r16
    .def tmp2 = r17
    
    ;-----wektory przerwan--------------
    
    .cseg
    .org 0x00
    rjmp reset
    .org 0x04
    rjmp timer1_compA
    .org 0x06
    rjmp timer0_ovf
    
    
    ;-----------------------------------
    
    reset:
    	ldi tmp, 0xFF
    	out DDRD, tmp
    	ldi tmp, 0xFF
    	out DDRB, tmp		;konfiguracja PORTB i PORTD
    	
    	ldi tmp, RAMEND
    	out SPL, tmp		;ustawienie stosu
    
    	ldi tmp, 0x0B
    	out TCCR1B, tmp	        ;preskaler 64 + CTC dla timera 1
    
    	ldi tmp, 0x05
    	out TCCR0B, tmp	        ;preskaler 1024 dla timera 0
    
    	ldi tmp, 0x42
    	out TIMSK, tmp		;wlaczenie przerwania compA dla timera 1 
    				        ;wlaczenie przerwania overflow dla timera 0 
    
    	ldi tmp, 0x3D
    	out OCR1AH, tmp
    	ldi tmp, 0x09
    	out OCR1AL, tmp	;comp1A = 15625
    
    	sei
    
    end:
       	rjmp end
    
    ;-----------------------------------
    
    timer1_compA:
    	in tmp,PORTD
    	ldi tmp2, 0x0F
    	eor tmp, tmp2
    	out PORTD, tmp
    	reti
    
    timer0_ovf:
    	in tmp,PORTD
    	ldi tmp2, 0xF0
    	eor tmp, tmp2
    	out PORTD, tmp
    	reti
    


    Temat zamknięty.
REKLAMA