C-Programmierung mit AVR-GCC/ Warteschleifen


In einem Programm ist es manchmal nötig eine bestimme Zeit zu warten, bevor es weiter ausgeführt wird.

Der Programmablauf kann verschiedene Arten von Wartefunktionen erfordern:

  • Warten im Sinn von Zeitvertrödeln
  • Warten auf einen bestimmten Zustand an den I/O-Pins
  • Warten auf einen bestimmten Zeitpunkt (siehe Timer)
  • Warten auf einen bestimmten Zählerstand (siehe Counter)

Der einfachste Fall, das Zeitvertrödeln, kann in vielen Fällen und mit großer Genauigkeit anhand der avr-libc Bibliotheksfunktionen _delay_ms() und _delay_us() erledigt werden. Die Bibliotheksfunktionen sind einfachen Zählschleifen (Warteschleifen) vorzuziehen, da leere Zählschleifen ohne besondere Vorkehrungen sonst bei eingeschalteter Optimierung vom avr-gcc-Compiler wegoptimiert werden.

Während gewartet wird, macht der Mikrocontroller allerdings nichts anderes mehr. Die Wartefunktion blockiert den Programmablauf. Möchte man einerseits warten, um zum Beispiel eine LED blinken zu lassen und gleichzeitig andere Aktionen ausführen wie eine weitere LED bedienen, sollten die Timer/Counter des AVR verwendet werden.

Delay-Funktionen

Bearbeiten

Die Delay-Funktionen sind im Header util/delay.h definiert. Wenn du diesen Header importierst, hast du Zugriff auf zwei unterschiedliche Verzögerungsroutinen.

die Funktion _delay_ms() verzögert die Programmausführung um so viele Millisekunden, wie im Parameter angegeben. Durch den Datentyp des Parameters (double) kannst du eine maximale Verzögerung von 6,5535 Sekunden erreichen. Dieser Wert ist unabhängig von der Taktfrequenz deines Mikrocontrollers. Die Funktion hat hingegen nur eine Auflösung von 1 Millisekunde.

Um genauere Zeitabstände abbilden zu können benötigst du die Funktion _delay_us(). Sie erwartet als Argument eine Zahl von Mikrosekunden zur Verzögerung.

Besonderheiten

Bearbeiten

Die oben genannten Routinen funktionieren nur richtig, wenn du vor der Einbindung dem Compiler mitteilst, wie groß die Taktrate ist. Durch eine Definition von F_CPU mit dem richtigen Wert in Hertz werden die internen Schleifendurchläufe berechnet. Ein falsch definierter Wert führt zu dementsprechend zu falschen Zeiten.

Der Quellcode muss mit eingeschalteter Optimierung übersetzt werden, sonst wird sehr viel Maschinencode erzeugt und die Wartezeiten stimmen nicht mehr mit dem Parameter überein.

Die Bibliotheksfunktionen funktionieren nur dann korrekt, wenn sie mit zur Übersetzungszeit bekannten konstanten Werten aufgerufen werden. Variablen kannst du also den Funktionen nicht als Parameter übergeben.

Codebeispiel

Bearbeiten
#include <avr/io.h>
#define F_CPU 1000000UL
#include <util/delay.h>

int main( void )
{
    DDRB |= (1 << PB0);

    while(1) {
        PORTB ^= (1 << PB0);
        _delay_ms(1000);
    }
    return 0;
}