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

[at90s2313][asm]dziwne zachowanie timera1 w asemblerze

przemek.opalski 13 Sie 2009 22:01 1572 4
REKLAMA
  • #1 6890612
    przemek.opalski
    Poziom 11  
    Po raz kolejny zwracam się z prośbą do kolegów forumowiczów. Od pewnego czasu pracuję nad regulatorem fazowym zwykłe sterowanie triaka, wykrywanie 0 sieci nastawiane opóźnienie załączenia nic odkrywczego. Postanowiłem napisać taki program aby rozpocząć przygodę z uC. Pierwsza wersja powstała w C dodałem do tego coś a'la soft start i nawet to pracowało ale ponieważ cała ta heca miała służyć nauce więc postanowiłem napisać taki sam program w asemblerze i tu zaczęły się schody. W C zasada działania była prosta w przerwaniu od wejścia INT0 (tutaj są podawane impulsy w zerze) był zerowany timer1, który sobie od zera w górę zliczał impulsy zegarowe (podział przez 8,zegar 8MHz) do rejestru OCR1A wpisywałem wartość opóźnienia jeżeli wartość timera1 była równa OCR1A następowało przerwanie od porównania triak jest załączany i tak w kółko. Tak samo zrobiłem program w asemblerze(listing poniżej) alee nie działało to tak samo jak w C. Po kilku dniowej analizie zauważyłem, że regulator działa ale przy wartości OCR1A powiedzmy równej 64 535 triak była załączany tak jak by zamiast przerwania z OCR1A następowało przerwanie od przepełnienia timera1?Oco tu chodzi?!?
    Poniżej przedstawiam listing w asemblerze na pewno będzie pomocny:

    
    
    .include "2313def.inc"
    .macro SUB16
    	subi ZL,low(@0)
    	sbci ZH,high(@0)
    .endmacro	
    .cseg
    .org 0x00
    rjmp init
    .org INT0addr
    rjmp INT0_vect
    .org OC1addr
    rjmp TIMER1_COMP1_vect
    .org OVF0addr
    rjmp TIMER0_OVF0_vect
    .org INT1addr 	
    reti 	  	
    .org ICP1addr 	
    reti 	  	
    .org OVF1addr 	
    reti 	  	
    .org URXCaddr 	
    reti 	  	
    .org UDREaddr 	
    reti 	  	
    .org UTXCaddr 	
    reti 	  	
    .org ACIaddr 
    reti
    
    
    ;przerwanie, narastające zbocze na wejściu PD2.
    ;Tutaj wchodza impulsy z detekcji zera co 10ms
    INT0_vect:
    cbi PORTD,4         ;skasowanie triaka
    ldi r16,0x02        
    out TCCR1B,r16      ;uruchomienie licznika
    ldi r16,0x00
    ldi r17,0x00
    out TCNT1L,r16      ;wyzerowanie licznika
    out TCNT1H,r17
    out OCR1AL,ZL       ;wpisanie ustawienia
    out OCR1AH,ZH
    reti
    ;
    TIMER1_COMP1_vect: ;przerwanie od porównania włącza triaka
    sbi PORTD,4        ;triak ON
    ;ldi r16,0x00       ;zatrzymuje licznik
    ;out TCCR1B,r16
    reti
    
    
    TIMER0_OVF0_vect:  ;Timer0 jest wykorzystywany jako odliczacz czasu np.eliminacja drgań styków
    inc r25
    reti
    ;-----------------------------------------------------------
    ;inicjalizacja mikrokontrolera
    ;-----------------------------------------------------------
    init:
    cli
    ldi r16,RAMEND         ;Wskaźnik stosu
    out SPL,r16
    
    ldi r16,0b0110000   ;Ustawienia portu D
    out DDRD,r16           
    ldi r16,0b0000011
    out PORTD,r16
    
    ldi r16,0b11111111   ;Ustawienia portu B
    out DDRB,r16
    out PORTB,r16
    
    
    ldi r16,0x00        ;Konfiguracja TIMERA1
    out TCCR1A,r16
    
    ldi r16,0x00
    ldi r17,0x00
    out TCNT1L,r16
    out TCNT1H,r17
    ldi r16,0x42
    out TIMSK,r16
    ldi ZL,low(2000)  ;wartość początkowa
    ldi ZH,high(2000)
    out OCR1AL,ZL
    out OCR1AH,ZH
    
    
    ldi r16,0x03     ; konfiguracja TIMERA0
    out TCCR0,r16
    ldi r16,125
    out TCNT0,r16
    
    ldi r16,0x40     ;konfiguracja przerwania INT0
    out GIMSK,r16
    ldi r16,0x03
    out MCUCR,r16
    
    sei                 ;odblokowanie przerwan
    ;-----------------------------------------------------------
    ; Pętla główna programu
    ;-----------------------------------------------------------
    main_loop:
    sbis PIND,6      ;\
    brne line3       ; |
    out PORTB,ZL     ; |
    line3:           ; \ na port B wysylam wartosc ZL,ZH czyli poziom mocy w zaleznosci
    sbic PIND,6      ; / od stanu koncowki PD6 górny lub dolny bajt.Dodane w celu diagnostyki
    brne line4       ; |
    out PORTB,ZH     ;/
    line4:
    
    ldi r17,high(10000) ; ograniczenie  wartosci mocy
    cpi ZL,low(10000)
    cpc ZH,r17
    brsh line1
    sbis PIND,1
    brne UP
    line1:
    ldi r17,high(1000)  ;ograniczenie wartosci mocy
    cpi ZL,low(1000)
    cpc ZH,r17
    brlo line2
    sbis PIND,0
    brne DOWN
    line2:
    ldi r24,0x00
    rjmp main_loop
    
    ;-----------------|Obsługa klawiszy|-----------------
    UP:
    sbrc r24,1      
    rjmp main_loop
    cpi r25,20
    brne main_loop
    ldi r24,0x02
    SUB16 -1000
    rjmp main_loop
    
    DOWN:
    sbrc r24,0
    rjmp main_loop
    cpi r25,20
    brne main_loop
    ldi r24,0x01
    SUB16 1000
    rjmp main_loop
    ;---------------------------------------------------------------------------------------------
    .exit
    

    bedę wdzięczny za wszelką pomoc
  • REKLAMA
  • Pomocny post
    #2 6891239
    janbernat
    Poziom 38  
    W instrukcji piszą(str. 34):
    "Consequently, the high byte OCR1AH must be written
    first for a full 16-bit register write operation.
    Najpierw H, potem L.
    A w programie jest:

    out OCR1AL,ZL
    out OCR1AH,ZH

    Najpierw L, potem H.
    Mogę się mylić.
    Sprawdź.
  • REKLAMA
  • #3 6892622
    Nawigator
    Poziom 33  
    Ja bym dał jeszcze push/pop SREG w przerwaniach a już obowiązkowo w TIMER0_OVF0_vect: gdzie instrukcja inc r25 zmienia flagi Z,N,V w SREG.

    N.
  • REKLAMA
  • #4 6892898
    przemek.opalski
    Poziom 11  
    janbernat to był strzał w dziesiątkę!!tu był błąd wpisałem tak jak mówisz i wszystko działa poprawnie jak w C. Niestety mój angielski jest za słaby a tyle razy przeglądałem instrukcję i nie zauważyłem tego zdania :) dobrze, że jest elektroda :)

    Mam pytanie do Nawigator'a, czemu służy zapamiętywanie SREG na stosie?bo bez tego działa, domyślam się, że coś w stylu "dobrego taktu" czy inaczej wyrobienie dobrego odruchu podczas pisania programu, żeby nie było czasem niespodzianek i program nie zachowywał się nieprzewidywanie?A stosuję sie to tylko w przypadku przerwań?czy może makr też?
  • #5 6896320
    Nawigator
    Poziom 33  
    SREG czyli Status Register zawiera flagi jednostki centralnej mikroprocesora czyli jakby oznaczenia efektów jego ostatniego wykonanego rozkazu.
    Flagi służą głównie jako argumenty/znaczniki do wykonywania rozkazów warunkowych czyli najczęściej skoków.
    Przerwanie może nastąpić w dowolnej chwili czyli też pomiędzy ustawieniem flagi w SREG a jej wykorzystaniem w następnym rozkazie. Jeżeli kod obsługi przerwania zmieni te flagi to po powrocie z przerwania wykonanie rozkazu warunkowego będzie błędne.
    W Twoim przypadku akurat rozkazy ldi, cbi, out w przerwaniach INT0_vect oraz w TIMER1_COMP1_vect nie zmieniają flag w SREG więc nic się nie dzieje ale w przerwaniu TIMER0_OVF0_vect instrukcja inc r25 zmienia flagi Z,N,V i na pewno kiedyś zdarzy się przypadek że program się wysypie.
    Prawdopodobieństwo małe ale tak zdarzy się na pewno np. za kilka miesiecy i wtedy będziesz szukał przyczyn a jest ona tu od razu widoczna w kodzie.
    SREG możesz też zapamietać w innym rejestrze roboczym np. in r7, SREG, OUT SREG, r7, niekoniecznie na stosie.
    Jak piszesz programy w asemblerze to te elementy kodu lepiej dawać zawsze bo potem szukanie usterek trwa długo, to nie jest kwestia dobrego taktu tylko obowiązek.
    Uff ale się opisałem... jak na zaliczeniu.

    N.
REKLAMA