Both sides previous revisionPrevious revisionNext revision | Previous revision |
de:examples:timer:hardware_delay [2010/11/10 00:00] – Wember | de:examples:timer:hardware_delay [2020/07/20 09:00] (current) – external edit 127.0.0.1 |
---|
====== Hardwareverzögerung ====== | ====== Hardwareverzögerung ====== |
| |
//Necessary knowledge: [HW] [[en:hardware:homelab:controller]], [AVR] [[en:avr:timers]], [LIB] [[en:software:homelab:library:pin]], [LIB] [[en:software:homelab:library:delay]], [LIB] [[en:software:homelab:library:timer]], [PRT] [[en:examples:timer:software_delay]]// | //Notwendiges Wissen: [HW] [[en:hardware:homelab:controller]], [AVR] [[en:avr:timers]], [LIB] [[en:software:homelab:library:pin]], [LIB] [[en:software:homelab:library:delay]], [LIB] [[en:software:homelab:library:timer]], [PRT] [[en:examples:timer:software_delay]]// |
| |
===== Theorie ===== | ===== Theorie ===== |
| |
Die Softwareverzögerung ist nicht die einzige Methode Pausen zu erzeugen. Das gleiche kann mit Timern gemacht werden. Timer sind Hardware welche mit einer bestimmten Frequenz rauf oder runter zählen. Die Taktfrequenz des Timers kann über die Frequenz des Microcontrollers oder einem externen Taktgeber erzeugt werden. Normalerweise kann die Taktfrequenz mit einem Multiplikator dividiert werden um eine geringere Frequenz zu erreichen - das wird mit einem Prescaler gemacht. Wichtig ist jedoch, dass die Taktfreqzenz des Timers linear mit der Zeit ist. Die Zeit kann berechnet werden, in dem die Periode der Taktfrequenz mit dem Wert des Timers multipliziert. | Neben der Softwareverzögerung gibt es auch Timer, um Unterbrechungen zu erzeugen. Timer sind Hardwarekomponenten, die mit einer bestimmten Frequenz hoch oder runter zählen. Die Taktfrequenz des Timers kann über die Frequenz des Mikrocontrollers oder einen externen Taktgeber erzeugt werden. Allgemein kann die Taktfrequenz mit einem Multiplikator dividiert werden um eine geringere Frequenz zu erreichen. Hierzu wird ein Vorteiler verwendet. Wichtig ist jedoch, dass die festgelegte Taktfrequenz des Timers linear zu der Zeit ist. Die Zeit kann durch Multiplikation der Periode der Taktfrequent des Timers mit dem Wert des Timers berechnet werden. |
| |
[{{ :examples:timer:timer_counter.png?300|The events which come with the changes of AVR timer.}}] | [{{ :examples:timer:timer_counter.png?300|Durch Veränderung des AVR Timers hervorgerufene Ereignisse.}}] |
| |
AVR Counter können eingestellt werden um ein Signal bei einem Overflow machen oder einen bestimmten Vergleichstreffer. Ein Overflow passiert, wenn der Counter seine maximalen Wert erreicht hat und er wieder von 0 anfängt. Mit einem vorgegebenen Wert vergleicht der Counter den Wert des Timers bei jedem Anstieg mit dem gegeben Wert des Nutzers. Falls einer der Fälle eintritt werden die Bits des Statusindexes des AVR automatisch High gesetzt. | AVR Taktgeber können so eingestellt werden, dass sie bei Überlauf des Timers oder bei Vergleichstreffern informieren. Ein Überlauf tritt auf, wenn der Timer seinen maximalen Wert erreicht hat und der Zyklus wieder bei 0 anfängt. Nach Erreichen eines vorgegebenen Wertes beginnt der Timer bei jedem Anstieg seines Wertes diesen mit einem vom Benutzer vorgegebenen Wert zu vergleichen. Daraufhin werden die Bits des AVR-Statusindexes automatisch high gesetzt. |
| |
Um eine Verzögerung mit einem Timer zu generieren, muss man nur den Timer setzen und darauf warten, dass das Statusbit High geht. Anders als bei der Softwareverzögerung ist die Arbeit des Timers nicht vom Compiler abhängig, und macht ihn so zuverlässiger. Zur gleichen Zeit wird die Diversität (bzw. Komplexität) des Setups des AVR Counters recht mühsam. Je nach Taktsignal des Microcontroller kann es sein, dass es nicht exakt mit der gewünschten Verzögerungsperiode dividiert und die Verzögerung ungenau wird. | Um eine Verzögerung mit einem Timer zu generieren, muss man nur den Timer setzen und darauf warten, dass das Statusbit high wird. Im Unterschied zur Softwareverzögerung ist die Arbeit des Timers nicht vom Compiler abhängig, wodurch er zuverlässiger ist. Gleichzeitig ist die Diversität (bzw. Komplexität) der Einstellungen des AVR Timers hoch. Je nach Taktsignal des Mikrocontrollers kann es sein, dass es nicht exakt mit der gewünschten Verzögerungsperiode dividiert und die Verzögerung so ungenau wird. |
| |
===== Übung ===== | ===== Übung ===== |
Der Programmcode unterhalb ist eine Verzögerungsfunktion die auf einen Timer basiert und etwas vereinfacht wurde. Das Prinzip des Zählens ist das gleiche wie bei einer Softwareverzögerungsfunktion - eine gewünschte 1ms Verzögerung wird generiert. Die Verzögerung wird mit einem 8-Bit ATmega128 Counter 0 erzeugt. Die Taktfrequenz, wie zuvor schon berechnet, ist 14,7456 MHz und muss mindestens 64mal dividiert werden, so dass der Counter seinen Overflow nicht in einer Millisekunde erreicht. | |
Der Wert den der Zähler haben muss, so dass der Overflow nach 1ms passiert wird mit einer variablen //timer_start// dargestellt. //F_CPU// welche einer konstante in der Macrosprache ist, gibt die Taktfrequenz in Hz an. Die Taktfrequenz sollte 25,6 sein, aber da Komma-zahlen nicht genutzt werden können wird der Startwert auf 26 eingestellt. | Der Programmcode unterhalb stellt eine vereinfachte Timer-basierte Verzögerungsfunktion dar. Das Zählen funktioniert genauso wie bei einer Softwareverzögerungsfunktion. Es wird eine gewünschte Verzögerung von 1 ms mit dem Timer 0 eines 8-Bit ATmega128 erzeugt. Die zuvor errechnete Taktfrequenz liegt bei 14,7456 MHz und das Timersignal muss mindestens 64 Mal dividiert werden, so dass der Timer seinen Überlauf nicht in einer Millisekunde erreicht. |
| Der Wert den der Timer haben muss, so dass der Überlauf nach 1 ms stattfindet wird mit durch die Variable //timer_start// dargestellt. //F_CPU//, eine Konstante in der Makrosprache, gibt die Taktfrequenz in Hz an. Diese sollte 25,6 betragen, da nur ganze Zahlen berücksichtigt werden, liegt der Startwert bei 26. |
Leider entsteht hier eine gewisse Ungenauigkeit, welche aber sehr gering ist (- 1,7µs). | Leider entsteht hier eine gewisse Ungenauigkeit, welche aber sehr gering ist (- 1,7µs). |
| |
In dem Zyklus wird der Counter initialisiert und die Overflow Flagge genullt (in dem man eine 1 reinschreibt). Dann wartet man bis der Counter vom Startwert bis 256 gezählt hat, also zum Overflow. Wenn der Overflow stattfindet wird die Flagge hoch gesetzt und eine Verzögerung von einer 1ms hat stattgefunden. Am Ende der Funktion wird der Timer gestoppt. | In dem Zyklus wird der Timer initialisiert und die Überlauf-Flagge genullt (in dem eine 1 hineingeschrieben wird). Dann wird abgewartet bis der Timer vom Startwert bis 256 gezählt hat, also zum Überlauf. In dem Moment wird die Flagge hoch gesetzt und eine Verzögerung von einer 1 ms hat stattgefunden. Am Ende der Funktion wird der Timer gestoppt. |
| |
| |
<code c> | <code c> |
// | // |
// Hardware delay in milliseconds. | // Hardwareverzögerung in Millisekunden. |
// | // |
void hw_delay_ms(unsigned short count) | void hw_delay_ms(unsigned short count) |
{ | { |
// Calculating the initial value of the timer. | // Berechnung des Startwertes des Timers. |
register unsigned char timer_start = 256 - F_CPU / 1000 / 64; | register unsigned char timer_start = 256 - F_CPU / 1000 / 64; |
| |
// Starting the timer. | // Start des Timers. |
timer0_init_normal(TIMER0_PRESCALE_64); | timer0_init_normal(TIMER0_PRESCALE_64); |
| |
// Counting the variable of the delay to the 0. | // Zählen der Verzögerungsvariable auf 0. |
while (count-- > 0) | while (count-- > 0) |
{ | { |
// Initializing the timer. | // Initialisierung des Timers. |
timer0_set_value(timer_start); | timer0_set_value(timer_start); |
| |
// Zeroing the overflow flag. | // Überlauf-Flagge auf Null setzen. |
timer0_overflow_flag_clear(); | timer0_overflow_flag_clear(); |
| |
// Waiting for overflow. | // Warten auf den Überlauf. |
while (!timer0_overflow_flag_is_set()) | while (!timer0_overflow_flag_is_set()) |
{ | { |
} | } |
| |
// Zeroing the overflow flag. | // Überlauf-Flagge auf Null setzen. |
timer0_overflow_flag_clear(); | timer0_overflow_flag_clear(); |
| |
// Stoping the timer. | // Timer anhalten. |
timer0_stop(); | timer0_stop(); |
} | } |
</code> | </code> |
| |
Das folgende Programm ist ähnlich wie das im Beispiel für die Softwareverzögerung, In der kürzeren 100ms halb-Periode wird die LED angeschaltet und in der längeren 900ms halb-Periode wird die LED ausgeschaltet. Das Resultat: die LED blinkt jede Sekunde. Leider ist in diesem Beispiel die Periode ebenfalls nicht exakt eine Sekunde, da das Ausführen andere Funktionen des Programms ebenfalls Zeit verbraucht. Um ein exaktes Timing zu nutzen, muss ein 16-Bit Timer mit Interrupts genutzt werden. | Das folgende Programm ist ähnlich wie das für die Softwareverzögerung. In der kürzeren 100 ms langen halb-Periode wird die LED eingeschaltet und in der längeren 900 ms halb-Periode ausgeschaltet. Das Resultat: die LED blinkt jede Sekunde. Leider beträgt die Periode in diesem Beispiel ebenfalls nicht exakt eine Sekunde, da die Ausführung anderer Funktionen des Programms ebenfalls Zeit verbraucht. Für ein exaktes Timing, muss ein 16-Bit Timer mit Interrupts genutzt werden. |
| |
<code c> | <code c> |
// | // |
// Demonstration program of hardware delay of the HomeLab. | // Beispielprogramm für eine Hardwareverzögerung mit dem HomeLab. |
// The Program blinks LED for a moment after every ~1 second. | // Das Programm lässt eine LED immer nach ~1 Sekunde blinken. |
// | // |
#include <homelab/pin.h> | #include <homelab/pin.h> |
| |
// | // |
// Determining the pin of the Test LED. | // Festlegung des Pins der Test-LED. |
// | // |
pin debug_led = PIN(B, 7); | pin debug_led = PIN(B, 7); |
| |
// | // |
// Main program. | // Hauptprogramm. |
// | // |
int main(void) | int main(void) |
{ | { |
// Setting the pin of the LED as output. | // LED Pin als Output setzen. |
pin_setup_output(debug_led); | pin_setup_output(debug_led); |
| |
// Endless loop. | // Endlosschleife. |
while (true) | while (true) |
{ | { |
// Lighting the LED. | // Aufleuchten der LED. |
pin_clear(debug_led); | pin_clear(debug_led); |
| |
// Hardware delay for 100 milliseconds. | // Hardwareverzögerung von 100 ms. |
hw_delay_ms(100); | hw_delay_ms(100); |
| |
// Switch off of the LED. | // Ausschalten der LED. |
pin_set(debug_led); | pin_set(debug_led); |
| |
// Hardware delay for 900 milliseconds. | // Hardwareverzögerung von 900 ms. |
hw_delay_ms(900); | hw_delay_ms(900); |
} | } |