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

[Atmega8][assembler] uprocesor sam się resetuje

loks 28 Kwi 2010 22:44 1594 2
REKLAMA
  • #1 8014766
    loks
    Poziom 12  
    Witam,
    Chciałem napisać prosty program do włączania i wyłączania 5 diod podłączonych do portów PC0-PC4 uP atmega8. Diody zapalą się po ustawieniu na portach stanu 0. Diody mają samoczynnie migać, a czas pomiędzy włączeniem, a wyłączeniem diod będzie ustawiany w timer0. Niestety uP po 294 cyklach uP restartuje się tj. wraca do funkcji reset. 294-ty cykl to wykonywanie komendy ret w funkcji Zapal_5_diod. Ma to miejsce zarówno w Avr Studio jaki na żywym układzie diody nie migają.
    Watchdog nie jest włączony. Oczywiście do rejestru TCCR0 wpisałem 0x01, ale tylko dlatego, żeby szybciej obserwować to w AVR Studio. Docelowo ustawie prescaler, aby móc obserwować miganie diody - wpiszę 0x05 do rejestru TCCR0.
    Oto listing programu:

    
    .include "m8def.inc"
    
     ;wektory przerwan
      .org $000	
      				rjmp reset
      ;.org $009
      ;				rjmp TIM0_OVF
    
    ;************************************************************
     reset:  
     ldi	r16,high(RAMEND)		; Set Stack Pointer to top of RAM
     out	SPH,r16
     ldi	r16,low(RAMEND)			; ustawienie stosu
     out	SPL,r16
    ;***********************************************************
     cli
     rcall Set_port_C				; inicjalizacja portu B
     rcall Set_Timer0				; inicjalizacja Timer0
     sei							; set global interrupt enable
     clr r16
     clr r17
     clr r18
     Start:
     nop
     in r16, TIFR					; sprawdzanie bitu TOV0
     andi r16, 0x01					; czy rowna sie 1
     cpi r16, 0x01					; czy rowna sie 1
     breq Zabawa_diodami 
     nop
     rjmp Start
    ;************************************************************
     Set_port_C:
     ; Define pull-ups and set outputs high
     ldi r16,(0<<PC5)|(1<<PC4)|(1<<PC3)|(1<<PC2)|(1<<PC1)|(1<<PC0)
     ; Define directions for port pins
     ldi r17,(0<<DDC5)|(1<<DDC4)|(1<<DDC3)|(1<<DDC2)|(1<<DDC1)|(1<<DDC0) 
     out PORTC,r16
     out DDRC,r17
     ; Insert nop for synchronization
     nop
     ret
    ;************************************************************
     Set_Timer0:
     ;ldi r16, 0x01
     ;out TIMSK, r16					; Overflow interrupt enable
     ldi r16, 0x01					; no prescaler
     out TCCR0, r16					; Clock select
     ret
    ;************************************************************
     TIM0_OVF:
     ;inc r17
     ;cpi r17, 0x02
     ;breq Zapal_5_diod
     ;cpi r18, 0x01
     ;breq Zgas_diody
     reti
    ;************************************************************
     Zapal_5_diod:
     ldi r16, 0x00
     out PORTC, r16
     nop
     ret
    ;************************************************************
    Zgas_diody:
     ldi r16, 0xFF
     out PORTC, r16
     clr r18
     nop
     ret
    ;************************************************************
    Zabawa_diodami:
     nop
     inc r18
     cpi r18, 0x01				; jezeli licznik=1 zapal diody
     breq Zapal_5_diod
     cpi r18, 0x02				; jezeli licznik=2 zgas diody
     breq Zgas_diody
     ldi r16, 0x01
     out TIFR, r16				; zerwoanie bitu TOV0 poprzez ustawienie go na 1
     nop
     ret
    ;************************************************************
    


    Jakieś pomysły?
    Będę wdzięczny za pomoc.
    Dzięki.
    Pozdr,
    Łukasz.
  • REKLAMA
  • #2 8014887
    JarekC
    Poziom 32  
    Witam,

    Przyczyną twoich problemów jest to iż błędnie zakładasz działanie instrukcji
    BREQ (skok jeżeli równe) a ty traktujesz ją jako CALL z warunkiem EQ (wywołaj jeżeli równe) a tak nie jest.

    Instrukcja BREQ location "skacze" do miejsca w skazywanego przez location
    nie odkładając adresu powrotu na stos. Aby wywołać podprogram musisz użyć
    instruckcji CALL (RCALL)

    Drugim błędem który ujawni się później jest brak zachowywania rejestru stanu (SREG) w przerwaniu od Timera.

    Pozdrawiam
    JarekC
  • #3 8018040
    loks
    Poziom 12  
    Racja. Już dawno nie pisałem w assemblerze. Zastosowałem etykiety do skoków, a później wywołałem funkcje i działa (funkcja zabawa diodami). Przy obsłudze przerwania będę odkładał rejestr SREG na stos.

    Poniżej poprawiony listing programu.
    
    .include "m8def.inc"
    
     ;wektory przerwan
      .org $000	
      				rjmp reset
    ;************************************************************
     reset:  
     ldi	r16,high(RAMEND)		; Set Stack Pointer to top of RAM
     out	SPH,r16
     ldi	r16,low(RAMEND)			; ustawienie stosu
     out	SPL,r16
    ;************************************************************
     cli
     rcall Set_port_C				; inicjalizacja portu B
     rcall Set_Timer0				; inicjalizacja Timer0
     sei							; set global interrupt enable
     clr r16
     clr r17
     clr r18
     Start:
     in r16, TIFR					; sprawdzanie bitu TOV0
     andi r16, 0x01					; czy rowna sie 1
     cpi r16, 0x01					; czy rowna sie 1
     breq Diody
     rjmp Start 
     Diody:
     rcall Zabawa_diodami
     rjmp Start
    ;************************************************************
     Set_port_C:
     ; Define pull-ups and set outputs high
     ldi r16,(0<<PC5)|(1<<PC4)|(1<<PC3)|(1<<PC2)|(1<<PC1)|(1<<PC0)
     ; Define directions for port pins
     ldi r17,(0<<DDC5)|(1<<DDC4)|(1<<DDC3)|(1<<DDC2)|(1<<DDC1)|(1<<DDC0) 
     out PORTC,r16
     out DDRC,r17
     ; Insert nop for synchronization
     nop
     ret
    ;************************************************************
     Set_Timer0:
     ldi r16, 0x00
     out TIMSK, r16					; Overflow interrupt disable
     ldi r16, 0x01					; no prescaler
     out TCCR0, r16					; Clock select
     ret
    ;************************************************************
     Zapal_5_diod:
     ldi r16, 0x00
     out PORTC, r16
     nop
     ret
    ;************************************************************
    Zgas_diody:
     ldi r16, 0xFF
     out PORTC, r16
     clr r18
     nop
     ret
    ;************************************************************
    Zabawa_diodami:
     inc r18
     cpi r18, 0x01				; jezeli licznik=1 zapal diody
     brne Zgas
     rcall Zapal_5_diod
     ldi r16, 0x01
     out TIFR, r16			; zerowoanie bitu TOV0 poprzez ustawienie go na 1
     rjmp Koniec
     Zgas:
     rcall Zgas_diody
     ldi r16, 0x01
     out TIFR, r16			; zerowoanie bitu TOV0 poprzez ustawienie go na 1
     Koniec:
     ret
    ;************************************************************
    


    Może przesiądę się na C:)
    Dzięki.
    Pozdr,
    Łukasz.
REKLAMA