Startseite

AVR Hello World! Vorlage

Dies ist eine Kopiervorlage zum Starten neuer Projekte. Es gibt "Hello World" auf die serielle Konsole aus und lässt eine LED blinken. Außerdem stellt es einen Millisekunden-Zähler bereit.

HelloWorld.zip nutzt den Hardware UART bidirektional. Für ATtiny 2313, 4313, sowie ATmega 48, 88, 164, 168, 324, 328, 640, 644, 1280, 1281, 1284, 2560, 2561 und einige ATxmega.

HelloTiny.zip mit soft-serial Emulation, nur Ausgabe. Für ATtiny 14, 25, 44, 45, 84, 85, 261, 441, 461, 841, 861, 2313, 4313 sowie ATmega 48, 88, 164, 168, 324, 328, 640, 644, 1280, 1281, 1284, 2560, 2561.

Wahrscheinlich werden zufällig noch mehr Modelle unterstützt.

Das Projekt wird ganz klassisch mit einem Makefile compiliert, so dass du die freie Wahl hast, ob und welche Entwicklungsumgebung du verwenden willst. Ein einfacher Text-Editor tut es auch. Auf der Seite AVR Entwicklungsumgebungen findest du die nötigen Downloads. Die Dokumentation der AVR C Bibliothek findest du dort.

Anwendungsbeispiel:

int main(void) 
{
    initSerialConsole();
    initSystemTimer();
    
    while(1)
    {
        delay(500);
        led_on();
        puts_P(PSTR("Hello World"));

        delay(500);
        led_off();
        printf("%d",milliseconds());
    }
}

Das Ausgeben von Text mit puts und printf ist bei der Fehlersuche sehr hilfreich. Mikrocontroller mit UART können auch Text empfangen, so dass praktisch alle Funktionen der stdio.h Library mit der seriellen Konsole verwendbar sind. Timer 0 wird benutzt, um Millisekunden zu zählen. Man kann sowohl den Timer als auch die Konsole einfach entfernen, wenn sie nicht benötigt werden.

Probeaufbau

In den folgenden Absätzen beschreibe ich einen Probeaufbau, mit dem du das Hello-World Projekt testen kannst. Ich glaube es eignet sich gut für Anfänger, um sich mit den Tools vertraut zu machen. Deswegen beschreibe ich den Aufbau sehr detailliert.

Schaltung

Zur Stromversorgung benutze ich drei NiMh Akkus oder eine LiIo Zelle an VCC und GND.

Verbinde den ISP Programmierdapter mit den Pins SCK, MISO, MOSI, RESET, VCC und GND.

USB-UART Kabel

Mit einem sogenannten USB-UART Kabel verbinde ich den seriellen Port des Mikrocontrollers mit meinem Computer. Dort starte ich ein Terminal-Programm, welches die übertragenen Texte in einem Fenster anzeigt. Auf diese Weise kann ich mit puts oder printf Meldungen ausgeben, die mir helfen, die Funktion des Programmes zu untersuchen.

Du brauchst für die vorliegende Schaltung nur zwei Drähte anzuschließen:

Manche USB-UART Kabel (z.B. mit PL2303 und CP2102 Chip) liefern 3,3 Volt Pegel an den Ausgängen und tolerieren 5 Volt an den Eingängen. Diese benutze ich am liebsten.

Makefile

Das Programm make hat die Aufgabe, herauszufinden, welche Dateien verändert wurden um dementsprechend den Compiler aufzurufen. Anstatt immer den gesamten Quellcode zu compilieren, macht make das nur für die Dateien, wo es benötigt wird. Schaue dir mal den oberen Teil des Makefiles vom Hello-World Projekt an:

# Makefile for this AVR project

# make clean      Delete all generated files
# make code       Compiles the source code
# make fuses      Program fuses
# make program    Program flash and eeprom

# Programmer hardware settings for avrdude
AVRDUDE_HW = -c avrispmkII -P usb -B16

# Name of the program without extension
PRG = HelloWorld

# Microcontroller type and clock frequency
MCU = attiny2313
F_CPU = 1000000

# Optional fuse settings, for example
# LFUSE = 0x64
# HFUSE = 0xDF
# EFUSE = 0xFF

# Objects to compile (*.c and *.cpp files, but with suffix .o)
OBJ = driver/serialconsole.o driver/systemtimer.o main.o

Hier stehen zuerst Hinweise, mit welchen Parametern man "make" aufrufen kann. Zum Beispiel gebe make code ein, um den Quelltext zu compilieren. Als Ergebnis kommt eine HEX Datei heraus, die den für den Mikrocontroller ausführbaren Maschinencode enthält.

Mit make program überträgt man die Firmware in den Mikrocontroller. Dabei wird Avrdude aufgerufen. Damit Avrdude die richtigen Aufrufparameter für deinen Programmieradapter erhält, gebe diese im Makefile mit AVRDUDE_HW = ... an.

Mit make fuses "brennt" man die Fuses entsprechend der angegebenen Fuse settings. Du solltest die Fuses nur dann brennen, wenn du ganz sicher bist, dass die angegebenen Werte richtig sind. Denn bei falschen Werten passiert es allzu leicht, das der Mikrocontroller unbrauchbar wird. Und Achtung: Werte die für einen Chip richtig sind, können für einen anderen Chip völlig falsch sein. Denn die Bedeutung der einzelnen Bits ist bei jedem Mikrocontroller-Typ anders.

Für das vorliegende Hello-World Projekt brauchst du die Fuses nicht zu setzen. Die Vorgabewerte, mit denen der Chip verkauft wird, sind bereits passend. Die Online Fuse-Kalkulatoren von Engbedded und Eleccelator helfen bei der Berechnung der Hexadezimalzahlen.

Mit dem Befehl make clean entfernst du alle vom Compiler erzeugten Dateien wieder.

Die Schlüsselwörter "code", "program", "fuses" und "clean" heissen in der Sprache von make "Targets". Etwas weiter unten im Makefile findest du für jedes Target einen Block Anweisungen, was dabei passieren soll. Diese Anweisungen musst du nicht unbedingt im Detail verstehen. Freue dich einfach darüber, hiermit eine funktionierende Vorlage zu haben, die du nach Bedarf anpassen kannst.

Man kann übrigens mehrere Targets mit einem Befehl abarbeiten, zum Beispiel: make clean code program. Wenn du einfach nur make ohne Parameter eingibst, wird immer das erste Target ausgeführt, was in diesem Fall "code" ist.

Mit PRG = HelloWorld gibst du dem Projekt einen Namen. Dementsprechend heißt die erzeugte HEX Datei HelloWorld.hex.

Mit MCU=... und F_CPU=... gibst du an, für welchen Mikrocontroller das Projekt compiliert werden soll und mit welcher Taktfrequenz er betrieben wird. Die Taktfrequenz ist für Warteschleifen mittels _delay_ms() und für den seriellen port wichtig. Wenn du hier einen falschen Wert angibst, stimmen die Timings nicht. Die LED wird dann mit der falschen Geschwindigkeit blinken und der Computer wird vom seriellen Port nur Hieroglyphen empfangen, statt den erwarteten Text.

Ein häufiger Anfängerfehler ist die Annahme, dass man mit F_CPU die Taktfrequenz verändern könne. Das ist nicht der Fall! Die Taktfrequenz wird mit Fuses eingestellt und hängt ggf. von einem externen Taktgeber oder Quarz ab.

In der Zeile OBJ=... Listest du alle Objekte auf, die der C-Compiler compilieren soll. Jede *.c (oder *.cpp) Datei wird in eine Objekt-Datei compiliert.

Quelltext an die Hardware anpassen

Trage die richtigen Parameter für Avrdude in das Makefile ein. Aber lasse den Mikrocontroller-Typ weg, denn der wird durch die Anweisungen ganz unten im Makefile automatisch angehängt. Passe auch MCU und F_CPU entsprechend deinem Mikrocontroller an.

In main.c musst du in den Funktionen led_on() und led_off() angeben, wo die LED angeschlossen ist:

void led_on()
{
    DDRA  |= (1<<PA1); 
    PORTA |= (1<<PA1);
}

void led_off()
{
    PORTA &= ~(1<<PA1);
}

Werfe einen Blick in die Datei driver/serialconsole.h, dort steht die Baudrate und welcher serielle Port verwendet werden soll. Beispiel für die Variante mit UART:

// Serial bitrate
#define SERIAL_BITRATE 2400

// Select the serial port
#define USE_SERIAL0

// In the software, lines are always terminated with \n.
// If terminal mode is enabled, line breaks are converted automatically:
// - in sending direction, line breaks are sent as \r\n.
// - in receiving direction, line breaks may be terminated by \r, \n or \r\n.
// - backspace characters in receiving direction delete the last received character from the input buffer.
#define TERMINAL_MODE 1

// Enable echo on serial interface
#define SERIAL_ECHO 0

// Size of input buffer in chars, max 254 (output is not buffered).
// Change it carefully, you get a stack overflow if the buffer occupies too much RAM.
#define SERIAL_INPUT_BUFFER_SIZE 100

Beispiel für die soft-serial Variante:

// Serial bitrate
#define SOFTSERIAL_BITRATE 2400

// Macros to control the TxD Pin
#define SOFTSERIAL_TXD_INIT   { DDRD  |=  (1<<PD1); }
#define SOFTSERIAL_TXD_HIGH   { PORTD |=  (1<<PD1); }
#define SOFTSERIAL_TXD_LOW    { PORTD &= ~(1<<PD1); }

Compilieren und Ausführen

Danach müsste die LED Blinken. Wenn du jetzt auch noch das USB-UART Kabel anschließt und ein Terminalprogramm (z.B. Hammer Terminal, Cutecom, Putty) mit der richtigen Baudrate startest, siehst du außerdem jede Sekunde den Text "Hello World" und den Zählerstand des Systemtimers. Mit Cutecom unter Linux sieht das so aus:

Serielle Baudraten

Mit einem 7,3728 Mhz oder 14,7456 Mhz Quarz kann der UART des Mikrocontrollers alle gängigen Baudraten exakt erzeugen. Diese beiden Quarze sind für den seriellen Port als Idealfall zu empfehlen. Beim obigen Testaufbau nutzen wir jedoch den internen R/C Oszillator, dessen Frequenz von der Versorgungsspannung und Temperatur abhängt. Es kann daher zu Übertragungsstörungen kommen - vor allem, wenn der Chip warm wird oder die Versorgungsspannung weit von 3,3V abweicht.