Forum: Compiler & IDEs Prescaler und Delay


von norton (Gast)


Lesenswert?

Hallo,

ich verwende einen ATmega48 und teile während des Programmablaufs die 
Clockfrequenz herunter (CLKPR) um Strom zu sparen.
Ist es nun möglich auch den F_CPU define zu verändern, damit die delay 
Funktionen in diesem Modus stimmen?
Oder muss ich dann beim delay den x- fachen wert verwenden um die 
richtige wartezeit zu bekommen?

von Johannes M. (johnny-m)


Lesenswert?

Ein mit #define erzeugtes Makro ist nur für den Präprozessor von 
Bedeutung und existiert während des Programmablaufs nicht mehr. Deshalb 
kann man da auch nix dran ändern.

Wenn Du _delay_XX-Funktionen mit im Betrieb veränderlichen 
CPU-Takteverwenden willst, musst Du wohl oder übel in Phasen mit 
herabgesetztem Takt die Warteschleifen anpassen (Achtung: die Parameter 
der _delay-Aufrufe selbst müssen konstant und zur Compilerlaufzeit 
bekannt sein, sonst machen die Funktionen nicht das, was sie sollen!).

Wenn Du z.B. 2 ms warten musst und den Takt um einen Faktor 8 
runterteilst, dann könnte es z.B. so aussehen:
1
uint8_t n;
2
3
if(!(CLKPR & 0x0F)) //Prescaler 1?
4
    n = 8;
5
else
6
    n = 1;
7
for(uint8_t i = 0; i < n; i++)
8
    _delay_ms(1);
wobei F_CPU dann als die niedrigere Frequenz definiert sein muss.

von Jörg X. (Gast)


Lesenswert?

Du kannst das Makro schon 'ändern':
1
#define F_CPU 8000000L
2
//'schneller' Code
3
//...
4
5
#undef F_CPU //loesch das alte..
6
#define F_CPU 1000000L // setz neu
7
//etc...
Wenn du aber mal irgendwo den Überblick verlierst, welche Angabe gerade 
gilt.. ;)

hth. Jörg

von Rolf Magnus (Gast)


Lesenswert?

Das Ändern des Makros ist aber dann auf bestimtme Codeabschnitte 
bezogen, nicht auf bestimmte Zeiträume zur Laufzeit.
Das geht also nur gut, wenn du für hohen Takt und niedrigen Takt immer 
nur unterschiedlichen Code hast. Wenn du dieselbe Funktion einmal mit 
niedrigem und einmal mit hohem Takt durchlaufen willst, geht es nicht.
Ein Ausweg wäre ein eigenes Delay-Makro, sowas wie:
1
#define my_delay(time)          \
2
    do {                        \
3
         if (slow_clock)        \
4
             _delay_ms(time/8); \
5
         else                   \
6
             _delay_ms(time);   \
7
    } while (0)

Du mußt dir dann halt eine Variable slow_clock anlegen, mit der du dir 
merkst, ob du gerade hohen oder niedrigen Takt hast. Alternativ kannst 
du natürlich auch direkt CLKPR abfragen.

von norton (Gast)


Lesenswert?

Danke für die Hilfe!

Ich habe mich für die Variante von  @Rolf Magnus entschieden.
Ich lese mir den Wert des Prescalers aus und dividiere einfach den 
Delaywert durch den des Prescalers.

Gruss Norton

von Peter D. (peda)


Lesenswert?

norton wrote:
> ich verwende einen ATmega48 und teile während des Programmablaufs die
> Clockfrequenz herunter (CLKPR) um Strom zu sparen.

Aha, Dein Gerät ist also batteriebetrieben.

Dann solltest Du besser die CPU ganz abschalten und per Uhrenquarz an T2 
wieder aufwecken.

Das Runtertakten bringt keine große Stromersparnis.


Peter

von Karl H. (kbuchegg)


Lesenswert?

norton wrote:
> Danke für die Hilfe!
>
> Ich habe mich für die Variante von  @Rolf Magnus entschieden.
> Ich lese mir den Wert des Prescalers aus und dividiere einfach den
> Delaywert durch den des Prescalers.

Und damit dürften dann die Delay Zeiten alle falsch sein.
Welchen Teil des Satzes "Beim Aufruf von _delay_ms muss
die angegebene Zeit eine Konstante sein" hast du nicht
verstanden?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Nö, Karl Heinz, da das Ganze ein Makro ist, löst der Compiler das
schon zur Compilezeit auf.

von norton (Gast)


Lesenswert?

Danke für die weiteren Anregungen und Hilfestellungen.

@Karl Heinz
> Und damit dürften dann die Delay Zeiten alle falsch sein.

Da hast du recht, aber für eine blinkende LED ist das Zeitvertrödeln 
genau genug.
Ich werde mir für genaueres Timing die Timer reinziehen.


@Peter Dannegger
> Dann solltest Du besser die CPU ganz abschalten und per Uhrenquarz an T2
> wieder aufwecken.

Kannst du das bitte ein wenig genauer erörtern. Ich fange gerade erst 
mit uC programmieren an und habe das nicht ganz verstanden. (Ich nehme 
an, wenn ich die CPU ganz abschalte kann ich keine Programmfunktionen 
(zb.: eintreten in den Aktivbereich) ausführen?)

Norton

von Rolf Magnus (Gast)


Lesenswert?

> (Ich nehme an, wenn ich die CPU ganz abschalte kann ich keine
> Programmfunktionen (zb.: eintreten in den Aktivbereich) ausführen?)

Das ist richtig. Die CPU muß durch einen entsprechenden Interrupt erst 
aufgeweckt werden. Wie Peter schon schreibt, kannst du einen Timer auch 
mit eigenem Takt versorgen und diesen dann nutzen, um den Prozessor nach 
einer bestimmten Zeit aufzuwecken. Dann kann er schauen, ob's was zu tun 
gibt, das dann ggf. machen, dann sich wieder schlafen legen bis zum 
nächsten Timer-Event. Auch das Aufwecken z.B. über einen Taster an einem 
Interrupt-Pin ist möglich.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.