Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[ATmega32][C/AVR-GCC] - Przycisk w obsłudze przerwania

05 Mar 2011 16:57 4202 11
  • Poziom 9  
    Używam PWM do generowania różnych współ. wypełnienia dla diody RGB.
    Jeden przycisk jest odpowiedzialny za zmienianie trybów, jest on podłączony do INT0 (pin pracuje jako wej. z podciąganiem do plusa, a przycisk podpięty do masy).

    W skrócie, gdy zostaje naciśniety przycisk program wchodzi do obsługi przerwania, inkrementuje zmienna m. Gdy wychodzi z obsługi w głównej pętli sprawdzana jest zmienna m i ustawiany odpowiedni tryb (kolor).

    Problem jest taki, że czasem (b. rzadko) przeskoczy mi o 2 tryby. W ubsłudze przerwania starałem się wyeliminować drgania styków, nawet opóźnienie 1sec w obsłudze nie pomagało....


    Code:


    #define F_CPU 4000000UL

    #include "avr/io.h"
    #include "avr/interrupt.h"
    #include "util/delay.h"
    #include "stdlib.h"

    #define red OCR0
    #define green OCR1A
    #define blue OCR2


    uint8_t m;   // m-tryb pracy

    //inicjacja
    void init(void){
       
       DDRD |= _BV(PD5) | _BV(PD7);       //piny PD5 i PD7 wyjściami

       //red
       DDRB = (1<<PORTB3);                           
       TCCR0 = (1<<WGM00)|(1<<WGM01)|(1<<COM01)|(1<<COM00)|(1<<CS01);
       //green
       TCCR1A = (1<<COM1A1)|(1<<COM1A0)|(1<<WGM10);
       TCCR1B = (1<<WGM12)|(1<<CS10);
       //blue
       TCCR2 = (1<<WGM00)|(1<<WGM01)|(1<<COM01)|(1<<COM00)|(1<<CS01);
    }


    //inicjacja przycisku
    void init_klaw(void){

       DDRD &= ~_BV(PD2); //pin PD2  wejściem
       PORTD |= _BV(PD2); //pin PD2 podciągnięty do plusa

       //przerwanie zew INT0 (reaguje na zbocze opadajace)
       MCUCR = (MCUCR | 0b00000010);
       MCUCR = (MCUCR & 0b11111110);

       GIFR = (1<<INTF0);
       GICR = (1<<INT0);
    }


    // Przerwanie od klawiatury
    SIGNAL(SIG_INTERRUPT0){
          
          m++;
          _delay_ms(100);
          while(!(PIND & 0x04)) {}
          _delay_ms(100);
          init_klaw();
    }



    int main(void){
          init_klaw();
          init();
          sei();
          m=0;

          while(1){      
                    if(m==0)
                   czerwony(0);
                if(m==1)
                   zolty(0);
                if(m==2)
                   zielony(0);
                if(m==3)
                   blekitny(0);
                if(m==4)
                   niebieski(0);
                if(m==5)
                   fioletowy(0);
                if(m==6)
                   bialy(0);
                if(m>6)
                   m=0;
          }      
    }

    Darmowe szkolenie: Ethernet w przemyśle dziś i jutro. Zarejestruj się za darmo.
  • Pomocny post
    Poziom 14  
    Uuu.. Kolego ten kod absolutnie nie nadaje się do analizy.

    w init_klaw piszesz,
    Code:
       DDRD = (DDRD & 0b11111011);          
    
       PORTD += (1<<PORTD2);
    później w init
    Code:
       DDRD += (1<<PORTD5); 
    
       DDRD += (1<<PORTD7);
    A teraz analizujemy: chcesz, żeby, żaden z pinów rejestru kierunkowego portu D oprócz pinu 2 nie zmienił swojej wartości a pin 2 był 0-em (a i tak 0-em był), a później dodajesz do tego rejestru 32 i 128 co sprawia, że piny 7 i 5 są 1-kami. Natomiast do PORTU D dodajesz 4 co sprawia, że (skoro był 0-em) jest w nim wartość 4.
    Sprawiasz, że ludzie to czytający chcą sobie strzelić w łeb. Jak byś to samo napisał tak:
    Code:
    DDRD &= ~_BV(PD2); //pin PD2  wejściem
    
    DDRD |= _BV(PD5) | _BV(PD7); //piny PD2 i PD7 wyjściami
    PORTD |= _BV(PD2); //pin PD2 podciągnięty do plusa
    to analiza byłaby prosta. Wnioski jakie trzeba wyciągać z tego co ty robisz są tu od razu podane na tacy.
    I z chęcią byśmy z tobą błędu poszukali, a najprawdopodobniej znalazł byś go sam. Przy założeniu, że jest błąd w ustawieniach czegoś.. ciężko stwierdzić, bo czytać się tego kodu nie da.
    ---
    Zastanów się nad tym, aby sprawdzać zbocze narastające, czyli puszczenie przycisku i na to reagować. Może pomoże.
  • Poziom 18  
    Co to ma być?
    Adaszeq napisał:

    // Przerwanie od klawiatury
    SIGNAL(SIG_INTERRUPT0){

    m++;
    _delay_ms(100);
    while(!(PIND & 0x04)) {}
    _delay_ms(100);
    }
    [/code]

    Pomijając już opóźnienia w obsłudze przerwania i użycie przestarzałej funkcji obsługi przerwania (SIGNAL),ta linijka
    Code:
    while(!(PIND & 0x04)) {}

    powoduje zawieszenie się programu w obsłudze przerwania, kiedy na PIND4 pojawi się logiczne 0.
    Ja napisałbym to w ten sposób:
    Code:
    ISR (INT0_vect){
    
          _delay_ms(10);
          if(!(PIND & 0x04)) {
                    m++;}
    }

    a najlepiej sprawdzał stan przycisku w pętli głównej lub przerwaniu timera co jakiś czas.
  • Pomocny post
    Użytkownik usunął konto  
  • Poziom 9  
    Zaraz to poprawię... program był kilka razy zmieniany i jest to rezultat pozostałości z innych wersji ;>

    Nie miałem styczności z takim wyrażeniem (~_BV(PD2)). Podejrzewam, że ustawia jedynkę na PD2 bicie, potem neguje?? czyli _BV(a) to 8bitowa liczba z jedynka na a bicie??

    Moyshaa napisał:

    Zastanów się nad tym, aby sprawdzać zbocze narastające, czyli puszczenie przycisku i na to reagować. Może pomoże.


    Dzięki podciąganiu na INT0 mam ciągle "1". Wciskam przycisk, zbocze opadające uaktywnia mi obsługę przerwania, tam inkrementuje zmienna m, odczekuje 100ms (drgania styków),i jesli na INT0 jest ciągle stan niski (przytrzymany przycisk) to w pętli while czeka, aż zostanie puszczony.

    W podkreśleniu sprawdzam czy był puszczony to odpowiada zboczu narastającemu??
    Tak to mniej więcej widzę i popraw mnie w którym momencie źle rozumuje...
  • Pomocny post
    Poziom 14  
    Koniecznie zadbaj o to, żeby wychodząc z tego przerwania jego flaga była wyzerowana, a wtedy to o czym kolega _marek_ mówi nie będzie miało miejsca.

    ---

    Podczas puszczania przycisku są zdecydowanie mniejsze drgania styków niż podczas jego przyciskania i o to mi chodziło. Poza tym reagujesz wciąż na zbocze opadające a tylko czekasz z powrotem na narastające, ale o to mniejsza. Popieram to o czym powiedział kolega _marek_ to najprawdopodobniej jest przyczyna.

    Cytat:
    czyli _BV(a) to 8bitowa liczba z jedynka na a bicie??
    dokładnie tak. Dodatkowo &= to mnożenie logiczne, a |= to dodawanie logiczne.
  • Poziom 9  
    ololukiXP napisał:

    Pomijając już opóźnienia w obsłudze przerwania i użycie przestarzałej funkcji obsługi przerwania (SIGNAL),ta linijka
    Code:
    while(!(PIND & 0x04)) {}

    powoduje zawieszenie się programu w obsłudze przerwania, kiedy na PIND4 pojawi się logiczne 0.
    Ja napisałbym to w ten sposób:
    Code:
    ISR (INT0_vect){
    
          _delay_ms(10);
          if(!(PIND & 0x04)) {
                    m++;}
    }

    a najlepiej sprawdzał stan przycisku w pętli głównej lub przerwaniu timera co jakiś czas.


    W C nie pisałem dlatego szukałem w sieci składni obsługi przerwania, jeśli SIGNAL jest przestarzałe to czym się różni od ISR??

    ololukiXP napisał:
    a najlepiej sprawdzał stan przycisku w pętli głównej lub przerwaniu timera co jakiś czas.


    Wydaje mi się, że reakcja na wciśnięcie klawisza jest lepsza w przerwaniu niż ciągłe sprawdzanie w pętli portów?
  • Poziom 38  
    Źle ci się wydaję sprawdzanie portów co 50ms daje dobre rezultaty a eliminacja drgań styków jest samoistna wystarczy ze 2 kolejne stany będą identyczne.
  • Poziom 9  
    Moyshaa napisał:
    Koniecznie zadbaj o to, żeby wychodząc z tego przerwania jego flaga była wyzerowana, a wtedy to o czym kolega _marek_ mówi nie będzie miało miejsca.

    ---

    Podczas puszczania przycisku są zdecydowanie mniejsze drgania styków niż podczas jego przyciskania i o to mi chodziło. Poza tym reagujesz wciąż na zbocze opadające a tylko czekasz z powrotem na narastające, ale o to mniejsza. Popieram to o czym powiedział kolega _marek_ to najprawdopodobniej jest przyczyna.

    Cytat:
    czyli _BV(a) to 8bitowa liczba z jedynka na a bicie??
    dokładnie tak. Dodatkowo &= to mnożenie logiczne, a |= to dodawanie logiczne.


    Więc zadbałem wychodząc z przerwania, żeby flaga była wyzerowana i wygląda na to, że tu był haczyk. a Mianowicie

    Cytat:
    W trakcie obsługi przerwania przychodzi następne i czeka w kolejce.
    I czekać będzie nie ważne jak bardzo zostanie "przeciągnięte" przerwanie.


    To mam jeszcze dwa pytanka.
    1. Wydawało mi się, że upuszczając obsługę przerwania flaga przerwania jest sama zerowana? więc czemu musiałem o to dodatkowo zadbać?

    2. W trakcie obsługi przerwania przychodzi następne i czeka w kolejce, mógłbyś bardziej to objaśnić?

    tadzik85 napisał:

    Źle ci się wydaję sprawdzanie portów co 50ms daje dobre rezultaty a eliminacja drgań styków jest samoistna wystarczy ze 2 kolejne stany będą identyczne.


    Czyli mam rozumieć, że dla sprzętu wydajniejsze jest sprawdzanie portu? niż zrobienie tego w przerwaniu?
  • Pomocny post
    Poziom 38  
    A jak masz 10 przycisków wykorzystasz 10 przerwań? marnotrawstwo. wykorzystasz jeden licznik i po kłopocie zero opóźnień typu delay. Same zalety.

    minus? jeden: wykorzystany licznik.
  • Poziom 9  
    tadzik85 napisał:
    A jak masz 10 przycisków wykorzystasz 10 przerwań? marnotrawstwo. wykorzystasz jeden licznik i po kłopocie zero opóźnień typu delay. Same zalety.

    minus? jeden: wykorzystany licznik.


    Masz rację, przekonałeś mnie... w sumie gdybym nie używał przerwań to bym nie nie marnował tyle czasu na drgania styków :D a obsługa większej ilości... przycisków byłaby karkołomna....
  • Poziom 14  
    Cytat:
    2. W trakcie obsługi przerwania przychodzi następne i czeka w kolejce, mógłbyś bardziej to objaśnić?
    Ja się postaram. Wciskasz przycisk więc wchodzisz w przerwanie i zerujesz jego flagę. Ale przycisk zadrżał, więc znów zostało ono wywołane tylko, że flaga I jest na czas obsługi wyzerowana. Więc nie przerywasz tego przerwania, ale jak kończysz je obsługiwać więc znów ustawia się flaga I i sprawdzane jest czy wystąpiło jakieś przerwanie i znów Ci wejdzie w tą samą obsługę przerwania. Jak byś zanim wyjdziesz z przerwania zadbał o to, żeby flaga tego przerwania była wyzerowana to nie byłoby tego efektu.