C-Programmierung mit AVR-GCC/ Hello World


In der Programmierung ist es üblich mit einem einfachen Beispiel anzufangen, um die Basics zu lernen. Das bekannteste Beispielprogramm ist das "Hello World"-Programm. Anhand dieses kleinen Beispiels möchte ich verdeutlichen, wie du eigne Programme übersetzen und auf einen Mikrocontroller programmieren kannst.

/* 
 * File: blink.c
 * Description: Toggels pin PB0 every 500ms
 * From: C-Programmierung mit AVR-GCC
 */

#define F_CPU 8000000UL

#include <avr/io.h>
#include <util/delay.h>

int main (void) {

   DDRB |= (1 << PB0);

   while(1) {
       PORTB ^= (1 << PB0);
       _delay_ms(500);
   }

   return 0;
}

Nehmen wir einmal an wir haben obiges Programm geschrieben und möchten es auf unserem Mikrocontroller einsetzen. Das Programm ist natürlich sehr rudimentär, trotzdem ist es geeignet die ersten Gehversuche beim Übersetzen und Programmieren zu wagen.

Übersetzen Bearbeiten

Als erstes muss unser Programm übersetzt werden. Dazu müssen wir den Compiler aufrufen und ihm unsere Quelltextdatei übergeben. Ich werde im folgenden den Ablauf unter Ubuntu zeigen. Unter Windows funktionieren die Konsolenbefehle allerdings genauso.

Im Terminal navigieren wir zuerst zum Verzeichnis, in dem die Quellcodedatei liegt. Danach führen wir folgenden Befehl aus.

avr-gcc -mmcu=atmega328p -Os -c blink.c -o blink.o

Mit diesem Befehl erstellen wir aus unserem Quelltext ein Object-File. Dabei wird die Syntax unseres Programms geprüft und gleichzeitig optimiert, damit wir bestmöglich den Speicherplatz im Controller ausnutzen können. Daher ist auch die Angabe der verwendeten Version des Controllers wichtig. In diesem Beispiel kompilieren wir für den Arduino Uno, welcher auf einem ATMega328P aufgebaut ist.

Als nächstes werden die einzelnen Object-Files gelinkt. Das bedeutet, dass alle Programmteile nun zu einem einzelnen Programm verbunden werden. Dies geschieht ebenfalls wieder mit avr-gcc.

avr-gcc blink.o -o blink.elf

Hier muss der verwendete Mikrocontroller und die Optimierungsanweisung nicht mehr angegeben werden. Es entsteht eine ELF-Datei, die alle Programmteile enthält. Um den Mikrocontroller mit einem Programmer zu konfigurieren benötigen wir aber noch eine Datei, die auch von der Programmiersoftware (avrdude) gelesen werden kann.

avr-objcopy -O ihex -j .text -j .data blink.elf blink.hex

Die ELF-Datei wird mit diesem Kommando in eine Textdatei im Intel-Hex Format übersetzt.

Speicherverbrauch testen Bearbeiten

Der Compiler bietet auch die Möglichkeit, den Speicherverbrauch für das Programm zu ermitteln. Dies ist nützlich gerade, wenn du sicher gehen willst, dass dein Programm auch in den verfügbaren Speicher deines Controllers passt.

avr-size --mcu=atmega328p -C blink.elf

Dieses Kommando listet dir übersichtlich auf, welche Speicher wie ausgelastet sind.

AVR Memory Usage
----------------
Device: atmega328p

Program:      30 bytes (0.1% Full)
(.text + .data + .bootloader)

Data:          0 bytes (0.0% Full)
(.data + .bss + .noinit)

Für unser Beispielprogramm beträgt der Speicherverbrauch also gerade einmal 30 Bytes und lastet den Speicher lediglich zu 0,1% aus. Eingangs hatte ich ja schon die etwas eingeschränkten Ressourcen angesprochen. Hier wird jetzt deutlich, dass die vermeintliche Einschränkung eigentlich gar keine ist.

Programm übertragen Bearbeiten

Nun wollen wir mithilfe eines Programmers und avrdude das Programm auch auf den Mikrocontroller laden.

avrdude -p m328p -c arduino -U flash:w:blink.hex:a

Teilweise ist es zusätzlich nötig die verwendete PC-Schnittstelle (USB, Seriell, ...) oder die Baudrate einzustellen.

avrdude -p m328p -c arduino -B 115200 -P /dev/ttyS0-U flash:w:blink.hex:a

Schließt man beispielsweise jetzt eine LED an den Pin PB0 an, blinkt diese im Takt von 500ms.