AVR Embedded Tutorial - Delays/de
│ Deutsch (de) │ English (en) │
Zur Übersichtseite AVR Embedded Tutorial/de.
Delays für ATmega328 / Arduino
... und natürlich andere AVR Controller.
Genaues Timing auf den AVR Controllern ist eigentlich ganz einfach - wenn man es in Assembler macht. Einfache Schleifen in Pascal dagegen lassen sich nicht genau timen, denn man weiss nie wie der Compiler die Schleife beim nächsten Mal baut.
So wird zum Beispiel bei Compileroption -o1 eine for-Schleife mit einer 16bit-Zählvariable angelegt, die gleiche Schleife bei -o2 und -o3 mit 8bit. Dadurch wird die Schleife fast doppelt so schnell.
Kurze Delays im Mikrosekundenbereich
{$goto on} // muss angegeben sein
procedure delay_short();
label
loop;
begin
asm
ldi r16, 60
loop:
nop
dec r16
brne loop
end['r16'];
end;
Die Größe der Zählvariable muss man ausprobieren. Die Loop dauert 4 Taktzyklen, bei 8MHz wären also 2 Loops eine Mikrosekunde. Dazu kommen aber noch Einsprung in die Routine und der Compiler bastelt noch etwas Stackpointer- und Registersicherung drumrum.
Längere Delays im Millisekundenbereich
{$goto on} // muss angegeben sein
// Pause msec, 1 bis 255 msec
procedure delay_ms(time : uint8);
const
fmul = 1 * fcpu div 1000000;
label
loop1, loop2, loop3;
begin
asm
ldd r20, time
loop1:
ldi r21, fmul
loop2: // 1000 * fmul = 1000 * 1 * 8 = 8000 cycles / 8MHz
ldi r22, 250
loop3: // 4 * 250 = 1000 cycles
nop
dec r22
brne loop3
dec r21
brne loop2
dec r20
brne loop1
end['r20','r21','r22'];
end;
Mit dieser Schleife bekommt man ein ziemlich genaues Timing im Bereich 1 bis 255msec. Die Schleife darf durch Interrupts unterbrochen werden, dann dauert sie natürlich länger.
Die innere Schleife dauert 4 Taktzyklen pro Durchlauf, ergo 1000 Zyklen. Die mittlere Schleife macht daraus je nach Taktfrequenz 1msec (bei 1Mhz 1 Durchlauf, bei 8MHz 8 Durchläufe, bei 16MHz 16 Durchläufe). Die äußere Schleife entspricht dann der Anzahl Millisekunden.
Achtung! fmul, fcpu müssen Konstanten sein. Dann berechnet der Compiler den Wert beim Kompilieren und setzt ihn fest ein. Als Variablen würde der Compiler eine Ganzzahldivision einbauen und das wollt ihr nicht wirklich - außerdem geht die Zuweisung ldi auf eine Variable schief.
noch längere Delays
... im Sekundenbereich? Also echt mal, das muss doch nicht sein. Schon 50msec nimmt man vielleicht beim Startup, wenn der Controller noch auf die Peripherie warten muss. Aber im Programmablauf sind lange Delays schlechter Stil und es gibt eigentlich immer bessere Möglichkeiten.
Siehe auch
- Übersichtseite AVR Embedded Tutorial