PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Variablentyp bei Präprozessor



Bot-Builder
19.09.2011, 11:33
Hallo an Alle!

Ich kämpfe jetzt schon ein paar Tage lang (mal wieder, muss ich leider sagen) mit dem Präprozessor. Den Ladewert eines Timers möchte ich in Abhängigkeit von der Taktfrequenz durch den Präprozessor berechnen lassen. Ich hatte schon mal ein ähnliches Problem, seinerzeit war das Variablenformat das Problem.



#define Systemtakt 100
#define F_CPU 14745600
#define LadewertTimer0 (256-((F_CPU/1024)/Systemtakt))

#if (LaderwertTimer0 == 112)
#warning "Alles klar!!"
#endif

sollte eigentlich als Ergebniss 112 ergeben. Tut es aber nicht. Hier liegt vermutlich auch das Problem beim Variablenformat. F_CPU ist eine uint32_t. Daher wird auch das Ergebniss als uint32_t gespeichert (?). Es reicht aber eine uint8_t. Wie kann man eine entsprechende Zuweisung erzwingen? Cast-Operator, vielleicht? Aber welcher bei uint8_t?

Bei der Gelegenheit. Gibt es einen eleganteren Weg um das Ergebniss von Präprozessorberechnungen zu prüfen oder vielleicht sogar im Klartext an zu zeigen?

Bin wie immer für jeden Tip dankbar.


Viele Grüße

Bot-Builder

Ceos
19.09.2011, 11:59
[POSTEDIT]ARRGH mein fehler alten Post gelöscht

Der Präprozessor kann garnicht rechnen!!!

er ersetzt nur den Ausdruck vorne durch den Ausdruck hinten

jetzt hab ich mich aber aufs Glatteis führen lassen!

wenn du im Programm irgendwo den ausdruck

LadewertTimer0

schreibst, wird der stumpf durch den Ausdruck
(256-((F_CPU/1024)/Systemtakt))

ersetzt, logischerweise kommt da bei

LadewertTimer0 == 112 ein Falsch raus!

LadewertTimer0 == (256-((F_CPU/1024)/Systemtakt)) würde ein Wahr ergeben


Der Präprozessor ist nur dafür da, dass du deinen Quelltext selber besser lesen kannst und der Compiler ihn noch verstehen kann. Der Präprozessor entfernt alle whitespaces und newlines aus dem Text, ersetzt alle definierten Symbole durch die Ausdrücke die du festgelegt hast (dazu zählt auch #include, die Dateien werden deinem Include entsprechend einfach zu einer großen Textdatei zusammengesetzt) und gibt dann den Ergebnistext an den Compiler! Der Präprozessor macht nur tExtarbeit und rechnet nicht! Er vergleicht bei #if nur ob der Textinhalt derselbe ist nicht den Wert

Bot-Builder
19.09.2011, 18:22
Hallo Ceos!

Da habe ich leider wieder einmal den Wald vor lauter Bäumen nicht gesehen!



Der Präprozessor kann garnicht rechnen!!!

Habe ich eigentlich im Prinzip gewußt. Was sich aber daraus ergibt, habe ich nicht gesehen.


LadewertTimer0 == 112 ein Falsch raus!

LadewertTimer0 == (256-((F_CPU/1024)/Systemtakt)) würde ein Wahr ergeben

Ist nun klar.

Vielen Dank für den Schubs in die richtige Richtung. Habe gerade meinen Code angepasst. Und er funktioniert einwandfrei.


Viele Grüße

Bot-Builder

Ceos
19.09.2011, 19:00
ich hab mich aber im ersten Moment auch total aufs Glatteis führen lassen und mich fürstlich hingelegt XD ... der Origignalpost war peinlich XD

sternst
19.09.2011, 23:54
Der Präprozessor kann garnicht rechnen!!!

er ersetzt nur den Ausdruck vorne durch den Ausdruck hinten

jetzt hab ich mich aber aufs Glatteis führen lassen!

wenn du im Programm irgendwo den ausdruck

LadewertTimer0

schreibst, wird der stumpf durch den Ausdruck
(256-((F_CPU/1024)/Systemtakt))

ersetzt, logischerweise kommt da bei

LadewertTimer0 == 112 ein Falsch raus!

LadewertTimer0 == (256-((F_CPU/1024)/Systemtakt)) würde ein Wahr ergeben
Das stimmt nicht.
Er rechnet nicht in Bezug auf das Verändern des C-Codes, da ersetzt er nur stumpf.
Er rechnet aber sehr wohl innerhalb seines eigenen Gültigkeitsbereichs, also in einer #if-Zeile.

Das Beispiel im Ursprungsbeitrag scheitert einzig und alleine daran, dass das "LaderwertTimer0" in der #if-Zeile falsch geschrieben ist.

Ceos
20.09.2011, 08:48
... ich sollte meine Kenntnisse mal wieder auffrischen ... ist ja schrecklich was man alles vergisst wenn man mal n Jahr lang nicht mehr damit umgeht!

Bot-Builder
20.09.2011, 11:42
Ich habe gestern Abend die #if Zeile ohne weiteres prüfen rausgenommen. Und Sie gerade wieder reingemacht.



#define F_CPU 1475600 // im makefile definiert
#define Systemtakt 50
#define VorteilerTimer0 1024
#define LadewertTimer0 (256-((F_CPU/VorteilerTimer0)/(Systemtakt*2)))

#if (LadewertTimer0 == 112)
#warning "Alles klar!"
#endif
....
ISR (TIMER0_OVF_vect)
{
TCNT0 = LadewertTimer0;
...


Die Warnung wird tatsächlich ausgegeben! Als rechnet der Präprozessor bei der Vergleichoperation tatsächlich doch. Und vergleicht nicht nur die reine Textform.

@Stefan
Du hast mal in einem anderen Thread erklärt, wie man dem Ergebniss einer Präprozessorberechnung einen Variablentyp aufzwingen kann.



#define ocr_Wert ((F_CPU / (1024 * 2 * 50L)) - 1)

Du hast damals erklärt, des der Ausdruck (1024 * 2 * 50) als int16_t berechnet wird und dann nach uint32_t promotet wird, was zu einem falschen Ergebniss führt. (1024 * 2 * 50L) hingegen wird als int32_t berechnet und damit richtig.

Hilf mir mal bitte, damit ich das verstehe. F_CPU ist vom Typ int32_t, VorteilerTimer0 ist vom Typ int16_t, das Divisionsergebniss ist ebenfalls vom Typ int16_t. Soweit richtig? Systemtakt ist vom Typ int8_t, das dann folgende Divisonsergebnis ebenfalls int8_t. Und die Differenz dann auch int8_t und damit passend für das Register TCNT0. Habe ich dann richtig verstanden, dass auch für Zwischenergebnisse einer Präprozessorberechnung immer der kleinste benötigte Variablentyp verwendet wird?

Welches "Symbol" wird verwendet um eine int16_t bzw. eine unit16_t zu erzwingen? L bedeutet int32_t (long) und UL unit32_t (unsinged long), das hast Du schon mal erklärt. int8_t bzw. unit8_t zu erzwingen macht vermutlich keinen Sinn? Und sowas gibt es dann auch nicht?

Ich weiss, die Fragen sind rein akademisch. Wäre aber schön, wenn Du mich da aufklären könntest. Vielleicht hilft es noch jemand anderem.;)

Danke.

Viele Grüße


Bot-Builder

sternst
20.09.2011, 12:36
wie man dem Ergebniss einer Präprozessorberechnung einen Variablentyp aufzwingen kann.So was gibt es nicht.
Der Präprozessor rechnet in seinem eigenen Bereich (#if-Zeilen) nach seinen eigenen Regeln. Mit denen bin ich nicht vollständig vertraut, aber ich bin mir ziemlich sicher, dass er nicht mit unterschiedlichen Typen arbeitet.

Bei dem ganzen "Typen-Zeug" geht es um C-Berechnungen im Allgemeinen. Dabei spielt es überhaupt keine Rolle, ob ein Teil der Berechnung per Präprozessor-Textersetzung eingebracht wurde, oder nicht. Der Begriff "Präprozessorberechnung" ist hier daher völlig unangebracht und missverständlich.


#define F_CPU 1475600 // im makefile definiert
#define Systemtakt 50
#define VorteilerTimer0 1024
...
TCNT0 = (256-((F_CPU/VorteilerTimer0)/(Systemtakt*2)));


F_CPU ist vom Typ int32_tJa.


VorteilerTimer0 ist vom Typ int16_t,Ja.


das Divisionsergebniss ist ebenfalls vom Typ int16_tNein, int32_t.


Systemtakt ist vom Typ int8_tNein, int16_t.


das dann folgende Divisonsergebnis ebenfalls int8_tNein, int32_t.


Und die Differenz dann auch int8_tNein, int32_t.


damit passend für das Register TCNT0Bei der Zuweisung wird dann das int32_t Ergebnis auf uint8_t zurechtgestutzt.

Bei Berechnungen werden die Typen der beiden Operanden aneinander angepasst, wobei der größere Typ den Takt vorgibt (mindestens int), und das (Zwischen-)Ergebnis hat den gleichen Typ.


Welches "Symbol" wird verwendet um eine int16_t bzw. eine unit16_t zu erzwingen?int16_t ist es bereits per Default. "50" ist ein int (äquivalent zu int16_t bei AVR). Ein unsigned macht man daraus mit U. "50U" ist ein unsigned int (äquivalent zu uint16_t bei AVR).

Bot-Builder
20.09.2011, 17:52
Hallo Stefan,

danke für Dein Erklärungen:



Bei Berechnungen werden die Typen der beiden Operanden aneinander angepasst, wobei der größere Typ den Takt vorgibt (mindestens int), und das (Zwischen-)Ergebnis hat den gleichen Typ.
int16_t ist es bereits per Default.


Das brings dann ja wohl auf den Punkt.

Viele Grüße

Bot-Builder