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

[ATmega][C] Ogromne rozmiary pliku - funkcja _delay_ms

rafalkosc 27 Lut 2011 16:19 1771 6
  • #1 9211914
    rafalkosc
    Poziom 13  
    Witam!

    Zauważyłem dziwną rzecz. Jeśli w kodzie użyję funkcji _delay_ms z argumentem w postaci zmiennej, rozmiar skompilowanego kodu rozrasta się do około 40kB, zaś jeśli parametrem będzie bezpośrednio liczba, kod zajmuje 4kB. Co może być przyczyną?
    A, jeśli wywołuję tę funkcję z parametrem - zmienną, program nie działa prawidłowo.
    Pomóżcie, proszę! :)

    
    #define F_CPU 12000000UL
    #define PWM_MAX 100
    
    #include <avr/io.h> 
    #include <util/delay.h>
      
    void inicjuj(){
        int i;
        
        DDRB = _BV(DDB3);
        for(i = 0; i < 3; i++){
    	PORTB = 0x08;
    	_delay_ms(100);
    	PORTB = 0x00;
    	_delay_ms(100);
        } //for i
        
        
        TCCR0 =     _BV(WGM00)    // timer 2 fast PWM
    	      | _BV(WGM01)     // ditto
    	      | _BV(COM01)
    	      | _BV(COM00)     // clear OC2 on compare match, set OC2 at TOP
    	      | _BV(CS00);     // 1/8 prescale
        OCR0  = 255;
        
        DDRA = 0x00;
        PORTA = 0xFF;
        
    
    
    } //inicjuj
    
    
    void jasnosc(volatile uint8_t *kanal, uint8_t wartosc){
        if(wartosc > PWM_MAX) wartosc = PWM_MAX;
        *kanal = wartosc;
    
    } //sciemniaj
    
    int main(){
        double czest = 10;
        char i;
        inicjuj();
      
         while(1){
              
            if(bit_is_clear(PINA, PA0)){
        	_delay_ms(20);
            if(bit_is_clear(PINA, PA0)){
    		
    		 if(OCR0 <= (PWM_MAX - 1)){
    		 jasnosc(&OCR0, ++OCR0);
            	_delay_ms(10);
            	} 
                } // while PA0
             
             } //PA1
             
             if(bit_is_clear(PINA, PA1)){
        	_delay_ms(20);
            if(bit_is_clear(PINA, PA1)){
    		
            	 if(OCR0 >= 1){
            	 jasnosc(&OCR0, --OCR0);
            	 _delay_ms(10);
            	}
            	
                } // while PA1
             } //PA1
            
            
            if(bit_is_clear(PINA, PA2)){  // zapalanie
        	    _delay_ms(20);
        	    if(bit_is_clear(PINA, PA2)){
        		    jasnosc(&OCR0, 255);
        	    }
        	}
        	
        	if(bit_is_clear(PINA, PA3)){ //gaszenie
        	    _delay_ms(20);
        	    if(bit_is_clear(PINA, PA3)){
        		    jasnosc(&OCR0, 0);
        	    }
        	}
        	
        	if(bit_is_clear(PINA, PA4)){
        	_delay_ms(20);
        	while(bit_is_clear(PINA, PA4)){
        		jasnosc(&OCR0, 0);
        		_delay_ms(czest * 50);
        		jasnosc(&OCR0, 255);
        		_delay_ms(czest * 50);
        	    }
        	}
        	
        	if(bit_is_clear(PINA, PA5)){
        	    _delay_ms(20);
        	    if(bit_is_clear(PINA, PA5)){
    		if(czest >= 2) czest -= 1;
        		while(bit_is_clear(PINA, PA5));
        	    }
        	}
            
            if(bit_is_clear(PINA, PA6)){
        	_delay_ms(20);
        	    if(bit_is_clear(PINA, PA6)){
        		czest += 1;
        		while(bit_is_clear(PINA, PA6));
        	    }
        	}
            
        } //while
    } // main 
    
    
  • Pomocny post
    #2 9211952
    tadzik85
    Poziom 38  
    temat wałkowany już kilka krotnie.

    funkcje delay mają argument typu float jeśli podajesz zmienna jako argument do dodajesz również operacje zmiennoprzecinkowe na tej funkcji które .... dają efekt jaki uzyskałeś
  • #3 9211999
    rafalkosc
    Poziom 13  
    Dzięki za zainteresowanie :)

    Aha, już rozumiem. Zaglądałem do pliku nagłówkowego tej funkcji, ale nie wpadłem na to.

    Mam jeszcze problem taki, że biorąc argument jako zmienną, miganie nie działa zbyt dobrze. Pewnie muszę się zaznajomić z obsługą pamięci, coś czuję. Ale czy kompilator nie ładuje zmiennych do RAMu? Bo jeśli tak jest, to nie powinno być problemu. Czy może jednak są we flasahu?
  • Pomocny post
    #4 9212031
    tadzik85
    Poziom 38  
    Zamiast wstawiać argument do delaya umieść delaya w pętli for ze stałym argumentem.

    Zmienna zawsze znajdują się w SRAM.
    Ale stałe można umieścić w pamięci programu.
  • Pomocny post
    #5 9212057
    McMonster
    Poziom 32  
    Problem jest w tym, że ta funkcja jest tak zbudowana, że działa poprawnie tylko, gdy poda się stałą (lub wyrażenie, które może być ewaluowane do stałej w czasie kompilacji) jako argument, bo kompilator przy optymalizacji wykonuje różne czynności na podstawie argumentu, żeby takie opóźnienie było względnie dokładne. Do tego ta stała jest ograniczona. Kiedy podasz zmienną, to w czasie kompilacji nie jest wiadome, jakiej wartości się spodziewać i kompilator nie może tego zoptymalizować. Więcej możesz przeczytać na tej stronie.

    Za to możesz zrobić np. takie coś, ale nie będzie dokładne:

    void my_delay(int d)
    {
        for(int i = 0; i < d; i++)
            _delay_ms(10);;
    }
  • #6 9212089
    rafalkosc
    Poziom 13  
    Dałem tak, jak proponowałeś:

    
    if(bit_is_clear(PINA, PA4)){
        	_delay_ms(20);
        	while(bit_is_clear(PINA, PA4)){
        		for(j = 0; j < okres; j++){
        		    jasnosc(&OCR0, 0);
        		    _delay_ms(1);
        		}
        		for(j = 0; j < okres; j++){
            	    jasnosc(&OCR0, 255);
    		    _delay_ms(1);
        		}
        	    }
        	}
    


    I działa jak trzeba, dzięki! :)
    Tylko dalej nie rozumiem, dlaczego nie działało ze zmienną, czy to całkowitą, czy float. W headerze było napisane, że funkcja działa do ok. 6s opóźnienia.
  • #7 9212134
    McMonster
    Poziom 32  
    Bo gdy tam jest stała, to kompilator wykonuje dużo programistycznej magii podczas optymalizacji na podstawie tej wartości oraz częstotliwości zegara tak, żeby procesor odczekał dokładnie tyle, ile trzeba. Jeśli tam jest zmienna, to wartość nie jest znana (potencjalnie może tam się znaleźć cokolwiek w czasie wykonywania programu) i wtedy kompilator nie może tego zrobić, a sama funkcja bez tego jest bezużyteczna.

    Mikrokontrolery do odmierzania czasu mają tylko swój zegar, więc opóźnienia można realizować jedynie przez odliczanie kolejnych cykli zegarowych układu.
REKLAMA