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

ATmega: Przerwania zewnętrzne INT0 i INT1 - poprawność kodu?

dscreator 09 Mar 2006 15:23 1970 2
REKLAMA
  • #1 2393978
    dscreator
    Poziom 10  
    Posty: 29
    Ocena: 3
    Potrzebuje dwa przyciski i postanowilem wykorzystać w tym celu przerwania zewnętrzne int0 i int1. Napisalem programik ale chyba coś poplątałem bo zwarcie do masy (przez przycisk) portu int0 nie powoduje uruchmienia podprogramu przerwania. Program wygląda następująco, jeśli ktoś ma chwilkę to proszę o podpowiedzenie czy procedura obsługi int0 jest poprawna. Do portu int0 mam dołączony przycisk a ten z kolei do masy. W podprogramie obsługi przerwania jest gaszenie i zapalanie diody.
    .INCLUDE "M8DEF.INC"

    .CSEG

    .org INT0addr
    rjmp klawiatura
    .ORG $000
    rjmp reset


    reset:

    ldi r16, high(RAMEND)
    out SPH, r16
    ldi r16, low(RAMEND)
    out SPL, r16

    ;sbi ddrd,ddd0 ;tryb wyjsciowy pd0 stan wysoki
    ;cbi portd,portd0
    ;sbi pind,pind0

    ;cbi ddrd,ddd2
    ;cbi portd,pd2

    ;ldi r16, 0b11111111
    ;out ddrd, r16
    ;ldi r16, 0b11111111
    ;out portd, r16

    ;ldi r16,

    sbi portd,2


    cbi ddrd,2 ;pd2 jako wejsciowy z podlaczonym podciaganiem
    sbi portd,2


    in r16,mcucr
    cbr r16,1<<isc00
    cbr r16,1<<isc11
    out mcucr,r16 ; przerwanie int0 dowolnym zboczem

    ldi r16,1<<intf0
    out gifr, r16 ; zeruj znacznik żądania przerwania int0

    in r16,gicr
    sbr r16,1<<int0
    out gicr,r16 ;włącz przerwanie int0
    sei
    skok:
    rjmp skok


    klawiatura:
    petla:
    ldi r16, 0b11111111
    out ddrb, r16

    wmiejscu:
    ldi r16, 0b10101010
    out portb, r16

    rcall podprogram1
    ldi r16, 0b01010101
    out portb, r16
    rcall podprogram1
    rjmp wmiejscu

    ;__________________
    podprogram1:


    ldi r18,255
    petla1:
    ldi r17,255
    petla2:
    dec r18
    cpi r18,0
    brne petla2
    ldi r18,255
    dec r17
    cpi r17,0
    brne petla2
    ret
  • REKLAMA
  • Pomocny post
    #2 2395901
    ZlyDotyk
    Poziom 19  
    Posty: 169
    Pomógł: 40
    Ocena: 1
    deklarujesz skok do przerwania pod jakims tam adresem:
    .org INT0addr
    rjmp klawiatura

    teraz deklarujesz skok do resetu
    .ORG $000
    rjmp reset
    reset:
    i dalej jakis kod... tyle ze ten kod zaczyna sie zaraz za rjmp RESET jednoczesnie zamazujac skok do Twojego przerwania INT0. Zakrecone no nie?;]
  • Pomocny post
    #3 2396338
    Jacu$
    Poziom 27  
    Posty: 730
    Pomógł: 119
    Ocena: 26
    :arrow: dscreator
    Przede wszystkim koniecznie skomentuj każdą linię i wklejaj za pomocą znaczników Code, ponieważ (jak widzisz) Twój program jest zupełnie nieczytelny (forum usuwa spacje na początku linii).
    Program powinien zaczynać się zaraz za obszarem wektorów przerwań. Jeśli jakiegoś przerwania nie wykorzystujesz to zamiast mnemonika rjmp wstawiasz pod tym adresem reti. Patrz przykład poniżej (nie chciało mi się komentować wszystkich przerwań):
    
    	.CSEG
    	.ORG 0x0000
    			rjmp reset
    			rjmp klawiatura	;INT0
    			reti					;INT1 
    			reti					;Timer2 Compare
    			reti					;Timer2 Overflow
    			reti
    			reti
    			reti
    			reti
    			reti
    			reti
    			reti
    			reti
    			reti
    			reti
    			reti
    			reti
    			reti					;TWI
    			reti					;SPM Ready
    
    reset:	ldi r16, high(RAMEND)
    			out SPH, r16
    			ldi r16, low(RAMEND)
    			out SPL, r16
    
    


    Moim zdaniem dwie poniższe linijki są kompletnie zbędne:
    
            ldi r16,1<<intf0
            out gifr, r16 ; zeruj znacznik żądania przerwania int0
    


    Podprogram dający opóźnienie jest dziwnie napisany. Instrukcje sprawdzające, czy w rejestrze po dekrementacji jest wartość 0 są zbędne - przecież już sama dekrementacja ustawia znaczniki w SREG. Można więc napisać ten podprogram dużo prościej i czytelniej:
    
    podprogram1:
    			clr r17
    			clr r18
    petla:	dec r18
    			brne petla
    			dec r17
    			brne petla
    			ret
    
    


    Można też zdefiniować sobie makroinstrukcję DJNZ (Decrement and Jump if No Zero) na początku programu:
    MACRO DJNZ	;DJNZ	LICZNIK, ETYKIETA_PETLI
    		dec	@0
    		brne  @1
    ENDMACRO
    

    Wówczas podprogram będzie jeszcze prostszy i czytelniejszy:
    
    podprogram1:
    			clr r17
    			clr r18
    petla:	DJNZ r18, petla
    			DJNZ r17, petla
    			ret
    

    Niestety, w assemblerze programy są zrozumiałe tylko w trakcie pisania. Dwa dni później nawet sam autor nie bardzo wie o co w tym wszystkim chodzi (oczywiście, przesadzam ;-) ).
REKLAMA