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).
Lesezeichen