Forum: Mikrocontroller und Digitale Elektronik CAST und #if in einer Header-Datei (XC8)


von Florian (Gast)


Lesenswert?

Hallo zusammen!

Ich hoffe ich bin hier richtig?

Meine IDE ist MPlab X mit dem XC8 Compiler (Free-Version).
Controller: PIC16F1789 (was aber erst mal keine Rolle spielen dürfte)

folgenden Code habe ich in einer Header-Datei:

#define TMR_TEST                27.2
#define TMR_DEVIDER             ((int)TMR_TEST)


#if TMR_DEVIDER < 1
    #define RTCC_DEVIDER    RTCC_DIV_1
    #define DV 0
#elif TMR_DEVIDER < 2
    #define RTCC_DEVIDER    RTCC_DIV_2
    #define DV 1
#elif TMR_DEVIDER < 4
    #define RTCC_DEVIDER    RTCC_DIV_4
    #define DV 2
#elif TMR_DEVIDER < 8
    #define RTCC_DEVIDER    RTCC_DIV_8
    #define DV 3
#elif TMR_DEVIDER < 16
    #define RTCC_DEVIDER    RTCC_DIV_16
    #define DV 4
#elif TMR_DEVIDER < 32
    #define RTCC_DEVIDER    RTCC_DIV_32
    #define DV 5
#elif TMR_DEVIDER < 64
    #define RTCC_DEVIDER    RTCC_DIV_64
    #define DV 6
#elif TMR_DEVIDER < 128
    #define RTCC_DEVIDER    RTCC_DIV_128
    #define DV 7
#elif TMR_DEVIDER < 256
    #define RTCC_DEVIDER    RTCC_DIV_256
    #define DV 8
#else
    #error
#endif


Ausgeführt wird hier der #error obwohl der CAST von 27.2 (float) nach 
int 27 ergibt. Eigentlich muss #elif TMR_DEVIDER < 32 ausgeführt werden.

Ändere ich es wie folgt:

#define TMR_TEST                27
#define TMR_DEVIDER             TMR_TEST

wird #elif TMR_DEVIDER < 32 ausgeführt.

Kann mir das jemand erklären?

Vielen Dank!

Gruß

Florian

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Florian schrieb:
> Ausgeführt wird hier der #error obwohl der CAST von 27.2 (float) nach
> int 27 ergibt.

Deine Macros werden vom Präprozessor interpretiert. Der weiß gar nicht, 
was float ist.

von Peter II (Gast)


Lesenswert?

der Präprozessor kann nur int. Auch der Cast nach int kann er nicht. Das 
ist die Aufgabe vom Compiler

von Florian (Gast)


Lesenswert?

Danke für die schnellen Antworten!

Wenn ich in der Main einen der defines in eine Variable schreiben lasse 
und diese dann über einen breakpoint anschaue, steht in der Variablen 
das erwartete Ergebnis. Ich lasse z.B. einen Wert berechnen wie:


#define ZEIT.     127
#define WERT      (1/(ZEIT/4000.0))

In der Main dann:

float Test;

While(1)
{
Test = WERT;
}

Dabei steht in Wert dann 35...


Schreibe ich aber:

#define WERT       ((int)(1/(ZEIT/4000.0)))

steht in Test 35.0.

Der Cast nach int muss also funktioniert haben.
.0 ist klar, weil Test ja Datentyp "float" ist. Ändere ich auch das auf 
int oder char steht in Test nur noch 35. Der Compiler bemängelt hier 
auch nichts. Wenn Test aber vom Typ int oder char ist und ich den Cast 
nach int beim define weglasse (also wieder 35.49 hinter WERT steht) 
bemängelt der Compiler eine unerwartete Zuweisung von float nach int 
(oder eben char).

Wenn ich jetzt aber annehme, dass der Cast nach int beim define 
funktioniert, dann ist mir völlig unklar, warum dann die if / elif 
Anweisungen nicht zum logischen Ergebnis führen. Die Vermutung liegt 
aber nahe, dass es durchaus mit dem Cast zu tun hat, weil wenn ich

#define WERT       35

schreibe stimmt auch das was beim if / elif passiert.

Ich verstehe ganz einfach den Unterschied zwischen

#define WERT       35

und

#define WERT       ((int)(1/(ZAHL/4000.0)))

nicht, weil sowohl im einen, als auch im anderen Fall der Wert der 
Variablen Test 35 ist. Für das if / elif nach dem define ist aber 
offensichtlich ein Unterschied vorhanden. Und den würde ich gerne 
kennen...


Vielen Dank

Gruß

Florian

von Florian (Gast)


Lesenswert?

Es muss natürlich

#define ZEIT     127

heißen anstatt

#Delfine ZEIT.    127

von Peter II (Gast)


Lesenswert?

Florian schrieb:
> Für das if / elif nach dem define ist aber
> offensichtlich ein Unterschied vorhanden. Und den würde ich gerne
> kennen...

du musst zwischen Präprozessor und Compiler unterscheiden.

cast macht nur der Compiler, das ifdef macht aber der Präprozessor. 
Damit sollte eigentlich klar sein, warum es nicht geht.

von Noch einer (Gast)


Lesenswert?

In diesem Fall ersetzt der Präprozessor nur den Text, rechnet aber 
nichts selbst.

von Florian (Gast)


Lesenswert?

Vielen Dank!

Soweit verstehe ich das jetzt.

Die ganze if Geschichte kann der Präprozessor also nicht sinnvoll 
ausführen, weil die Berechnungen der defines noch nicht gemacht sind zu 
diesem Zeitpunkt.

Die einzige Lösung für den Fall wäre also, wenn ich die defines so lasse 
(mitsamt CAST) und die if Geschichte dann vom Controller einmalig am 
Anfang ausführen lasse. Z.B. in einer INIT-Funktion.


Aber was ich immer noch nicht verstehe ist, warum es mit dem alten 
Compiler unter MPLAB 8 so funktioniert hat? Ist der 
Präprozessor/Compiler in dieser Hinsicht also "schlechter" oder "dümmer" 
geworden? Der Vorteil war eben, ohne RAM oder Flash zu verbrauchen den 
kompletten INIT für einen Timer zu haben (und nicht alles selbst rechnen 
zu müssen).

Gruß

Florian

von Peter II (Gast)


Lesenswert?

kann man nicht eventuell RTCC_DEVIDER brechnen?

Hinter dem define RTCC_DIV_256 stehen doch auch nur Zahlen.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Es dürfte genügen, das hier

#define TMR_TEST 27.2
#define TMR_DEVIDER ((int)TMR_TEST)

zu verkürzen und für TMR_TEST direkt einen ganzzahligen Wert zu 
verwenden, bzw. auf TMR_TEST zu verzichten und gleich den ganzzahligen 
TMR_DIVIDER* zu nutzen.

Warum muss "TMR_TEST" ein nichtganzzahliger Float-Wert sein?

*) Den Teiler schreibt man übrigens divider

von Florian (Gast)


Lesenswert?

Nochmal Danke für die Erklärungen und Ansätze!

der Code aus meinem 1. Post dient als Beispiel was die defines Betrifft 
um mein Problem vereinfacht darstellen zu können. (Bitte nicht 
steinigen!!)

Das ist die eigentliche Version:

#define INT_FREQ                (1/(Entprellzeit/4000.0))
#define INTER_CLOCK_CORR        35
#define CLK_EFF                 (OSC_CLK/4.0)
#define CLK_PERINTERRUPT        (CLK_EFF/INT_FREQ)
#define TMR_DEVIDER             ((int)(CLK_PERINTERRUPT/256))


#if TMR_DEVIDER < 1
    #define RTCC_DEVIDER    RTCC_DIV_1
    #define DV 0
#elif TMR_DEVIDER < 2
    #define RTCC_DEVIDER    RTCC_DIV_2
    #define DV 1
#elif TMR_DEVIDER < 4
    #define RTCC_DEVIDER    RTCC_DIV_4
    #define DV 2
#elif TMR_DEVIDER < 8
    #define RTCC_DEVIDER    RTCC_DIV_8
    #define DV 3
#elif TMR_DEVIDER < 16
    #define RTCC_DEVIDER    RTCC_DIV_16
    #define DV 4
#elif TMR_DEVIDER < 32
    #define RTCC_DEVIDER    RTCC_DIV_32
    #define DV 5
#elif TMR_DEVIDER < 64
    #define RTCC_DEVIDER    RTCC_DIV_64
    #define DV 6
#elif TMR_DEVIDER < 128
    #define RTCC_DEVIDER    RTCC_DIV_128
    #define DV 7
#elif TMR_DEVIDER < 256
    #define RTCC_DEVIDER    RTCC_DIV_256
    #define DV 8
#else
    #error CPU-Clock zu gering
#endif


#define REST (((int)(CLK_PERINTERRUPT/(1<<DV))) % 256)
#define RTCC_Preset (256- ( REST - (INTER_CLOCK_CORR/(1<<DV))))


Entprellzeit ist bei mir 127 (im Moment zum Probieren).

Der Gedanke ist mit dem Programm den Timer entsprechend aufzuziehen, so 
dass dieser dann in der gewünschten Zeit die Taster / Schalter 
entprellt. Und schön ausprobieren / einstellen (man will ja auch nicht 
zu lange warten) kann man das dann wenn man nur die Entprellzeit von 1 
bis 255 in ms angeben muss. Natürlich geht das auch wenn ich es einmalig 
den Controller berechnen lasse oder zumindest alles nach den defines den 
Controller machen lasse. Kostet aber halt wieder Flash und RAM. Und da 
das früher gut funktioniert hat, hätte ich halt gerne.... ;-)

Das sind übrigens Teile von accurateinterrupt.h die man im Netz findet. 
Verwendet habe ich die damals mit einem HI-Tech Compiler unter MPlab 8.

Danke für den Hinweis mit "DEVIDER" --> "DIVIDER". Ich habs schon 100x 
gelesen, mir ist es aber nie aufgefallen.

Gruß

Florian

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.