www.mikrocontroller.net

Forum: Compiler & IDEs welche Compilermodule verwenden F_CPU?


Autor: Daniel V. (danvet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
ich habe ein kleines Problem mit F_CPU.

Beim ATMega2560 z.B.kann ich zwar einen 14,7456 MHz Quarz anschließen, 
der endgültige CPU-Takt hängt aber vom Taktteiler ab.

Da z.B. der ATMega2560V nur bis 8MHz spezifiziert ist, muss der 
Quarz-Takt halbiert werden. Deswegen mache ich in meiner 'cpu.h' eine 
Abfrage auf den Controllertyp und setze F_CPU entsprechend. Zur Laufzeit 
wird dann in 'cpu.c' der Takteiler entsprechend gesetzt. Deswegen gibt 
es bei mir noch ein F_XTAL um den Quarztakt zu spezifizieren.

Das GCC-Modul 'delay.h' verwendet aber F_CPU um die Delayzeiten zu 
berechnen. Umschiffen kann ich das, indem man 'cpu.h' vor 'delay.h' 
einbindet (und der Compiler meckert dann, dass F_CPU 'redefined' ist, 
aber egal).

Welche Module verwenden denn noch F_CPU ?

Daniel

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da F_CPU der CPU-Takt und nicht der Quarztakt ist, warum setzt du das 
nicht auf halbe Quarzfrequenz und fertig? Wie diese CPU-Frequenz 
zustande kommt, ob halbiert oder nicht, ist ja egal.

Autor: Daniel V. (danvet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dann habe ich mich nicht klar ausgedrückt:
Wenn ich zur Laufzeit (bzw. beim 'booten') den Takteiler ändere, ändert 
sich auch meine CPU-Frequenz. Dann stimmen die Ergebnisse aus z.B. 
'delay.h' nicht mehr, weil diese zur Compilezeit errechnet wurden. 
Deswegen prüfe ich zur Compilezeit den CPU-Typ und definiere den 
Taktteiler und F_CPU neu.

Leider wird aber F_CPU ja auch schon von der Entwicklungsumgebung 
(Eclipse+WinAVR) definiert, und diese Definition ist unter Umständen 
falsch, wenn ich F_CPU nicht vorher umdefiniere.

Deswegen meine Frage von oben.

Autor: Daniel V. (danvet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. schrieb:
> Da F_CPU der CPU-Takt und nicht der Quarztakt ist, warum setzt du das
> nicht auf halbe Quarzfrequenz und fertig? Wie diese CPU-Frequenz
> zustande kommt, ob halbiert oder nicht, ist ja egal.

Weil ich auf ein und dem gleichen Board einmal ATMEGA2560 und einmal 
ATMEGA2560V bestücken kann. Der Quarz bleibt der gleiche.

Autor: Werner B. (werner-b)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das wird so nicht funktionieren. Delay.h ist (im wesentlichen) nichts 
anderes als ein Sammlung von Makros welche ein konstantes F_CPU erwarten 
welche vom Compiler/Preprozessor ausgewertet werden. Wenn du F_CPU zu 
einer Variablen machst stimmen die Delays generell nicht mehr. Abgesehen 
davon wird immer die Floating Point Bibliothek benötigt.

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel V. schrieb:
> Leider wird aber F_CPU ja auch schon von der Entwicklungsumgebung
> (Eclipse+WinAVR) definiert, und diese Definition ist unter Umständen
> falsch, wenn ich F_CPU nicht vorher umdefiniere.

Eclipse definiert gar nichts, wenn du das nicht möchtest. Es gibt für 
alles in den settings eine Einstellung, die man anpassen kann.

Daniel V. schrieb:
> Umschiffen kann ich das, indem man 'cpu.h' vor 'delay.h'
> einbindet (und der Compiler meckert dann, dass F_CPU 'redefined' ist,
> aber egal).

Deine Lösung ist völlig in Ordnung, und wenn du Eclispe richtig 
einstellst, meckert auch der Compiler nicht mehr.

F_CPU wird überhaupt nicht vom Compiler versendet, nur von der avrlibc. 
Dort nutzt es IMHO ausser delay.h nur noch setbaud.h.

Oliver

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
versendet -> verwendet ;-)

Autor: Daniel V. (danvet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist ja auch mein Problem.

Um das ganze variabel zu machen, wäre es ja vorstellbar, dass zur 
Laufzeit (beim Aufrufen von delay_ms() z.B.) geschaut wird, welche 
Frequenz der Quarz hat (das gibt man z.B. über F_XTAL an) und wie der 
Takteiler eingestellt ist. Daraus errechnet sich dann die Wartezeit. Das 
wäre doch mal ein kleines Projekt....ausserdem könnte man die CPU 
runtertakten und die Delay-Zeiten stimmen immer noch :-)

Autor: Daniel V. (danvet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oliver schrieb:
> Eclipse definiert gar nichts, wenn du das nicht möchtest. Es gibt für
> alles in den settings eine Einstellung, die man anpassen kann.
> Oliver

Tja, leider kann ich Eclipse nicht dazu bewegen F_CPU nicht zu 
definieren.

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel V. schrieb:
> Tja, leider kann ich Eclipse nicht dazu bewegen F_CPU nicht zu
> definieren.

project properties->C/C++-Build->settings

dort unter AVR Compiler/Symbols (welche Überraschung ;-)  gibt es eine 
Checkbox "Omit F_CPU".
Anklicken, weg ist das F_CPU.

Olver

Autor: Daniel V. (danvet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oliver schrieb:
> Daniel V. schrieb:
>> Tja, leider kann ich Eclipse nicht dazu bewegen F_CPU nicht zu
>> definieren.
>
> project properties->C/C++-Build->settings
>
> dort unter AVR Compiler/Symbols (welche Überraschung ;-)  gibt es eine
> Checkbox "Omit F_CPU".
> Anklicken, weg ist das F_CPU.
>
> Olver

Das muss man aber auch erstmal finden, ich bin unter
project properties->C/C++-Build->environment
rumgeeiert

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nimm einen Timer für die Delay-Generierung, und bau die Funktionen
so, dass sie sich an die CPU-Frequenz anpassen können.  Je nach
Timer kannst du die unterschiedlichen CPU-Frequenzen sogar durch
den Vorteiler ausgleichen.

Oder betreibe einfach gleich beide Setups mit dem halben Takt...

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel V. schrieb:
> Um das ganze variabel zu machen, wäre es ja vorstellbar, dass zur
> Laufzeit (beim Aufrufen von delay_ms() z.B.) geschaut wird, welche
> Frequenz der Quarz hat (das gibt man z.B. über F_XTAL an) und wie der
> Takteiler eingestellt ist.

Das geht nicht.
Ein Macro muß zur Compilezeit definiert sein und kann auch nur zur 
Compilezeit ausgewertet werden.
Zur Laufzeit geht das garnicht.


Du mußt für den ATMega2560 und den ATMega2560V verschiedene 
Programmversionen compilieren. Einmal mit F_CPU = 14,7456MHz und einmal 
mit 7,3728MHz. Fertig ist die Laube.


Peter

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mir leuchtet noch nicht ein, warum man ein und dasselbe Programm einmal 
mit 14,7456MHz und einmal mit 7,3728MHz laufen lassen muß. Entweder 
reicht der niedrige Takt, dann aber auch auf beiden CPUs, da es ja das 
selbe Programm ist, oder es reicht nicht, dann ist der V sowieso nicht 
geeignet.

Autor: Daniel V. (danvet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch schrieb:
> Nimm einen Timer für die Delay-Generierung, und bau die Funktionen
> so, dass sie sich an die CPU-Frequenz anpassen können.  Je nach
> Timer kannst du die unterschiedlichen CPU-Frequenzen sogar durch
> den Vorteiler ausgleichen.
>
> Oder betreibe einfach gleich beide Setups mit dem halben Takt...

ja, aber dann hätte ich immer noch das  Problem, dass der GCC eventuell 
das falsche F_CPU verwendet (auch wennes jetzt nur in delay.h und 
setup.h vorkommt, aber das könnte sich ja in Zukunft ändern)

Autor: Daniel V. (danvet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:
> Das geht nicht.
> Ein Macro muß zur Compilezeit definiert sein und kann auch nur zur
> Compilezeit ausgewertet werden.
> Zur Laufzeit geht das garnicht.
>
> Peter

Hab ja nicht gesagt, dass ein Macro das machen muss...

Autor: Daniel V. (danvet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf Magnus schrieb:
> Mir leuchtet noch nicht ein, warum man ein und dasselbe Programm einmal
> mit 14,7456MHz und einmal mit 7,3728MHz laufen lassen muß. Entweder
> reicht der niedrige Takt, dann aber auch auf beiden CPUs, da es ja das
> selbe Programm ist, oder es reicht nicht, dann ist der V sowieso nicht
> geeignet.

Das ist ein berechtigter Einwand. Vielleicht liegt es einfach an mir, 
dass ich mich zunächst noch nicht festlegen möchte. Aber ich sollte wohl 
mal eine Grundsatzentscheidung treffen, da hast du Recht!

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel V. schrieb:
> ja, aber dann hätte ich immer noch das  Problem, dass der GCC eventuell
> das falsche F_CPU verwendet

Wenn du weder <util/delay.h> noch <util/setbaud.h> einbindest, musst
du auch kein F_CPU definieren.  Du hast ja schon festgestellt, dass
das sonst niemand braucht.  Der Rest der Bibliothek (und der Compiler
erst recht) interessiert sich einen feuchten Kehrricht dafür, mit
welcher Frequenz deine CPU läuft.  Am ehesten würdest du diese
Konstante noch in deiner eigenen Applikation benötigen, um das ganze
Timer-Setup zu berechnen, aber dafür verbietet dir ja 1.) niemand,
einen anderen Namen als F_CPU zu benutzen und zweitens kannst du dort
prima mit einem #ifdef arbeiten.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel V. schrieb:
> ja, aber dann hätte ich immer noch das  Problem, dass der GCC eventuell
> das falsche F_CPU verwendet

Dann bist Du aber selbst dran schuld.
Das F_CPU darf man nur an einer einzigen Stelle definieren für alle 
Module gleich.
Also entweder im Make auf der GCC-Kommandozeile.
Oder z.B. in einem "hardware.h", welches alle includieren.

Sicherheitshalber sollte man auch vor der Definition testen, ob schon 
ein F_CPU existiert und dann knallhart mit einem #error abbrechen.


Peter

Autor: Daniel V. (danvet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:
> Daniel V. schrieb:
>> ja, aber dann hätte ich immer noch das  Problem, dass der GCC eventuell
>> das falsche F_CPU verwendet
>
> Dann bist Du aber selbst dran schuld.
Deswegen wollte ich ja wissen, welche Module F_CPU verwenden. Aber woher 
weiß ich denn, dass zukünftige Module das nicht auch verwenden, z.B. 
wenn der Ordner utils weitere Headers bekommt. Jaaa, vielleicht denk 
ich da zu weit vorraus. Selber schuld.

> Das F_CPU darf man nur an einer einzigen Stelle definieren für alle
> Module gleich.

Das ist mir völlig klar.
Ich wollte in diesem Thread eigentlich nur darauf hinweisen, dass die 
Definition von F_CPU völlig ausblendet, dass der AVR das Feature eines 
Taktteilers hat. Und der kann nunmal zur Laufzeit geändert werden.
Also darf ich z.B. delay_ms() nicht verwenden, wenn ich am Taktteiler 
rumspiele.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel V. schrieb:
> Ich wollte in diesem Thread eigentlich nur darauf hinweisen, dass die
> Definition von F_CPU völlig ausblendet, dass der AVR das Feature eines
> Taktteilers hat. Und der kann nunmal zur Laufzeit geändert werden.

Die AVR-GCC Entwickler gehen wohl davon aus, daß man nur einmal in der 
Initialisierung den Teiler einstellt und dann kann man den Teiler gleich 
in F_CPU hineinrechnen.

Inwieweit es sinnvoll ist, den Teiler mitten im Programm umzustellen, 
muß jeder für sich entscheiden.
Daß dann neben dem Delay auch Timer, UART, CAN, ADC, I2C, SPI-Takte nach 
dem Mond gehen, dürfte klar sein.


Peter

Autor: Dieter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:
> Die AVR-GCC Entwickler gehen wohl davon aus, daß man nur einmal in der
> Initialisierung den Teiler einstellt

So wie ich das bisher verstanden hab, macht Daniel V. genau das. Oder?

Daniel V. schrieb:
> Wenn ich zur Laufzeit (bzw. beim 'booten') den Takteiler ändere, ändert
> sich auch meine CPU-Frequenz.

Autor: Daniel V. (danvet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:

> Inwieweit es sinnvoll ist, den Teiler mitten im Programm umzustellen,
> muß jeder für sich entscheiden.
> Daß dann neben dem Delay auch Timer, UART, CAN, ADC, I2C, SPI-Takte nach
> dem Mond gehen, dürfte klar sein.
>
>
> Peter

Ja, das zieht dann einen ganzen Rattenschwanz hinter sich her....und die 
Taktberechnungen müssten in den Init-Routinen über eine Variable 
erfolgen (nicht über F_CPU).

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel V. schrieb:
> und die
> Taktberechnungen müssten in den Init-Routinen über eine Variable
> erfolgen (nicht über F_CPU).

...was zusätzlichen Laufzeitaufwand bedeutet, obwohl du eigentlich
in der Applikation am Ende mit genau einer CPU-Frequenz arbeitest.

Autor: Daniel V. (danvet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dieter schrieb:
> Peter Dannegger schrieb:
>> Die AVR-GCC Entwickler gehen wohl davon aus, daß man nur einmal in der
>> Initialisierung den Teiler einstellt
>
> So wie ich das bisher verstanden hab, macht Daniel V. genau das. Oder?
>
> Daniel V. schrieb:
>> Wenn ich zur Laufzeit (bzw. beim 'booten') den Takteiler ändere, ändert
>> sich auch meine CPU-Frequenz.

Jepp, beim booten stelle ich alles ein. Mitten im Programm ändere ich 
nichts. Aber das wäre ja auch mal interessant...

Autor: R. Max (rmax)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dieter schrieb:
> Peter Dannegger schrieb:
>> Die AVR-GCC Entwickler gehen wohl davon aus, daß man nur einmal in der
>> Initialisierung den Teiler einstellt
>
> So wie ich das bisher verstanden hab, macht Daniel V. genau das. Oder?

Ja, aber in Abhängigkeit von der CPU-Variante, auf der der Code gerade 
läuft, d.h. die endgültige Teilereinstellung ist zur Compilezeit nicht 
bekannt.

Eine Lösung könnte noch sein, die Delay-Funktionen in ein Makro zu 
packen, das den übergebenen Wert bei Bedarf halbiert, um bei halber 
Frequenz wieder auf die gleiche Zeit zu kommen:
#define F_CPU 14745600
#include <util/delay.h>

uint8_t halfspeed = 0; // Wird bei ATmega2560V von init auf 1 gesetzt

#define my_delay_us(a) if (halfspeed) _delay_us((a)/2); else _delay_us((a))
#define my_delay_ms(a) if (halfspeed) _delay_ms((a)/2); else _delay_ms((a))

Das verdoppelt halt den Platzbedarf für jede Verwendung von Delay.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mir dünkt, du diskutierst hier Stunden über ein Problem, das gar keins
ist: entweder läuft deine Applikation mit 7 MHz, dann kannst du sie
auch auf den nicht-V-AVRs damit laufen lassen, oder sie läuft damit
nicht, dann kannst du die Vs einfach in die Ecke legen.

Hat denn jemand schon vor der Fertigstellung des Prototyps schachtel-
weise beide CPU-Varianten gekauft?

Autor: R. Max (rmax)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch schrieb:
> Mir dünkt, du diskutierst hier Stunden über ein Problem, das gar keins
> ist: [...]

Klar mag es in diesem konkreten Fall bessere Lösungen geben, aber warum 
die Frage nicht zum Anlaß nehmen, sich mal Gedanken zu machen, wie 
Delays mit einer laufzeitabhängigen Takfrequenz unter einen Hut gebracht 
werden können?

Autor: Dieter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
R. Max schrieb:
> Klar mag es in diesem konkreten Fall bessere Lösungen geben, aber warum
> die Frage nicht zum Anlaß nehmen, sich mal Gedanken zu machen, wie
> Delays mit einer laufzeitabhängigen Takfrequenz unter einen Hut gebracht
> werden können?

Mit Timern! (!!!!) Denn dazu sind die schließlich da :)

Autor: R. Max (rmax)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dieter schrieb:

> Mit Timern! (!!!!) Denn dazu sind die schließlich da :)

Kein Grund hier rumzuschreien, zumal Deine Antwort am Problem vorbei 
geht. Auch Timer sind von der Taktfrequenz abhängig (wenn man extern 
getaktete mal außen vor läßt). Man muß sich also auch bei Timern 
zusätzliche Gedanken machen, wenn die Taktfrequenz erst zur Laufzeit 
endgültig feststeht.

Autor: Dieter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Erstens habe ich nicht geschriehen, zweitens ist es bei Timern ja wohl 
überhaupt kein Problem, zur Laufzeit die den richtigen Wert zur 
Verzögerung auszurechnen. Denn ob man das vom Compiler oder zur Laufzeit 
machen lässt, ist quasi kein Unterschied. Nen problem hat man nur, wenn 
mans zuvor per Hand und Taschenrechner ausgerechnet hat.

Und mein Beitrag war insofern durchaus ernst gemeint, weil es 
Hauptproblem beim verwenden der delay-Macros bei Timern nicht auftritt. 
Die delay-Macros kann man nämlich nicht mit variablen (=zur Laufzeit 
berechneten Werten) verwenden, ohne irgendwelche Krücken drumherum zu 
stricken.

Autor: Daniel V. (danvet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch schrieb:
> Mir dünkt, du diskutierst hier Stunden über ein Problem, das gar keins
> ist: entweder läuft deine Applikation mit 7 MHz, dann kannst du sie
> auch auf den nicht-V-AVRs damit laufen lassen, oder sie läuft damit
> nicht, dann kannst du die Vs einfach in die Ecke legen.
>
> Hat denn jemand schon vor der Fertigstellung des Prototyps schachtel-
> weise beide CPU-Varianten gekauft?

Du musst dich ja nicht an der Diskussion beteiligen :-)

Ich habe mit den nicht V-AVRs angefangen und  festgestellt, dass es bei 
einem Spannungsverlust am Board (also wenns ausgeschaltet wird) 
vorteilhaft ist, wenn man einen V-AVR drin hat - der arbeitet auch noch 
bei 2,7V ;-).

Autor: Daniel V. (danvet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
R. Max schrieb:
> Jörg Wunsch schrieb:
>> Mir dünkt, du diskutierst hier Stunden über ein Problem, das gar keins
>> ist: [...]
>
> Klar mag es in diesem konkreten Fall bessere Lösungen geben, aber warum
> die Frage nicht zum Anlaß nehmen, sich mal Gedanken zu machen, wie
> Delays mit einer laufzeitabhängigen Takfrequenz unter einen Hut gebracht
> werden können?

Du sprichst mir aus der Seele :-)

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dieter schrieb:
> Denn ob man das vom Compiler oder zur Laufzeit
> machen lässt, ist quasi kein Unterschied.

Das ist schon ein gewaltiger Unterschied, ob man ne Konstante zuweist 
oder ob man erstmal die Math-Lib ackern läßt (in float, damits richtig 
reinhaut).


> Nen problem hat man nur, wenn
> mans zuvor per Hand und Taschenrechner ausgerechnet hat.

Wer macht den sowas?
Die Compiler rechnen Konstanten selber aus. Sie sind zu faul, unnötigen 
Code zu generieren.
Ich schreib immer nur die Formel hin, Taschenrechner wäre mir zu 
umständlich und fehlerträchtig.

Delay abhängig vom Vorteiler 1 oder 2 ist auch nicht aufwendig:
void delay_ms( uint16_t ms )
{
  do{
    _delay_ms( 0.5 );
    if( !(CLKPR & 1<<CLKPS0) )
      _delay_ms( 0.5 );
  }while( --ms );
}

Autor: Daniel V. (danvet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:
>
> Delay abhängig vom Vorteiler 1 oder 2 ist auch nicht aufwendig:
>
> void delay_ms( uint16_t ms )
> {
>   do{
>     _delay_ms( 0.5 );
>     if( !(CLKPR & 1<<CLKPS0) )
>       _delay_ms( 0.5 );
>   }while( --ms );
> }
> 

Das ist mit Abstand die Beste Idee, die ich hier gelesen habe!

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel V. schrieb:
> Das ist mit Abstand die Beste Idee, die ich hier gelesen habe!

Geht aber auch nur im Millisekundenbereich, und da sind die delay-
Makros eigentlich schon nur noch mal für'n schnellen Hack da, in
einer fertigen Applikation sollte man es seiner CPU ersparen,
sinnlose Kreise für solch eine Ewigkeit zu drehen.

Für den Mikrosekundenbereich schlägt der Overhead bei dieser Lösung
schon zu stark auf's Ergebnis durch.

Daniel V. schrieb:
> Ich habe mit den nicht V-AVRs angefangen und  festgestellt, dass es bei
> einem Spannungsverlust am Board (also wenns ausgeschaltet wird)
> vorteilhaft ist, wenn man einen V-AVR drin hat

Dann musst du doch aber ohnehin in der Lage sein, mit den 7 MHz
auszukommen.  Wenn du das andererseits nicht bist, dann war das
mit den V-AVRs auch nicht sinnvoll, dann kannst du entweder normale
Typen mit 14 MHz takten und hoffen, dass sie weit genug runter noch
arbeiten, oder du könntest genauso gut die V-Type mit 14 MHz takten.
Beides wird ziemlich gleichermaßen gut oder schlecht gehen, ist aber
halt vom Hersteller nicht mehr garantiert.

Autor: R. Max (rmax)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel V. schrieb:

> Das ist mit Abstand die Beste Idee, die ich hier gelesen habe!

Ja, recht kompakt, hat aber den Nachteil, daß die Auflösung mit 1ms 
deutlich schlechter ist als bei _delay_ms().

Hier noch eine Variante, mit dem gleichen Nachteil, die aber etwas 
kleiner sein dürfte, weil sie den Delay-Code nur einmal einbindet und 
etwas genauer, weil sie das Clock-Register nur einmal testet, statt in 
jedem Schleifendurchlauf. Allerdings halbiert sich die maximal mögliche 
Wartezeit.
void delay_ms( uint16_t ms )
{
    if( !(CLKPR & 1<<CLKPS0)
        ms <<= 1;
    while (ms--)
        _delay_us(500);
}

Autor: Daniel V. (danvet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
R. Max schrieb:

> Hier noch eine Variante, mit dem gleichen Nachteil, die aber etwas
> kleiner sein dürfte, weil sie den Delay-Code nur einmal einbindet und
> etwas genauer, weil sie das Clock-Register nur einmal testet, statt in
> jedem Schleifendurchlauf. Allerdings halbiert sich die maximal mögliche
> Wartezeit.
>
>
> void delay_ms( uint16_t ms )
> {
>     if( !(CLKPR & 1<<CLKPS0)
>         ms <<= 1;
>     while (ms--)
>         _delay_us(500);
> }
> 

Ja mein ich doch, die Idee ist interessant und kann ausgebaut werden.

Autor: Daniel V. (danvet)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch schrieb:
> Daniel V. schrieb:
>> Das ist mit Abstand die Beste Idee, die ich hier gelesen habe!
>
> Geht aber auch nur im Millisekundenbereich, und da sind die delay-
> Makros eigentlich schon nur noch mal für'n schnellen Hack da, in
> einer fertigen Applikation sollte man es seiner CPU ersparen,
> sinnlose Kreise für solch eine Ewigkeit zu drehen.
>
> Für den Mikrosekundenbereich schlägt der Overhead bei dieser Lösung
> schon zu stark auf's Ergebnis durch.

Bei den manchen Display-Routinen braucht man halt die Wartezeiten, weil 
die Displays so schnarchig sind.


>
> Daniel V. schrieb:
>> Ich habe mit den nicht V-AVRs angefangen und  festgestellt, dass es bei
>> einem Spannungsverlust am Board (also wenns ausgeschaltet wird)
>> vorteilhaft ist, wenn man einen V-AVR drin hat
>
> Dann musst du doch aber ohnehin in der Lage sein, mit den 7 MHz
> auszukommen.  Wenn du das andererseits nicht bist, dann war das
> mit den V-AVRs auch nicht sinnvoll, dann kannst du entweder normale
> Typen mit 14 MHz takten und hoffen, dass sie weit genug runter noch
> arbeiten, oder du könntest genauso gut die V-Type mit 14 MHz takten.
> Beides wird ziemlich gleichermaßen gut oder schlecht gehen, ist aber
> halt vom Hersteller nicht mehr garantiert.

Ja, da sollte ich mal ne Grundsatzentscheidung treffen und einfach nur 
einen Typ verbauen. Stimmt.


btw: Wie zitiere ich denn mehrere verschiedene Beiträge in einem Post? 
Einfach kopieren scheint nicht zu funktionieren...

Autor: R. Max (rmax)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel V. schrieb:
> btw: Wie zitiere ich denn mehrere verschiedene Beiträge in einem Post?
> Einfach kopieren scheint nicht zu funktionieren...

Du kannst mehrmals nacheinander einen Beitrag oder einen Ausschnitt 
daraus markieren und dann auf "Markierten Text zitieren" klicken. Es 
wird dann im Eingabefeld jeweils ein neuer Zitatblock angehängt.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniel V. schrieb:
> Bei den manchen Display-Routinen braucht man halt die Wartezeiten, weil
> die Displays so schnarchig sind.

Bei Millisekunden lohnt es sich aber eigentlich immer, einen
Timer anzuwerfen und die CPU schlafen zu legen (*).  Ich schrieb ja
schon weiter oben, wenn du das mit dem Timer geschickt machst,
brauchst du nur je nach CPU-Frequenz zwei verschiedene Vorteiler
zu wählen (die sich um 2:1 unterscheiden), während die eigentliche
Berechnung dann komplett unabhängig von der tatsächlichen CPU-Frequenz
klappt.  Beim ATmega2560 geht das auf diese Weise für den Timer 2,
dessen Vorteiler komplett 2:1 gestaffelt sind.

(*) Oder aber du legst die komplette Ausgabe in den Hintergrund,
wenn das Display so schnarchlangsam ist, ähnlich wie man das für
eine UART-Ausgabe ja auch machen würde.

Autor: Andreas Ferber (aferber)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Noch weniger Extra-Overhead, und ohne großen Auflösungsverlust:
static inline void
my_delay_ms(double ms)
{
        _delay_ms(ms);
        if (!(CLKPR & 1<<CLKPS0))
                _delay_ms(ms);
}

Das FP-Berechnung wird hier vom Compiler komplett wegoptimiert, so wie 
es auch bei _delay_ms() alleine der Fall ist.

Andreas

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.