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

[Rozwiązano] [ATMega48][C][AVR] Optymalizacja kodu, brakuje miejsca.

qscgu 15 Sty 2011 15:39 2721 7
REKLAMA
  • #1 9009345
    qscgu
    Poziom 34  
    Witam,

    Napisałem sobie kod dla woltomierza na ADS1110 i chciałbym go wyświetlić na ekranie jednak brakuje mi może 100bajtów w pamięci - używam Atmega48, kod wynikowy zajmuje 4224 bytes (103.1% Full)
    Czyli za dużo. Da się coś z tym zrobić? Używam 4 dzielników napięć przełączanych przekaźnikami i stąd te mnożniki w programie.

    Kod działa jeśli usunę mnożniki i robi się prawie 1K wolnego miejsca. Czemu tak to jest??

    Może wpleść assemblera w kod C ? Może da się gdzieś indziej zaoszczędzić te bajty?

    Używam dwóch bibliotek ze strony radzio.dxp.pl:
    HD44780:
    http://radzio.dxp.pl/hd44780/hd44780_avr_4-bit_norw_c.htm
    Oraz TWI:
    http://radzio.dxp.pl/twi/

    Mój kod:
    
    #include <avr/io.h> 
    #include <util/delay.h> 
    #include <stdlib.h>
    #include "twi.h"
    #include "HD44780.h"
    
    #define DeviceWrite  0b10010000 //adres ADS1110
    #define DeviceRead  0b10010001 //adres ADS1110
    
    void io_init(void)
    {
    	DDRD = 0b00000000;
    	PORTD = 0b00000001;
    	DDRB = 0b00000000;
    	PORTB = 0b11000001;
    	DDRC = 0b00000111;
    	PORTC = 0b00000000;
    }
    
    
    int main(void) 
    { 
    	unsigned char High;
    	unsigned char Low;
    	float nap;
    //	float mult = 1;
    	unsigned char mode = 0; 
    	char wynik[8];  
    	unsigned char changed = 0; 
    
    	io_init();  
        LCD_Initalize();
    	LCD_GoTo(0,0);
    	LCD_WriteText("Div1 V: ");
    
       	while(1) 
       	{ 
    		twistart(); 
    		twiwrite(DeviceRead);
    
    		High = twiread(ACK);
    		Low  = twiread(NOACK);
    
    		twistop();
    
    		
    		if(bit_is_clear(PIND, PD0)) {
    			//Pierwszy button
    			mode = 0;
    			nap = (Low | (High << 8)) * ( 2.048 / 32768);
    			changed = '1';
    			PORTC = 0b00000000;
    		} else
    		if(bit_is_clear(PINB, PB0)) {
    			//Drugi button
    			mode = 1;
    			nap = (Low | (High << 8)) * ( 2.048 * 5 / 32768);
    			changed = '2';
    			PORTC = 0b00000001;
    		} else
    		if(bit_is_clear(PINB, PB7)) {
    			//Trzeci button
    			mode = 2;
    			nap = (Low | (High << 8)) * ( 2.048 * 10 / 32768);
    			changed = '3';
    			PORTC = 0b00000110;
    		} else
    		if(bit_is_clear(PINB, PB6)) {
    			//Czwarty button
    			mode = 3;
    			nap = (Low | (High << 8)) * ( 2.048 * 150 / 32768);
    			changed = '4';
    			PORTC = 0b00000111;
    		}
    
    		if (changed > 0) {
    			LCD_GoTo(3,0);
    			LCD_WriteData(changed);
    			changed = 0;
    		}
    
    		dtostrf(nap,8,6,wynik);
    
    		LCD_GoTo(0,1);
    		LCD_WriteText(wynik);
    
    		_delay_ms(50);
    
       	}
    
    }	
    
  • REKLAMA
  • #2 9009399
    tmf
    VIP Zasłużony dla elektroda
    Hmm, na oko ten program da się zmieścić w poniżej 1kB :) Wybal te float, bo jest do niczego niepotrzebny i zrób wszystko na arytmetyce stałopozycyjnej.
  • REKLAMA
  • #3 9009435
    janbernat
    Poziom 38  
    A zwłaszcza że 32768 dec to jest 1000 0000 0000 0000 bin albo 8000 hex.
    Nie przypadkowo ta częstotliwość kwarcu jest w zegarkach.
  • REKLAMA
  • #4 9010050
    qscgu
    Poziom 34  
    jak zrobić to na stałopozycyjnej arytmetyce?

    Szczególnie mnożniki napięć?

    Do tego miejsca

    
     nap = (Low | (High << 8))
    

    otrzymujemy wynik pomiaru. Potem standardowo musimy go pomnożyć przez 2.048 bo tyle wynosi napięcie referencyjne czyli teoretycznie można pomnożyć przez 2048

    (Low | (High << 8)) * 2048 co nam daje maksymalną wartość unsigned 134217728 lub signed: -67108864 do +67108864.

    czyli zmieścimy się do 32bitów bo uns long int to +/-2147483648.

    No i teraz powinniśmy podzielić wynik przez 32768...

    I tutaj się już gubię :)

    możecie mi chociaż tok myślowy pokazać jak to powinienem obrobić żeby dostać odpowiedni wynik?

    EDIT:

    Można by teoretycznie napisać funkcję która dzieli dwie liczby zwraca liczbę stałą po zwykłym dzieleniu czyli

    wynik = wynik_konwersji * 2048 * dzielnik;

    przed przecinkiem:
    wynik_przed = wynik / (32768*1000);
    po przecinku mamy tak:
    reszta = wynik - wynik_przed * (32768*1000);

    i teraz jakaś iteracja dzieląca dalej...
  • #5 9010350
    LordBlick
    VIP Zasłużony dla elektroda
    2048 /32768=1/16... Generalnie wszystkie stałe należy uprościć, aby procesor nimi nie młócił niepotrzebnie...
  • #6 9010400
    qscgu
    Poziom 34  
    udało mi się chyba, za moment edytuje post i wkleje iterator dzielący na ilośc miejsc po przecinku. W sumie to zwykłe dzielenie jakie wykonuje ludzki mózg tylko przełożone na procesor.
  • REKLAMA
  • #7 9010470
    asembler
    Poziom 32  
    qscgu napisał:
    udało mi się chyba, za moment edytuje post i wkleje iterator dzielący na ilośc miejsc po przecinku. W sumie to zwykłe dzielenie jakie wykonuje ludzki mózg tylko przełożone na procesor.

    Ciekawe jak ten ludzki koprocesor działa.
  • #8 9010538
    qscgu
    Poziom 34  
    Ok mam coś takiego:

    #include <avr/io.h> 
    #include <util/delay.h> 
    #include <stdlib.h>
    #include <inttypes.h>
    #include "twi.h"
    #include "HD44780.h"
    
    #define DeviceWrite  0b10010000 //adres ADS1110
    #define DeviceRead  0b10010001 //adres ADS1110
    
    void io_init(void)
    {
    	DDRD = 0b00000000;
    	PORTD = 0b00000001;
    	DDRB = 0b00000000;
    	PORTB = 0b11000001;
    	DDRC = 0b00000111;
    	PORTC = 0b00000000;
    }
    
    
    int main(void) 
    { 
    	unsigned char High;
    	unsigned char Low;
    	unsigned char mode = 0; 
    	unsigned char changed = 0; 
    	int Rezultat = 0;		//rezultat konwersji * 1000 * 2.048 * mnożnik
    	int przedPrzecinkiem = 0;		//przed przecinkiem
    	int reszta = 0;			//reszta z dzielenia
    	unsigned char chars = 0;	//ilośc mniejsc po przecinku
    	char buffer[4];
    
    	io_init();  
        LCD_Initalize();
    	LCD_GoTo(0,0);
    	LCD_WriteText("Div1 V: ");
    
       	while(1) 
       	{ 
    		twistart(); 
    		twiwrite(DeviceRead);
    
    		High = twiread(ACK);
    		Low  = twiread(NOACK);
    
    		twistop();
    
    		//Rezultat = (Low | (High << 8)) * 2048;
    		Rezultat = (Low | (High << 8));
    
    		if(bit_is_clear(PIND, PD0)) {
    			//Pierwszy button
    			mode = 0;
    			Rezultat *=  1; 
    			changed = '1';
    			PORTC = 0b00000000;
    			chars = 5;
    		} else
    		if(bit_is_clear(PINB, PB0)) {
    			//Drugi button
    			mode = 1;
    			Rezultat *=  5;
    			changed = '2';
    			PORTC = 0b00000001;
    			chars = 4;
    		} else
    		if(bit_is_clear(PINB, PB7)) {
    			//Trzeci button
    			mode = 2;
    			Rezultat *=  10;
    			changed = '3';
    			PORTC = 0b00000110;
    			chars = 4;
    		} else
    		if(bit_is_clear(PINB, PB6)) {
    			//Czwarty button
    			mode = 3;
    			Rezultat *=  150;
    			changed = '4';
    			PORTC = 0b00000111;
    			chars = 3;
    		}
    
    		if (changed > 0) {
    			LCD_GoTo(3,0);
    			LCD_WriteData(changed);
    			changed = 0;
    		}
    
    		LCD_GoTo(0, 1);
    		przedPrzecinkiem = (int)(Rezultat / 16000);
    		
    		itoa( przedPrzecinkiem, buffer, 10);
    
    		LCD_WriteText(buffer);
    		LCD_WriteText(".");
    		reszta = Rezultat - przedPrzecinkiem * 16000;
            reszta *= 10;
    
            for (unsigned char i = 0; i < 5; i++)
            {
                if (reszta < 16000)
                {
                    reszta *= 10;
                    LCD_WriteNumber(0);
                }
                else
                {
                    unsigned char hm = (reszta / 16000);
                    LCD_WriteNumber(hm);
                    reszta = reszta - (hm * 16000);
                    reszta *= 10;
                }
            }
    
    		LCD_GoTo(7,1);
    		LCD_WriteNumber('V');
    
    		_delay_ms(50);
    
       	}
    
    }	
    
    


    OK kod skompilowany, program zajmuje 1176B, kosmos normalnie. Dzięki za pomoc. Zastowie wątek przez jakiś czas otwarty jakby ktoś chciał coś dodać a na razie zajmuje się testowaniem mojego cuda.

    PS. Algorytm przetestowałem na C# .NET więc myślę że tu też będzie działać.
REKLAMA