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][C] kłopot z przerwaniem i 7seg.

csdominik 19 Sie 2010 10:02 1624 4
REKLAMA
  • #1 8414475
    csdominik
    Poziom 11  
    Witam,
    ostatnio zająłem się pisaniem stosunkowo prostej aplikacji na AVR ATmega8, potrzebnej mi na studia. Na celu miałem też trochę lepsze poznanie AVR.
    W czym problem : W moim programie chciałem przetestować typowe zachowanie uC, napisałem kilka prostych funkcji, włączyłem przerwania, zrobiłem pętle nieskończoną w której na moim wyświetlaczu 7 segmentowym przemyka 0 . (są 4 wyświetlacze). Następnie zrobiłem symulacje uśpienia uC przez naciśniecie PD (0) , na teraz jest to tylko bardzo duże opóźnienie. Oczywiście będąc w pętli nieskończonej uC reaguje na przerwania od TIMERA, INT0 oraz INT1. Zdaję sobie sprawę ze znak_LED jest zrobiony trochę "na dziko". Ale taka wersja na pewno działa.
    PROBLEM 1 :
    ATmega w ogóle nie reaguje na wciśnięcie przeze mnie przycisku PD2 (INT0), natomiast wciśnięcie przycisku PD3 (INT1) działa znakomicie. Działa także przerwanie od TIMERA. Zastanawiające. Czy zrobiłem gdzieś błąd w programie? W konfiguracji? Czy może nie wiem o czymś krytycznym?
    PROBLEM 2:
    Następną sprawą jest problem z funkcją error1();. Zaraz po jej wywołaniu uC działa jak należy - wyświetla z lewej strony aktualną wartość K , a potem z prawej na 3 wyświetlaczach napis Err i tak sobie mryga aż k=10, wtedy wychodzi, zeruje wyświetlacz, no i ... właśnie powinien wrócić do pętli nieskończonej w której na wyświetlaczu przemykają zera. Ale u mnie na wyświetlacz gaśnie, i nic się dalej nie dzieje. Przynajmniej ja nie wiem jak to sprawdzić. A zależy mi oczywiście na poprawnym powrocie z przerwania. Dodam jeszcze że gdy obsługę przerwania INT1 zostawię pustą - to program poprawnie wraca z przerwania.

    Czy ktoś widzi moje błędy? Bo już od kilku godzin siedzę i nie mogę znaleźć błędu.


    	
    //              HARDWARE:
    //		PORTB :			
    //				PB0 -	A
    //				PB1 -	B
    //				PB2 -	C
    //				PB3 -	D
    //				PB4 -	E
    //				PB5 -	F
    //				PB6 - G
    //				PB7 - DP
    //		PORTC :
    //				PC0 -	A0
    //				PC1 -	A1
    //				PC2 -	A2
    //				PC3 -	A3
    //				PC4 -	
    //				PC5 -	
    //				PC6 -
    //				PC7 -
    //		PORTD :
    //				PD0 - SW0	
    //				PD1 - SW1	
    //				PD2 - SW2	 	// int0
    //				PD3 -	SW3		// int1
    //				PD4 -	SW4
    //				PD5 -	SW5	
    //				PD6	-	SW6	
    //				PD7	-	SW7	
    	#include <avr/io.h>	
    	#include <avr/interrupt.h>	
    	#include <avr/sleep.h>
    	#define F_CPU 1000000 	// 1Mhz
    	#include <util/delay.h>
    
    // definicja wyboru wyświtlacza 7seg.
    	#define	A_0	1
    	#define	A_1	2
    	#define	A_2   4
    	#define	A_3	8
    // TABLICA ZMIENNYCH DO WYSWIETLACZA LED 7SEG
    unsigned char liczba_LED[10]={0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90};
    unsigned char znak_LED[4]={0x06,~(0x50),~(0x20),~(0x20)};
    //					znaki=		E	,	r	,	-	,	-	,
    
    // PRZERWANIA:
    ISR (INT0_vect)  // przerwanie od INT0
    {
    // jakies tam instrukcje
    }
    
    ISR (INT1_vect)  // przerwanie od INT0
    {
    	error1();	
    	wyswietl_7seg_zostaw(0,A_0|A_1|A_2|A_3);
    	_delay_ms(250);
    }
    
    ISR (TIMER1_OVF_vect) // przerwanie od przepełnienia licznika
    {
    // jakieś tam instrukcje 
    }
    
    ISR (BADISP_vect){} // jeśli wystapi jakiekolwiek inne przerwanie - to to ratuje sytuacje przed resetem
    
    void AVR_init(void)
    {
    	DDRB = 0xFF;	// PORTB WYJSCIOWY
    	DDRC = 0xFF; 	// PORTC wYJSCIOWY
    	DDRD = 0x00;	// PORTD WEJSCIOWY
    }
    
    void wyswietl_7seg_zostaw (int liczba, int PORT_A_LCD)
    {
    	PORTB = liczba_LED[liczba];
    	PORTC = 0x00+~(PORT_A_LCD);
    	_delay_ms(100);
    }
    
    
    void wyswietl_7seg_znak (int liczba, int PORT_A_LCD)
    {
    	PORTB = znak_LED[liczba];
    	PORTC = 0x00+~(PORT_A_LCD);
    	_delay_ms(5);
    }
    
    void error1(void)
    {
    	for(int k=0;k<10;k++)
    	{
    	for(int ki=0;ki<100;ki++)
    	{
    		wyswietl_7seg_znak (0, A_2); // wyswietlam znak E
    		
    		wyswietl_7seg_znak (1, A_1); // wyswietlam znak r
    		
    		wyswietl_7seg_znak (1, A_0); // wyswietlam znak r
    	}
    		wyswietl_7seg_zostaw(k,A_3); // wyswietlam k
    		_delay_ms(100);
    	}
    	wyswietl_7seg_zostaw(0,A_0|A_1|A_2|A_3);
    	_delay_ms(250);
    }
    
    
    // MAIN:
    int main(void)
    {
    //	INICJALIZACJA AVR 
    	AVR_init();
    	
    	PORTB = 0xC0; 				// zero na wyświetlaczu
    	
    //	PRZERWANIA
    	GICR 	= _BV(INT0);  		// włączenie przerwania od INT0 ; mogłoby być GICR 	= _BV(INT0|INT1);
    	GICR 	= _BV(INT1);
    	MCUCR 	= 0; 		// włączenie reakcji na opadające zbocze.
    	
    	
    	TCCR1B 	= _BV(CS11);		// preskaler X8 = 524280 = troche ponad 1/2 sek
    	TIMSK 	= _BV(TOIE1);		// włacz obsługę przerwania przepełnienia TIMER 1
    	
    	
    //-- WŁĄCZ GLOBALNĄ OBSŁUGE PRZERWAŃ --
    	sei();
    	
    
    //PĘTLA NIESKOŃCZONA	
    	for( ; ; ) 
    	{
    	
    	if(bit_is_clear(PIND, 0)) atmega_sleep();
    	
    	wyswietl_7seg_zostaw (0, A_3); // mimo że jest napisane zostaw - to naturalnym jest że 
    	wyswietl_7seg_zostaw (0, A_2); // zera przelatują, każda kolejna funkcja
    	wyswietl_7seg_zostaw (0, A_1); // kasuje poprzednie ustawienie PORTC
    	wyswietl_7seg_zostaw (0, A_0); 
    	
    	
    	
    	
    	}
    	
    	return 0;
    	
    }
    
  • REKLAMA
  • Pomocny post
    #2 8414529
    tmf
    VIP Zasłużony dla elektroda
    Nie pokazałeś całości, a problem może właśnie tkwić w rzeczach, których nie pokazałeś. Ale kilka uwag - po pierwsze przyciski drgają, w efekcie nie dostajesz jednego przerwania tylko dziesiątki. Twoja procedura obsługi to eliminuje, bo jest strasznie długa, ale i tak co najmniej 2 razy zostanie wywołana. Przyciski jak rozumiem masz podciągnięte rezystorem?
    Kolejna rzecz to obsługa przerwań - w tym programie być może to bez znaczenia, ale przerwania mają być obsługiwane jak najkrócej. U ciebie obsługa może trwać prawie 1,5s co zdecydowanie jest przegięciem. W tym czasie wszystkie inne przerwania i funkcje procesora są "zawieszone". Napewno tego chcesz? Teraz to:
    GICR = _BV(INT0); // włączenie przerwania od INT0 ; mogłoby być GICR = _BV(INT0|INT1);

    Kor jest w porządku, ale komentarz mocno nie teges. Zobacz do czego jest rozwijane makro _BV() a dowiesz się dlaczego _BV(INT0|INT1) nie zadziała tak jak piszesz.
    No i uruchom kod w symulatorze, zobaczysz na czym program staje.
  • REKLAMA
  • Pomocny post
    #3 8414548
    gaskoin
    Poziom 38  
    csdominik napisał:

    	
    
    	GICR 	= _BV(INT0);  		// włączenie przerwania od INT0 ; mogłoby być GICR 	= _BV(INT0|INT1);
    	GICR 	= _BV(INT1);
    


    najpierw zezwalasz na przerwania od int0, a potem ich zabraniasz pisząc w ten sposób ... więc kod jest nie w porządku, no chyba, że jest to celowe, w co wątpię. Powinieneś zrobić tu ORa
  • REKLAMA
  • #4 8414614
    csdominik
    Poziom 11  
    Dziękuję za odpowiedz. Co do uwag - tak mam podpięte rezystory, a rozkaz _VB(INT0|INT1); rzeczywiście nie będzie działać poprawnie.
    Jeśli chodzi o drgania styków - zwykle je eliminowałem, ale w tym wypadku widziałem testując układ, że ich nie ma - chociaż w rzeczywistości były eliminowane przez długość przerwania.
    Moją ideą było uśpienie uC, i wybudzenie go podczas przerwania - po czym wykonywałbym rozkazy testujące warunki w jakich wybudził sie uC, tak się składa że chciałem zrobić to w przerwaniu, zastanowię się jakie konsekwencje dla mnie miałoby poprawienie tego. Jeśli chodzi o kod - zostały mi jakieś 2 funkcje, wyświetlania na 7segm. I funkcja ATmega_sleep(); w której dałem diablo duże opóźnienie.
    Dziękuję za pomoc.

    W zasadzie pozostaje problem - nie wchodzenia w INT0.


    UPDATE :
    @ gaskoin
    O rany, rzeczywiście, tą komendą nadpisuję wcześniej ustawione zezwolenie na przerwanie. Dziękuję bardzo za pomoc!
    Te moje błedne podejrzenia dotyczące GICR - jednak nie były bezpdstawne, powinno być (myślę że tak będzie na 100% działało)
    Cytat:
    GICR = _BV(INT0)|_BV(INT1);



    Temat do zamknięcia.
REKLAMA