This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| de:examples:timer:software_delay [2010/09/07 16:58] – Wember | de:examples:timer:software_delay [2020/07/20 12:00] (current) – external edit 127.0.0.1 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | ====== Softwareverzögerungen ====== | ||
| + | // | ||
| + | |||
| + | ===== Theorie ===== | ||
| + | |||
| + | Oft ist es wichtig in einem Programm eines Mikrocontrollers Verzögerungen einzubauen, einige Aktionen zu terminieren, | ||
| + | Eine Zahl von Null bis zum Wert der Taktfrequenz des Prozessors in Hz, sollte theoretisch eine Verzögerung von einer Sekunde erzeugen. Aus verschiedenen Gründen ist dieses jedoch praktisch nicht ganz so einfach. | ||
| + | |||
| + | Wenn der Prozessor des Microcontrollers mit Nummern rechnet, deren Binärform so groß ist wie der innere Bus (AVR hat 8 Bits), dann braucht es einen Taktzyklus des Prozessors um eine arithmetische Operation, wie z.B. 1 zu einem Wert zu addieren, durchzuführen. Soll mit tausenden oder millionen gerechnet werden, muss die Nummer 16 oder 32 Bit groß sein und ein 8-Bit Prozessor benötigt zur Berechnung mehr als eine Taktfrequenz. Daher sollte man sich mit der Arbeitsweise und insbesondere den Befehlen des Prozessors auskennen, wenn man mit großen Werten arbeitet. | ||
| + | |||
| + | Wenn man in fortgeschrittenen Sprachen programmiert (z.B. C), werden die Programme nicht auf Basis des Befehls geschrieben, | ||
| + | |||
| + | ===== Beispiel ====== | ||
| + | |||
| + | Das folgende Beispiel generiert eine Softwareverzögerung im AVR Mikrocontroller. Ein Teil des in C geschriebenen Programms zählt eine Variable x in vier Zyklen von 0 bis 100. | ||
| + | In jedem Zyklus wird ein leerer " | ||
| + | |||
| + | <code c> | ||
| + | unsigned char x; | ||
| + | |||
| + | // Zyklus bis x ist 100 | ||
| + | for (x = 0; x < 100; x++) | ||
| + | { | ||
| + | // Mit " | ||
| + | asm volatile (" | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Dies ist der gleiche Teil des Programms nach dem Kompilieren. Die beiden Hexadezimalzahlen links geben den Maschinencode an, und rechts befindet sich der Befehl mit den Operanden in Assembler. | ||
| + | Der Maschinencode und die Assemblersprache sind konform; Assembler dient nur dazu, den Maschinencode für Menschen lesbar zu machen. Kompiliert wurde mit der Optimierungsmethode für die Länge des Programms (Parameter -Os). | ||
| + | |||
| + | <code asm> | ||
| + | 80 e0 | ||
| + | 00 00 | ||
| + | 8f 5f subi r24, 0xFF ; subtrahieren von 255 aus dem r24 Index, was bedeutet +1 addieren | ||
| + | 84 36 | ||
| + | e1 f7 brne .-8 ; Falls der Vergleich nicht übereinstimmt, | ||
| + | </ | ||
| + | |||
| + | In der kompilierten Form erkennt man, was mit dem Zyklus der C-Sprache passiert und man kann berechnen wie viele Taktfrequenzen benötigt werden, um den Zyklus einer Periode zu beenden. Die Information über die Wirkung der Befehle und ihre Laufzeit findet man im AVR Datenblatt. Im vorliegenden Beispiel, braucht es 4 Taktzyklen um 4 Befehle in einer Periode auszuführen, | ||
| + | Wenn man nun den Arbeitstakt von 14,7456 MHz annimmt, kann man die vom Programm verursachte Verzögerung berechnen. | ||
| + | |||
| + | (1 + 100 ⋅ 4 + 1) / 14745600 = 27,26 μs | ||
| + | |||
| + | Die Verzögerung in diesem Beispiel ist in Mikrosekunden angegeben und die Variable nutzt 8-Bit, daher ist der Maschinencode recht einfach. Um eine Pause in Millisekunden zu verursachen, | ||
| + | |||
| + | Das Ziel dieser Übung ist es nicht präzise Softwareverzögerungen in Maschinencode zu erstellen, da diese eine sehr präzise Arbeit ist und die Funktionen zur Erzeugung von Verzögerungen bereits in der avr-libc und der Bibliothek von HomeLab hinterlegt sind. Diese werden auch in den folgenden Beispielen genutzt. | ||
| + | |||
| + | Bei der Arbeit mit Softwareverzögerungen arbeitet, ist es wichtig zu wissen, dass diese trotz ihrer Einfachheit, | ||
| + | Während jedes Taktes in dem der Mikrocontroller unnötig Zahlen zählt, wird Energie verbraucht. Wenn also batteriebetriebene Anwendungen genutzt werden, ist es nicht sinnvoll lange Softwareverzögerungen zu schreiben. Für diesen Fall sollte man lieber Hardwaretimer nutzen, welche unabhängig arbeiten und den Prozessor aus dem Ruhezustand holen wenn es an der Zeit ist die Arbeit fortzuführen. | ||
| + | |||
| + | ===== Übung ====== | ||
| + | |||
| + | Der folgende Programmcode beinhaltet die Softwareverzögerunsfunktion // | ||
| + | // | ||
| + | |||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Softwareverzögerung in Millisekunden. | ||
| + | // | ||
| + | void sw_delay_ms(unsigned short count) | ||
| + | { | ||
| + | // Zählen der Variable der Verzögerung auf 0 | ||
| + | while (count-- > 0) | ||
| + | { | ||
| + | // 1ms Verzögerung mit spezieller Funktion. | ||
| + | _delay_ms(1); | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Das folgende Programm dient dazu, die gegebene Funktion zu nutzen, es erzeugt zwei Verzögerungen in der Endlosschleife: | ||
| + | |||
| + | |||
| + | <code c> | ||
| + | // | ||
| + | // Das Vorführprogramm des HomeLab für Softwareverzögerungen. | ||
| + | // Es lässt eine LED für ~1 Sekunde aufleuchten. | ||
| + | // | ||
| + | #include < | ||
| + | #include < | ||
| + | |||
| + | // | ||
| + | // Festlegung des Pins zum Testen der LED | ||
| + | // | ||
| + | pin debug_led = PIN(B, 7); | ||
| + | |||
| + | // | ||
| + | // Hauptprogramm | ||
| + | // | ||
| + | int main(void) | ||
| + | { | ||
| + | // Setzt LED Pin als Output. | ||
| + | pin_setup_output(debug_led); | ||
| + | |||
| + | // Endlosschleife | ||
| + | while (true) | ||
| + | { | ||
| + | // Aufleuchten der LED | ||
| + | pin_clear(debug_led); | ||
| + | |||
| + | // Softwareverzögerung für 100 ms | ||
| + | sw_delay_ms(100); | ||
| + | |||
| + | // Ausschalten der LED | ||
| + | pin_set(debug_led); | ||
| + | |||
| + | // Softwareverzögerung für 900 ms. | ||
| + | sw_delay_ms(900); | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Auch wenn es so aussieht, als blinke die LED jede Sekunde, dauert es tatsächlich etwas länger, da das ansprechen der LED und die Verzögerungsfunktionen ein paar Taktfrequenzen des Mikrocontrollers benötigen. | ||