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

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

Adaszeq 05 Mar 2011 16:57 4868 11
REKLAMA
  • #1 9238572
    Adaszeq
    Poziom 10  
    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....


    
    
    #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;
    		}		
    }
    
    
  • REKLAMA
  • Pomocny post
    #2 9239195
    Moyshaa
    Poziom 14  
    Uuu.. Kolego ten kod absolutnie nie nadaje się do analizy.

    w init_klaw piszesz,
       DDRD = (DDRD & 0b11111011);          
       PORTD += (1<<PORTD2); 
    
    później w init
       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:
    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.
  • #3 9239294
    ololukiXP
    Poziom 19  
    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
    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:
    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.
  • REKLAMA
  • Pomocny post
    #4 9239406
    Konto nie istnieje
    Konto nie istnieje  
  • #5 9239426
    Adaszeq
    Poziom 10  
    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...
  • REKLAMA
  • Pomocny post
    #6 9239436
    Moyshaa
    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.
  • #7 9239488
    Adaszeq
    Poziom 10  
    ololukiXP napisał:

    Pomijając już opóźnienia w obsłudze przerwania i użycie przestarzałej funkcji obsługi przerwania (SIGNAL),ta linijka
    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:
    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?
  • #8 9239527
    tadzik85
    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.
  • #9 9239594
    Adaszeq
    Poziom 10  
    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
    #10 9239604
    tadzik85
    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.
  • REKLAMA
  • #11 9239650
    Adaszeq
    Poziom 10  
    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....
  • #12 9239740
    Moyshaa
    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.
REKLAMA