Ein Haup-Batzen dürfte die Verwendung von float sein.

Nimm zB folgendes Progrämmchen:

Code:
float a, b, c, d;

void foo ()
{
        a = b*d - a/c;
}

int main()
{
	while (1);
}
Und übersetz es wie gewohnt mit "avr-gcc -mmcu=atmega8 -Os -o float.elf float.c"

Dann schauen wir auf die Größe mit "avr-size float.elf"
Code:
   text    data     bss     dec     hex filename
   2730       8      16    2754     ac2 float.elf
Der ATmega8 ist also schon zu 1/3 voll. Wo die draufgehen sieht man mit "avr-nm -S --size-sort float.elf"
Code:
00800074 00000004 B a
00800068 00000004 B b
0080006c 00000004 B c
00800070 00000004 B d
00800060 00000008 D __thenan_sf
000000f8 0000000a T main
00000346 00000056 T __addsf3
0000039c 0000005e T __subsf3
0000005c 0000009c T foo
00000948 000000f4 T __unpack_f
00000626 00000156 T __divsf3
0000077c 000001cc T __pack_f
000003fa 0000022c T __mulsf3
00000102 00000244 t _fpadd_parts
In die zweiten Spalte stehen die Größen der Objekte (Bytes in hex). Das __*-Zeug kommt von der float-Software die dazugelinkt werden muss, weil AVR keine float/double Hardware-Unterstützung hat.

Wenn du die Größen deiner Funktionen so auflistet, erkennt man wo am meisten Platz verbraucht wird und wo eine Optimierung am meisten bringt.

Die Optimierungsstufe von avr-gcc sollte -Os sein. -O0 oder -O3 sind keinesfalls ratsam.

Ansonsten hilft, mehrfach verwendete Sachen in eigene Funktionen zu packen. Damit kann der Code wiederverwendet werden und muss nicht jedesmal mit leicht anderen Parametern erzeugt werden.

Code:
//-----------------------------------------------------------------------------------------------------------------     
// Titel : LCD 4x16 zeigt die Uhrzeit an für Testschaltung MYAVR
//-----------------------------------------------------------------------------------------------------------------     
// Prozessor    : ATmega8
// Takt                 : 3686400 Hz
// Sprache              : C
// Datum                : 10.04.2008
// Version              : 1.0
// Autor                : 
//-----------------------------------------------------------------------------------------------------------------     
#include <avr/io.h>
#ifndef  F_CPU
#define  F_CPU 3686400UL                                                                                // Quarz mit 3.6864 Mhz
#endif
#include <util/delay.h>                                                                                 // definiert _delay_ms() Warteschleife 
#include "i2cmaster.h"
#include <stdlib.h>
#include <string.h>
#define DS13   0xd0                                                                                              // device address of Realtime Clock DS1307, see datasheet
char i; 


/////////////////////////////////////////////////////////////////////////////
// Uhr
/////////////////////////////////////////////////////////////////////////////

// Schreibt 'num' gefolgt von 'c' an position line:pos (zeile:spalte)
void lcd_write_num (unsigned char line, unsigned char pos, unsigned char num, char c)
{
        unsigned char digit;
        static char buf[4];
        
        buf[2] = c;
        buf[3] = 0;
        new_line (line, pos);           // legt die Zeile, und dann die Spalte fest 
        
        digit = num >> 4;
        buf[0] = digit + '0';
        
        digit = num & 0xf;
        buf[1] = digit + '0';
}        

static const char * day_of_week[] = 
{ 
        "Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"
};

void Uhr2()
{
        i2c_init();                                                             // initialize I2C library
        unsigned char sek, min, std, day, date, month, year;                                           // Typ char gibt Sekunde,Minute,Stunde,Wochentag,Tag den,Monat,Jahr.
        unsigned char i;
        
        for (i=1; i<30; i=i+1)
        {
                        _delay_ms(250);
        
//-----------------------------------------------------------------------------------------------------------------
//                      Daten Auslesen des Realtime Clock DS 1307
//-----------------------------------------------------------------------------------------------------------------                     
                        i2c_start_wait(DS13+I2C_WRITE);                         // setzt die Adresse vom DS13 und den schreiben mode
                        i2c_write(0x00);                                // schreibe Address = 0 liegt Wert Zeitdaten
                        i2c_rep_start(DS13+I2C_READ);                           // setzt die Adresse vom DS13 und den lese mode
                        sek = i2c_readAck();                                    // lese den Inhalt von Adresse 0 Sekunden               
                        min = i2c_readAck();                                    // lese den Inhalt von Adresse 1 Minuten
                        std = i2c_readAck();                                    // lese den Inhalt von Adresse 2 Stunden
                        day = i2c_readAck();                                    // lese den Inhalt von Adresse 3 WochenTag
                        date = i2c_readAck();                                   // lese den Inhalt von Adresse 4 Tag den
                        month = i2c_readAck();                                  // lese den Inhalt von Adresse 5 Monate
                        year = i2c_readNak();                                   // lese den Inhalt von Adresse 6 Jahre                                  
                        i2c_stop();                                                                     // Ende des einlesens
//-----------------------------------------------------------------------------------------------------------------
//                      LCD Hintergundbeleuchtung einschalten.
//                      Ausgabe der Stunden auf das LCD Display.
                        lcd_write_num (2, 5, std, ':');
//-----------------------------------------------------------------------------------------------------------------
//                      Ausgabe der Minuten auf das LCD Display.
                        lcd_write_num (2, 8, min, ':');
//-----------------------------------------------------------------------------------------------------------------
//                      Ausgabe der Sekunden auf das LCD Display.
                        lcd_write_num (2, 11, sek, 0);
//-----------------------------------------------------------------------------------------------------------------
//                      Ausgabe der Wochentage auf das LCD Display.
                        if (day >= 1 && day <= 7)
                        {
                                new_line(1,2);                                                          // legt die Zeile, und dann die Spalte fest                                             
                                lcd_write (day_of_week[day-1]);
                        }        
//-----------------------------------------------------------------------------------------------------------------
//                      Ausgabe der Tages auf das LCD Display.
                        lcd_write_num (1, 7, date, '.');
//-----------------------------------------------------------------------------------------------------------------
//                      Ausgabe die Monate auf das LCD Display.
                        lcd_write_num (1, 10, month, '.');
//-----------------------------------------------------------------------------------------------------------------
//                      Ausgabe der Jahre auf das LCD Display.
                        lcd_write_num (1, 13, year, 0);
        }
}

//-----------------------------------------------------------------------------------------------------------------
Code:
deep-thought> avr-nm -S --size-sort uhr.o
00000001 00000001 C i
00000000 00000004 b buf.0
00000015 0000000e d day_of_week
0000033e 0000002e T lcd_write_num
0000036c 000000c0 T Uhr2
00000000 0000033e T Uhr
Das ist nicht nur übersichtlicher, sondern auch etwas kleiner (256 Bytes anstatt 830, und itoa ist noch net mitgerechnet).