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

"C" - volatile nie działa w programie

shadowwelder 10 Lut 2010 23:48 2141 7
  • #1 7676371
    shadowwelder
    Poziom 11  
    Witam.
    Problemem jest nie działająca instrukcja volaitile. Dopiero zaczynam programowanie w C jednak zanim rozpocząłem pisać nowy temat to przeszukałem zasoby neta - z marnym skutkiem i dlatego pytam bardziej doświadczonych kolegów.
    Program jest prostym zegarem na AT90S2313 i wykorzystuje T0 do multipleksowania wyświetlaczy 7 -segmentowych(są 4 sztuki :) a T1 odlicza 1s. Do sprawdzania poprawności wyświetlanych cyfr stosuje instrukcje w pętli while(1) (w obecnej formie program kompiluje bez błędów,ostrzeżeń lecz nie działa na układzie). Przesunięcie tych instrukcji do obsługi przerwania ISR(TIMER1_OVF1_vect) powoduje, że układ pracuje poprawnie. Przypuszczam iż powodem jest zmienna volatile unsigned char sekundy.

    Oto listing:

    #include <avr/io.h>
    #include <avr/interrupt.h>
    
    unsigned char display,liczba1,liczba2,liczba3,liczba4;				//deklaracja zmiennych-godzina,nr wyswietlacza
    unsigned char liczba[10] = {192,249,164,176,153,146,130,248,128,144};		//deklaracja cyfr arabskich na 7seg
    volatile unsigned char sekundy;
    
    ISR(TIMER0_OVF0_vect )
    {
    TCNT0  = 178;
    PORTD |= (1<<3)|(1<<4)|(1<<5)|(1<<6);
    	
    	switch(display)           //włączanie wyświetlaczy
    	{
    	case 0:
    	PORTB = liczba[liczba1];
    	PORTD &= ~(1<<3);
    	break;
    	
    	case 1:
    	PORTB = liczba[liczba2];
    	PORTD &= ~(1<<4);
    	break;
    	
    	case 2:
    	PORTB = liczba[liczba3];
    	PORTD &= ~(1<<5);
    	break;
    	
    	case 3:
    	PORTB = liczba[liczba4];
    	PORTD &= ~(1<<6);
    	break;
    	}
    	display += 1;
    	if (display == 4) display = 0;	
    
    }
    
    ISR(TIMER1_OVF1_vect)
    {
    TCNT1  = 3026;
    sekundy += 1;	
    }
    
    
    int main(void)
    {
    DDRB    = 0xff;
    PORTB   = 0xff;
    
    DDRD   |= (1<<3)|(1<<4)|(1<<5)|(1<<6);
    PORTD  |= (1<<3)|(1<<4)|(1<<5)|(1<<6);
    
    sekundy	= 0;
    display = 0;
    liczba1 = 0;   //minuty
    liczba2 = 0;
    liczba3 = 0;   //godziny
    liczba4 = 0;
    
    TCNT1   = 3026; 								//Wartość początkowa aby T1 odmierzył 1s 
    TCCR1B |= (1<<CS10)|(1<<CS11);					//Ustawienie T1 na sygnał fck = 4MHz/64
    TIMSK  |= (1<<TOIE1);							//Odblokowanie przerwania od T1
    
    TCNT0   = 178;									//Wartość początkowa aby T0 odmierzył 5ms 
    TCCR0  |= (1<<CS12);							//Ustawienie T0 na sygnał fck = 4MHz/256
    TIMSK  |= (1<<TOIE0);							//Odblokowanie przerwania od T0
    sei();
    
    while(1)
    	{
    	if (sekundy >= 60)
    		{
    		sekundy  = 0; 
    		liczba1 += 1;
    		}
    	if (liczba1 == 10)
    		{
    		liczba1  = 0;
    		liczba2 += 1;
    		if (liczba2 == 6)
    			{
    			liczba2  = 0;
    			liczba3 += 1;
    			}
    		}
    	if (liczba3 == 10)
    		{
    		liczba3  = 0;
    		liczba4 += 1;
    		if (liczba4 == 2)
    			{
    			if (liczba3 == 4)
    				{
    				liczba3 = 0;
    				liczba4 = 0;
    				}
    			}
    		}
    	}
    }
  • #2 7676461
    mirekk36
    Poziom 42  
    Po pierwsze do jak wklejasz taki kod - to DAJ go w znacznikach CODE ! bo czyta się to delikatnie mówiąc tragicznie.

    Po drugie twoje domysły co do volatile są nietrafione.

    Po trzecie to nawet nie wiadomo z twojej wypowiedzi jaki jest problem poza tym, że w układzie coś tam nie działa - ale co nie działa poprawnie ??? a gdy wrzucisz fragment kodu do przerwania to działa poprawnie tzn jak ?

    może troszkę jaśniej opisz i sprecyzuj problem hmmm ? wtedy uda się na pewno coś pomóc ;)
  • #3 7676552
    shadowwelder
    Poziom 11  
    Program w pętli nieskończonej ma za zadanie zwiększyć liczbę minut(liczba1) gdy sekundy wyniosą 60(nastapi 60 przerwanie od T1) itd aż do liczby4. W obecnej konfiguracji układ wyświetla same zera po załadowaniu do AVR. Przeniesienie tej części programu(z pętli "while(1)") do obsługi przerwania od T1 powoduje poprawne działanie układu(zwiększają się minuty - liczba1,liczba2 oraz godziny liczba3,liczba4). Trochę kombinowałem i nadal nie wiem jak sobie z tym poradzić.
  • #5 7676947
    shadowwelder
    Poziom 11  
    Witam.
    Poszedłem za radą kolegi i zmieniłem dodatkowo liczba1...liczba4 na volatile i działa - dziękuje za pomoc. Rozumiem, że błąd był dla niektórych wręcz śmieszny, jednak zaczynam zabawę z C i czasami takie wpadki się zdarzają :) Dla uściślenia - volatile stosować wtedy gdy dokonuje się np obsługi przerwania i w wyniku tego przerwania wartość zmiennej mogłaby by zostać niezapisana np w mojej pętli while(1)? Książkowo - służy do wyłączenia obiektu z ewentualnej optymalizacji - czyli może zostać zignorowany jak w moim programie ?
  • #6 7677054
    Freddie Chopin
    Specjalista - Mikrokontrolery
    volatile stosować do każdej zmiennej która jest używana przez program główny i przerwanie/przerwania lub przez różne przerwania. Innymi słowy - do każdej zmiennej która używana jest w więcej niż jednym "wątku".

    4\/3!!
  • #7 7677056
    tmf
    VIP Zasłużony dla elektroda
    Implementacja volatile w znacznym stopniu zalezy od kompilatora. W avr-gcc mowi kompilatorowi, ze zmienna moze zostac zmieniona niezaleznie od sekwencji wykonywania programu - np. w przerwaniu, albo sprzetowo - np. rejestry IO procesora. W efekcie kompilator przy kazdym odwolaniu do takiej zmiennej raczej zaladuje ponownie jej zawartosc niz skorzysta z kopii. W efekcie optymalizacja jest gorsza, ale ciagle jakas moze byc. W stosunku do assemblera volatile znaczy, ze kompilator danej instrukcji nie moze wyrzucic - czesto stosuje ja razem z nop, ktore bez volatile zostaloby wywalone, jako instrukcja nic nie robiaca.
    volatile nigdy przez kompilatror nie jest ignorowane.
  • #8 7677145
    shadowwelder
    Poziom 11  
    Teraz już wszystko jasne. Dziękuje za pomoc i wyjaśnienie - temat uważam za zamknięty :)
REKLAMA