arduino: delaymicroseconds () (Deutsch)

Wie funktioniert die Funktion delayMicroseconds ()? Soweit ich verstanden habe, ist der Vorteiler von timer0 auf 64 eingestellt. Für einen 16-MHz-Takt ergibt sich ein Wert von 4,0 us pro Zählung. Ich bin ein bisschen verwirrt in der Mathematik, um zum 1uS-Intervall zu gelangen?

Kommentare

  • Die Dokumentation sagt " Diese Funktion arbeitet sehr genau im Bereich von 3 Mikrosekunden und mehr. Wir können nicht garantieren, dass delayMicroseconds genau für kleinere Verzögerungszeiten ausgeführt wird. " In den Dokumenten für micros() heißt " Auf 16-MHz-Arduino-Karten (z. B. Duemilanove und Nano) hat diese Funktion eine Auflösung von vier Mikrosekunden (dh der zurückgegebene Wert ist immer ein Vielfaches von vier). "
  • Siehe auch electronic.stackexchange.com/q/22584/2191

Antwort

Der Quellcode für diese Funktion ist ziemlich gut dokumentiert und befindet sich in / usr / share / arduino / hardware /arduino/cores/arduino/wiring.c auf Linux-Systemen. Windows-Systeme haben einen ähnlichen Pfad wie die Datei wiring.c. Bemühen Sie sich, die Datei zu finden und zu durchsuchen. Konzentrieren Sie sich vorerst nur auf diese einzelne Funktion, sie ist nicht auf andere Funktionen angewiesen.

Wenn Sie den Code überprüfen, werden Sie feststellen, dass es nicht um Timer geht, sondern um Befehlszyklen. Der Code hängt stark davon ab, dass die Compileroptimierung für Sie genauso ist wie für den Entwickler der Bibliothek. Das ist eine Annahme des Autors! Die Anzahl der von jedem Befehl „verbrannten“ CPU-Zyklen ist im Atmel AVR-Befehlssatzdokument gut dokumentiert.

Zunächst ist der Verzögerungswert wird auf 1 überprüft, in diesem Fall wird nur von der Routine zurückgekehrt, die bereits über eine Mikrosekunde CPU-Zeit verbracht wurde.

Dann wird der Verzögerungswert mit vier multipliziert (<<=2). Die __asm__ -Schleife wird in eine 4-CPU-Zyklusschleife kompiliert. 4 Zyklen × 4 = 16 Zyklen. 16 MHz / (4 × 4) = 1 MHz, was 1 us Zykluszeit benötigt, die Auflösung, nach der wir suchen.

Die letzten -2 Mikrosekunden (bevor die Schleife gestartet wird) sind wieder eine Korrektur für den Compiler Overhead eingeführt. Das Aufrufen von __asm__ -Code von C erfordert einige zusätzliche Anweisungen zum Speichern von CPU-Registern.

Für ein normales Arduino bei 16 MHz wird nur der folgende Code kompiliert:

/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. */ void delayMicroseconds(unsigned int us) { // calling avrlib"s delay_us() function with low values (e.g. 1 or // 2 microseconds) gives delays longer than desired. //delay_us(us); // for the 16 MHz clock on most Arduino boards // for a one-microsecond delay, simply return. the overhead // of the function call yields a delay of approximately 1 1/8 us. if (--us == 0) return; // the following loop takes a quarter of a microsecond (4 cycles) // per iteration, so execute it four times for each microsecond of // delay requested. us <<= 2; // account for the time taken in the preceeding commands. us -= 2; // busy wait __asm__ __volatile__ ( "1: sbiw %0,1" "\n\t" // 2 cycles "brne 1b" : "=w" (us) : "0" (us) // 2 cycles ); } 

Übrigens: Der kompilierte Code ist ziemlich genau, aber beachten Sie Folgendes: Auf Arduino sind zeitgesteuerte Interrupts konfiguriert, von denen die meisten nichts wissen. Wenn während der Ausführung von delayMicroseconds() ein Interrupt empfangen wird, ist das Timing von delayMicroseconds() falsch. Sie können Interrupts natürlich stoppen, bevor Sie delayMicroseconds() aufrufen und anschließend aktivieren. Dies wirkt sich jedoch wiederum auf die Zeitgenauigkeit durch die Dauer des kompilierten Codes zum Aktivieren / Deaktivieren aus.

Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.