C-Programmierung mit AVR-GCC/ Makefile

Aus Wikibooks
Zur Navigation springen Zur Suche springen

Das Kompilieren von Hand ist eine mühevolle Arbeit. Es gibt aber auch die Möglichkeit das zu automatisieren. Mithilfe des Tools make lassen sich die Quelldateien automatisch kompilieren und auch auf den Mikrocontroller programmieren.

Wenn man bisher gewohnt ist, mit integrierten Entwicklungsumgebungen à la Visual-C Programme zu erstellen, wirkt das makefile-Konzept auf den ersten Blick etwas kryptisch. Nach kurzer Einarbeitung ist diese Vorgehensweise jedoch sehr praktisch. Diese Dateien (üblicher Name: 'Makefile' ohne Dateiendung) dienen der Ablaufsteuerung des Programms make, das auf allen Unix/Linux-Systemen installiert sein sollte, und in einer Fassung für Windows auch im WinAVR Unterverzeichnis utils/bin enthalten ist.

Ist im Makefile alles richtig eingestellt, genügt es, sich drei Parameter zu merken, die über die shell bzw. die Windows-Kommandozeile (cmd.exe/command.com) als Parameter an "make" übergeben werden. Das Programm make sucht sich "automatisch" das Makefile im aktuellen Arbeitsverzeichnis und führt die darin definierten Operationen für den entsprechenden Aufrufparameter durch.

Kommando
make all Erstellt aus den im Makefile angegebenen Quellcodes eine hex-Datei (und ggf. auch eep-Datei).
make program Überträgt die hex-Datei (und wahlweise auch die eep-Datei für den EEPROM) zum AVR.
make clean löscht alle temporären Dateien, also auch die hex-Datei

Diese Aufrufe können in die allermeisten Editoren in "Tool-Menüs" eingebunden werden. Dies erspart den Kontakt mit der Kommandozeile. Bei WinAVR sind die Aufrufe bereits im Tools-Menü des mitgelieferten Editors Programmers-Notepad eingefügt. Eclipse greift ebenfalls auf diese Standardaufrufe zu und bindet diese in den Build-Prozess ein.

Variablen setzen[Bearbeiten]

Um unser Makefile komfortabel auch in anderen Projekten einsetzen zu können, definieren wir einige Variablen, die von Projekt zu Projekt angepasst werden. Eine Variablendefinition geschieht sehr einfach. Folgendes Beispiel zeigt, wie du die Baureihe deines AVR einstellst.

MCU = atmega328p

Wir definieren für jeden Parameter eine Variable, der sich zu einem anderen Projekt unterschieden kann. Diese Variablen werden an den Anfang der Datei gestellt.

TARGET=blink
MCU=atmega328p
SOURCES=blink.c lib.c

PROGRAMMER=arduino
#auskommentieren für automatische Wahl
PORT=-P/dev/ttyS0
BAUD=-B115200

TARGET gibt den Namen der fertigen HEX-Datei an. MCU bezeichnet wie oben schon erwähnt den Mikrocontroller. SOURCES ist eine durch Leerzeichen getrennte Liste aller C-Quelldateien, die in unserem Projekt verwendet werden. PROGRAMER gibt an, welchen Programmertyp wir für die Programmierung des AVR verwenden möchten. Manchmal ist es nötig Port und Baudrate für avrdude anzugeben. Das kannst du mit PORT und BAUD tun.

Jetzt folgen noch einige Regeln, die den Quelltext kompilieren und in eine HEX-Datei schreiben. Eine Regel programmiert den erstellen Code auf den AVR. Da sich dieses Buch zum Großteil mit der Programmierung unter AVR-GCC beschäftigt, soll hier nicht näher auf den Inhalt des Makefiles eingegangen werden. Wer sich umfassender mit make beschäftigen möchte, kann sich auf der Seite von Michael Becker http://www.ijon.de/comp/tutorials/makefile.html informieren.

Das Makefile[Bearbeiten]

Hier nochmal das komplette Makefile zum herunterladen. Du kannst es so in eigenen Projekten verwenden.

TARGET=blink
MCU=atmega328p
SOURCES=blink.c

PROGRAMMER=arduino
#auskommentieren für automatische Wahl
PORT=-P/dev/ttyS0
BAUD=-B115200

#Ab hier nichts verändern
OBJECTS=$(SOURCES:.c=.o)
CFLAGS=-c -Os
LDFLAGS=

all: hex eeprom

hex: $(TARGET).hex

eeprom: $(TARGET)_eeprom.hex

$(TARGET).hex: $(TARGET).elf
	avr-objcopy -O ihex -j .data -j .text $(TARGET).elf $(TARGET).hex

$(TARGET)_eeprom.hex: $(TARGET).elf
	avr-objcopy -O ihex -j .eeprom --change-section-lma .eeprom=1 $(TARGET).elf $(TARGET)_eeprom.hex

$(TARGET).elf: $(OBJECTS)
	avr-gcc $(LDFLAGS) -mmcu=$(MCU) $(OBJECTS) -o $(TARGET).elf

.c.o:
	avr-gcc $(CFLAGS) -mmcu=$(MCU) $< -o $@

size:
	avr-size --mcu=$(MCU) -C $(TARGET).elf

program:
	avrdude -p$(MCU) $(PORT) $(BAUD) -c$(PROGRAMMER) -Uflash:w:$(TARGET).hex:a

clean_tmp:
	rm -rf *.o
	rm -rf *.elf

clean:
	rm -rf *.o
	rm -rf *.elf
	rm -rf *.hex