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

[C][Attiny2313]Dlaczego ten kod zajmuje tyle miejsca ?

finger6 03 Lut 2011 19:54 1481 9
REKLAMA
  • #1 9098640
    finger6
    Poziom 11  
    Wiem, że macie już powyżej uszu lampek RGB, ale mimo wszystko może mi dacie jakieś wskazówki ?
    Napisałem taki program, do obsługi lampki z jednym przyciskiem, którego wciśnięcie ma zmieniać tryb z pracy płynnej na skokową. To jest w zasadzie dopiero szkielet programu, ale już zajmuje więcej niż procesor ma pamięci... Mógłby mi ktoś powiedzieć jak go zoptymalizować ?

    #define F_CPU 400000L
    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    
    volatile int red, green, blue; //do funkcji fpwm
    volatile tryb=0; //do wektora przerwan
    volatile int i; 
    volatile int C=20; 
    volatile int D=2000;
    ISR(INT0_vect) //przerwanie int0
    {
    	tryb=tryb+1;
    	if (tryb==2) tryb=0;
    }
    
    int fpwm(red, green, blue) //PWM
    {
    DDRB=0xff;
    TCCR0A|=(1<<COM0A1)|(1<<COM0A0)|(1<<WGM00);
    TCCR0B|=(1<<CS00);
    OCR0A=red;
    TCCR1A|=(1<<COM1A1)|(1<<COM1A0)|(1<<COM1B0)|(1<<COM1B1)|(1<<WGM10);
    TCCR1B|=(1<<CS10);
    OCR1A=green;
    OCR1B=blue;
    }
    
    int plynnie(void) //plynne zmienianie kolorow
    {
    while (1)
    {
    for (i=0; i<255; i++)
    {
    fpwm(0, 255, i);
    _delay_ms(C);
    };
    _delay_ms(D);
    for (i=0; i<255; i++)
    {
    fpwm(i, 255-i, 255);
    _delay_ms(C);
    };_delay_ms(D);
    for (i=0; i<255; i++)
    {
    fpwm(255-i, i, 255-i);
    _delay_ms(C);
    };_delay_ms(D);
    for (i=0; i<255; i++)
    {
    fpwm(i, 255-i, 0);
    _delay_ms(C);
    };_delay_ms(D);
    for (i=0; i<255; i++)
    {
    fpwm(255, 0, i);
    _delay_ms(C);
    };_delay_ms(D);
    for (i=0; i<255; i++)
    {
    fpwm(255-(i/2), (i/4), 255);
    _delay_ms(C);
    };_delay_ms(D);
    for (i=0; i<255; i++)
    {
    fpwm(120, 65+(i/3), 255-i);
    _delay_ms(C);
    };_delay_ms(D);
    for (i=0; i<255; i++)
    {
    fpwm(120+(i/2), 255-i, 0);
    _delay_ms(C);
    };_delay_ms(D);
    for (i=0; i<255; i++)
    {
    fpwm(255, i/3, 0);
    _delay_ms(C);
    };_delay_ms(D);
    for (i=0; i<255; i++)
    {
    fpwm(255, 85+(i/3), 0);
    _delay_ms(C);
    };_delay_ms(D);
    for (i=0; i<255; i++)
    {
    fpwm(255, 255, i);
    _delay_ms(C);
    };_delay_ms(D);
    for (i=0; i<255; i++)
    {
    fpwm(255-i, 255, 255);
    _delay_ms(C);
    };_delay_ms(D);
    for (i=0; i<255; i++)
    {
    fpwm(0, 255-i, 255);
    _delay_ms(C);
    };_delay_ms(D);
    for (i=0; i<255; i++)
    {
    fpwm((i/2), 0, 255-i);
    _delay_ms(C);
    };_delay_ms(D);
    }
    
    }
    int skokowo(void) //skokowa zmiana kolorow
    {
    while(1)
    {
    fpwm(255,0, 0);
    _delay_ms(2000);
    fpwm(0, 255, 0);
    _delay_ms(2000);
    fpwm(0, 0, 255);
    _delay_ms(2000);
    }
    }
    int main(void)
    {
    GIMSK|=(1<<INT0); //zezwolenie na przerwanie int0
    sei(); //ogolne zezwolenie na przerwania
    
    switch(tryb)
    {
    	case 0:
    	plynnie();
    	case 1:
    	skokowo();
    }
    }
    
    [/quote]
  • REKLAMA
  • Pomocny post
    #2 9098753
    janbernat
    Poziom 38  
    Jak masz zamiar używać takich "konstrukcji" jak:
    _delay_ms(C);
    to i ATMega128 może się okazać za mała.
    Spróbuj wpisać na stałe 20 czy 2000.
  • REKLAMA
  • #3 9098790
    finger6
    Poziom 11  
    To było to :) Teraz kod zajmuje 1,7kB (chociaż, czy to nadal nie za dużo?) a nie 8kB :) Dzięki
  • REKLAMA
  • Pomocny post
    #5 9098953
    hotdog
    Poziom 26  
    Akurat nie o zmienne globalne chodzi...

    Chodzi o to że podając stałą do tych funkcji zostanie ona przeliczona na etapie kompilacji na ilość... napiszemy tików.

    Jeżeli natomiast podjesz zmienną do funkcji opóźnienia to niestety ale może ona z założenia może się zmienić w trakcie pracy programu i wtedy uC musi na żywo obliczyć ilość tych ticków. A jak dodamy że są to operacje dzielenia liczby typu float, to trzeba je zrobić sobie programowo, co zajmuje sporo pamięci.

    Cała tajemnica...

    Pozdro
  • Pomocny post
    #6 9099005
    JarekC
    Poziom 32  
    Witam,

    Przyczyn jest kilka:
    1.stosowanie procedury _delay_ms()
    Ponieważ procedura ta ma atrybut "always_inline" to w momencie gdy jej użyjesz w swoim programie nastąpi wstawienie całego kodu tej procedury w każdym miejscu jej użycia. Czyli użyjesz 20 razy to 20 razy zostanie powielony kod. Usunięcie _dalay_ms zmniejsza kod do ok 1800 bajtów.

    Ponieważ wywołujesz ją tylko z dwoma wartościami C i D. To możesz zadeklarować dwie procedury Delay1 i Delay2 w których będziesz się odwoływał do _delay_ms.

    W przypadku stałych korzystaj z #define.

    2. używanie int
    Do zmiennych które nie wykraczają za zakres 0-255 używaj "unsigned char" lub "uint8_t" (po dołączeniu stdint.h)


    Poniżej lekko poprawiony kod. Teraz zajmuje mniej niz 1200 bajtów.
    
    #define F_CPU 400000L
    #include <stdint.h>
    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    
    
    void fpwm(uint8_t red, uint8_t green, uint8_t blue);
    void plynnie (void);
    void skokowo (void);
    void Delay1 (void);
    void Delay2 (void);
    
    
    #define C 20
    #define D 2000
    
    volatile uint8_t  red, green, blue; //do funkcji fpwm
    volatile uint8_t tryb=0; //do wektora przerwan
    volatile uint8_t i;
    
    
    
    ISR(INT0_vect) //przerwanie int0
    {
      tryb=tryb+1;
      if (tryb==2)
        tryb=0;
    }
    
    void fpwm(uint8_t red, uint8_t green, uint8_t blue) //PWM
    {
     DDRB=0xff;
     TCCR0A|=(1<<COM0A1)|(1<<COM0A0)|(1<<WGM00);
     TCCR0B|=(1<<CS00);
     OCR0A=red;
     TCCR1A|=(1<<COM1A1)|(1<<COM1A0)|(1<<COM1B0)|(1<<COM1B1)|(1<<WGM10);
     TCCR1B|=(1<<CS10);
     OCR1A=green;
     OCR1B=blue;
    }
    
    
    void plynnie (void) //plynne zmienianie kolorow
    {
     while (1)
     {
      for (i=0; i<255; i++)
       {
        fpwm(0, 255, i);
        Delay1();
       };
       Delay2();
    
       for (i=0; i<255; i++)
        {
         fpwm(i, 255-i, 255);
         Delay1();
        };
       Delay2();
    
       for (i=0; i<255; i++)
        {
         fpwm(255-i, i, 255-i);
         Delay1();
        }
       Delay2();
    
       for (i=0; i<255; i++)
        {
         fpwm(i, 255-i, 0);
         Delay1();;
        };
       Delay2();
    
       for (i=0; i<255; i++)
        {
         fpwm(255, 0, i);
         Delay1();;
        };
       Delay2();
    
       for (i=0; i<255; i++)
        {
         fpwm(255-(i/2), (i/4), 255);
        };
       Delay2();
    
       for (i=0; i<255; i++)
        {
         fpwm(120, 65+(i/3), 255-i);
         Delay1();;
        };
       Delay2();
    
       for (i=0; i<255; i++)
        {
         fpwm(120+(i/2), 255-i, 0);
         Delay1();;
        };
       Delay2();
    
       for (i=0; i<255; i++)
        {
         fpwm(255, i/3, 0);
         Delay1();;
        };
       Delay2();
    
       for (i=0; i<255; i++)
        {
         fpwm(255, 85+(i/3), 0);
         Delay1();;
        };
       Delay2();
    
       for (i=0; i<255; i++)
        {
         fpwm(255, 255, i);
         Delay1();;
        };
       Delay2();
    
       for (i=0; i<255; i++)
        {
         fpwm(255-i, 255, 255);
         Delay1();;
        };
    
       Delay2();
    
       for (i=0; i<255; i++)
        {
         fpwm(0, 255-i, 255);
         Delay1();;
        };
       Delay2();
    
       for (i=0; i<255; i++)
        {
         fpwm((i/2), 0, 255-i);
         Delay1();;
        };
       Delay2();
      }
    }
    
    
    void skokowo(void) //skokowa zmiana kolorow
    {
     while(1)
      {
       fpwm(255,0, 0);
       Delay2();
    
       fpwm(0, 255, 0);
       Delay2();
    
       fpwm(0, 0, 255);
       Delay2();
      }
    }
    
    
    void Delay1 (void)
     {
      _delay_ms (C);
     }
    
    
    void Delay2 (void)
     {
      _delay_ms (D);
     }
    
    int main(void)
    {
     GIMSK|=(1<<INT0); //zezwolenie na przerwanie int0
     sei(); //ogolne zezwolenie na przerwania
    
     switch(tryb)
      {
       case 0:
       plynnie();
       case 1:
       skokowo();
      }
    
    
    } 
    
    



    Pozdrawiam
    JarekC
  • REKLAMA
  • #7 9099436
    janbernat
    Poziom 38  
    A tak naprawdę zacznij używać timerów.
    A nie _delay() jako wytrychu.
    Kup sobie książkę http://atnel.pl/wydawnictwo .
    Warto.
    Jawna reklama.
    Ale link nie jest tymczasowy.
  • #8 9099520
    finger6
    Poziom 11  
    Obu timerów używam do generowania PWM, można je wykorzystać jeszcze do opóźnień ? Albo lepiej, do generowania przerwań, w których sprawdzał bym stan przycisku (zamiast przerwania INT0). A na tą książkę już odkładam kase ;)

    Dzięki wszystkim za pomoc.
  • #9 9099687
    janbernat
    Poziom 38  
    No jak "za ciasno" z timerami to można zrobić PWM programowy.
    Wtedy jeden timer do teoretycznie dowolnej ilości PWM.
    I tym samym timerem sprawdzasz stan przycisku.
    Zaczyna się na str.395 książki.
  • #10 9102427
    Electix
    Poziom 21  
    Hej! :)
    Ja bym na miejscu kolegi przyjrzał się realizacji choćby płynnej zmiany kolorów. Jest to strasznie długa funkcja gdzie pewne operacje powtarzane są wielokrotnie i to też ma wpływ na objętość kodu. Ja kiedyś też robiłem lampkę z jednym przyciskiem na ATtiny2313 i mi cały program zajął około 500b i miał mniej niż 100 linii. A sekret tkwił w tym, że realizację ściemniania, rozjaśniania dla poszczególnych kolorów napisałem w jednej funkcji. Podając do niej jako parametr kolor i czy ma ściemniać czy rozjaśniać. Oczywiście nie obejdzie się tu bez użycia wskaźników, ale właśnie one po to są :)
    dla przykładu:
    
    void lightc(volatile uint8_t * color, _Bool dimmer)
    {
    	switch (dimmer)
    	{
    		case 0:
    				for(; *color>0x00; (*color)--) _delay_ms(czas);
    				*color=0x00;
    				break;
    		case 1:
    				for(; *color<0xFF; (*color)++) _delay_ms(czas);
    				*color=0xFF;
    				break;
    	}
    }
    
    void teczas(void)
    {
    	lightc(&RLED, Brighten);
    	_delay_ms(czas);
    	lightc(&BLED, Dim);
    	_delay_ms(czas);
    	lightc(&GLED, Brighten);
    	_delay_ms(czas);
    	lightc(&RLED, Dim);
    	_delay_ms(czas);
    	lightc(&BLED, Brighten);
    	_delay_ms(czas);
    	lightc(&GLED, Dim);
    	_delay_ms(czas);
    }


    tu masz zrealizowaną całą tęczę :)
REKLAMA