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

[Atmega16] Proste przerwania od przycisków

MurderDoll 14 Lut 2010 09:47 5767 8
REKLAMA
  • #1 7691524
    MurderDoll
    Poziom 10  
    Wgrałem do Atmega16 prosty programik obsługi przerwań zewnętrznych (poniżej kod).

    #include <avr/io.h>
    #include <avr/interrupt.h>        
    
    SIGNAL (SIG_INTERRUPT0){
      PORTB = 0xFF;
    }
    
    SIGNAL (SIG_INTERRUPT1){
      PORTB = 0x00;
    }
    
    int main(void){
      DDRB = 0xFF;
      DDRD = 0x00;
      PORTD = 0xFF;
      GIMSK = _BV(INT0)|_BV(INT1);
      MCUCR = _BV(ISC01)|_BV(ISC11);
      sei();
      while(1);
    }


    Zwieram port PD2(INT0) oraz PD3(INT1) do masy i nic się nie dzieje. Dioda podłączona do portu PB0 nawet się nie zapala. Gdzie leży problem?
  • REKLAMA
  • Pomocny post
    #2 7691712
    zumek
    Poziom 39  
    MurderDoll napisał:
    ...
    Zwieram port PD2(INT0) oraz PD3(INT1) do masy i nic się nie dzieje...

    No to ustaw w projekcie właściwy uC, bo jeżeli w/w kod kompiluje się bez błędów, to jest kompilowany dla innego uC.
      GIMSK = _BV(INT0)|_BV(INT1);

    M16 nie posiada takiego rejestru.
  • #3 7691929
    MurderDoll
    Poziom 10  
    Moja duża wina i niedopatrzenie.
    Rzeczywiście oprócz GIMSK miałem również Makefile ustawionego na ATmega8.

    Poniżej wklejam prosty działający kod na obsługę przerwań w Atmega16.

    #include <avr/io.h> 
    #include <avr/interrupt.h> 
    
    ISR(INT0_vect){ 
    	PORTA = 0xFF; 
    }
    
    ISR(INT1_vect){ 
    	PORTA = 0x00; 
    }
    
    void init(void){ 
    	sei(); 
    	MCUCR = ((1<<ISC01)|(0<<ISC00));  
    	GICR |= _BV(INT0) | _BV(INT1);  
    	DDRA = 0xff; 
    	DDRD = 0x00; 
    	PORTD = 0xff; 
    } 
    
    int main(void){ 
    	init();
    	while(1);
    } 
    
  • REKLAMA
  • #4 7692308
    tmf
    VIP Zasłużony dla elektroda
    Program dzialajacy ale zasadniczo bezuzyteczny. Jesli stosujesz przyciski musisz zrobic debouncing - przycisk drga i jedno nacisniecie/zwolnienie generuje serie impulsow. W programie, ktory pokazales jest to bez znaczenia, ale zobacz co sie stanie jesli zamiast np. PORTA=0 wpiszesz PORTA=PORTA^0xFF. Wtedy moznaby sie spodziewac, ze kolejne nacisniecia przycisku zmienia stan portu na przeciwny (na przemian dioda sie zapala i gasnie). Ciekawe na ile nacisniec zaobserwujesz takie zjawisko, a na ile stan portu bedzie losowy.
  • #5 7694825
    MurderDoll
    Poziom 10  
    rozumiem, że gdy przerwanie bedzie miało taką postać:
    
    ISR(INT0_vect){
    // np. inkrementacja globalnego licznika
    _delay_ms(1000);
    }
    


    to przy jednym naciśnięciu uzyskam zwiększenie licznika o jeden?
    Jeszcze jedno pytanie. Czy przy taktowaniu zegara wewnętrznego 1MHz dla mC Atmega16 będzie to delay równy dokładnie jednej sekundzie?
  • REKLAMA
  • #6 7694863
    tadzik85
    Poziom 38  
    funkcja _delay_ms() możne posiadać argument o maksymalnej wartości 262,2/ F_CPU

    w twoim przypadku 262; jeśli chcesz realizować dłuższe opóźnienie musisz powielić tą instrukcje np w pętli for
  • REKLAMA
  • #7 7695185
    ciastek4
    Poziom 14  
    Obsługa przycisków w ten sposób jest trochę nie wskazana, zwłaszcza gdy chcemy zrobić sprzętowy "debouncing" .
    Polecam lekturę:
    http://www.ganssle.com/debouncing.pdf

    Nie jest zalecane, aby wprowadzać opóźnienie w przerwaniach. Przerwanie powinno być bardzo zwięzłe i szybkie. Jeżeli chcesz zrobić softwarową obsługę "debouncingu" lepszym sposobem jest wywoływanie przerwania np. co 20ms i sprawdzanie w nim czy przyciśnięto przycisk. Jeżeli tak to zwiększamy licznik od przycisku, jeżeli nie to kasujemy ten licznik. W chwili gdy licznik osiągnie wartość np. 5 ( 20* 5 = 100ms ) to ustawiamy flagę przyciśnięcia przycisku. W funkcji main sprawdzamy sobie cały czas tą flagę i jeżeli jest ustawiona to wchodzimy do obsługi przycisku.
    kod np. mógłby tak wyglądać
    
    ISR(TIMER0_OVF_vect)
    {
    static uint8_t but1_timer;
    
    
    if( BUT1_RD() ) but1_timer++;
    else but1_timer=0;
    
    if(but1_timer > 5) but1_pushed = 1; // flaga wcisniecia przycisku
    }
    
  • #8 7696105
    MurderDoll
    Poziom 10  
    czy ten fragment kodu


    oznacza np. czytanie z portu wejściowego czy nastąpoiło zwarcie do masy konkretnego wejścia w mC?

    kolejna rzecz to co oznacz dokładnie to równanie ( 20* 5 = 100ms ) skąd liczba 20?
  • #9 7696331
    ciastek4
    Poziom 14  
    MurderDoll napisał:
    czy ten fragment kodu


    oznacza np. czytanie z portu wejściowego czy nastąpoiło zwarcie do masy konkretnego wejścia w mC?

    To zalezy jak sobie ja zaimplementujesz (but1 zadeklarowany na pinie A nr 4) może wyglądać:

    #define BUT1_RD() ( PINA&(1<<4) ) //przycisk aktywowany stanem wysokim
    lub #define BUT1_RD() ( (~PINA)&(1<<4)) //przycisk aktywowany stanem niskim


    MurderDoll napisał:

    kolejna rzecz to co oznacz dokładnie to równanie ( 20* 5 = 100ms ) skąd liczba 20?

    20ms - to czas co po jakim jest wywoływane przerwanie od timera . Tutaj zrobiłem byka bo powinno być 20* 6 = 120ms- czyli czas jaki jest potrzebny do obsługi przycisku (ustawienie flagi wciśnięcia przycisku). Oczywiście ten czas można zmniejszyć, ponieważ podałem go jako przykład w tym temacie.
REKLAMA