Forum: Mikrocontroller und Digitale Elektronik Arduino Parser belügt mich


von makroOderMeinFehler (Gast)


Angehängte Dateien:

Lesenswert?

Nee der lügt natürlich nicht. Aber es wirkt so.

Ich hab gerade eine Meldung, die ich nicht nachvollziehen kann
1
#define COUNT  54  // Anzahl Digitalpins (Wert 54)
2
#define PIN    A0  // Analoger Pin A0    (Wert 54)
3
4
#if (PIN < COUNT)
5
#error PIN ist zu klein
6
#endif
7
8
void setup() {
9
  Serial.begin(9600);
10
  delay(500);
11
  Serial.print("COUNT = ");
12
  Serial.println(COUNT);
13
  Serial.print("A0 = ");
14
  Serial.println(A0);
15
}
16
17
void loop() {
18
}

Beim compilieren kommt eine Fehlermeldung
1
exit status 1
2
#error PIN ist zu klein

Wenn ich die Prüfung des Makros auskommentiere, compiliert der Code und 
es wird 2x 54 angezeigt, was auch korrekt ist. Und wieso kriegt der 
Parser das nicht hin?

von at-user (Gast)


Lesenswert?

Trag doch mal für PIN "100" ein ...

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Zeig' das #define von A0.

Das ist ziemlich sicher nicht der numerische Wert 54.

von makroOderMeinFehler (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Zeig' das #define von A0.
>
> Das ist ziemlich sicher nicht der numerische Wert 54.

Ja iwas stimmt nicht. Nur: print gibt für "A0" definitiv 54 aus. Was 
m.E. auch ok ist.

von makroOderMeinFehler (Gast)


Lesenswert?

Gut. Ich werde also auf die Suche gehen, wo A0 definiert ist. Hat jemand 
einen Tipp, in welcher h ich beginnen soll?

von at-user (Gast)


Lesenswert?

Schonmal drangedacht dass "A0" eine CONST Variable ist und kein 
Präprozessor Makro?

von Theor (Gast)


Lesenswert?

makroOderMeinFehler schrieb:
> Rufus Τ. F. schrieb:
>> Zeig' das #define von A0.
>>
>> Das ist ziemlich sicher nicht der numerische Wert 54.
>
> Ja iwas stimmt nicht. Nur: print gibt für "A0" definitiv 54 aus. Was
> m.E. auch ok ist.

Wie auch immer: Schaue Dir die Definition von A0 an.
Es wird sich vermutlich herausstellen, dass A0 zur Kompilationszeit und 
zur Laufzeit zwei verschiedene Wirkungen hat.

von at-user (Gast)


Lesenswert?

https://electronics.stackexchange.com/questions/67087/analogread0-or-analogreada0
1
hardware/arduino/avr/variants/standard/pins_arduino.h
2
3
static const uint8_t A0 = 14;
4
static const uint8_t A1 = 15;
5
static const uint8_t A2 = 16;
6
static const uint8_t A3 = 17;
7
static const uint8_t A4 = 18;
8
static const uint8_t A5 = 19;
9
static const uint8_t A6 = 20;
10
static const uint8_t A7 = 21;

von at-user (Gast)


Lesenswert?

Das obige kopierte stimmt natürlich nicht. Hier sind die richtigen 
Konstanten:
1
static const uint8_t A0 = 54;
2
static const uint8_t A1 = 55;
3
static const uint8_t A2 = 56;

von Stefan F. (Gast)


Lesenswert?

Auszug aus der Datei hardware/arduino/avr/variants/mega:
1
#define PIN_A0   (54)
2
static const uint8_t A0 = PIN_A0;

A0 ist eine Variable im RAM. Auf solche Variablen kann der Präprozessor 
nicht zugreifen.

von makroOderMeinFehler (Gast)


Lesenswert?

at-user schrieb:
> Schonmal drangedacht dass "A0" eine CONST Variable ist und kein
> Präprozessor Makro?

Nee. Aber wenn du recht hast erklärt es den Effekt

In pins_arduino.h ist A0 aber auch definiert
1
#define PIN_A0   (14)
2
3
static const uint8_t A0 = PIN_A0;

hat at-user ja auch gerade geschrieben

Nur dann verstehe ich nicht, wieso 54 ausgegeben wird.

Oder ist A0 ein Pointer und print gibt den Inhalt aus? Ich verstehs noch 
nicht

von makroOderMeinFehler (Gast)


Lesenswert?

Stefanus F. schrieb:
> Auszug aus der Datei hardware/arduino/avr/variants/mega:
>
1
> #define PIN_A0   (54)
2
> static const uint8_t A0 = PIN_A0;
3
>
>
> A0 ist eine Variable im RAM. Auf solche Variablen kann der Präprozessor
> nicht zugreifen.

OK. Der Klick kam langsam. Aber jetzt ist er auch bei mir angekommen.

Vielen Dank :)

von at-user (Gast)


Lesenswert?

>Nur dann verstehe ich nicht, wieso 54 ausgegeben wird.

54 ist der Inhalt der in der Variable drin steht, die du gerade 
ausliest.
A0 ist kein Pointer, sondern ein ganz normaler Integer.
Println() wandelt dir automatisch deinen Integer in einen String um und 
gibt diesen aus.

von makroOderMeinFehler (Gast)


Lesenswert?

at-user schrieb:
>>Nur dann verstehe ich nicht, wieso 54 ausgegeben wird.
>
> 54 ist der Inhalt der in der Variable drin steht, die du gerade
> ausliest.
> A0 ist kein Pointer, sondern ein ganz normaler Integer.
> Println() wandelt dir automatisch deinen Integer in einen String um und
> gibt diesen aus.


OK noch eine Frage zum verständnis: Was "sieht" der Parser, wenn er A0 
sieht?

von makroOderMeinFehler (Gast)


Lesenswert?

1
#define COUNT  54  // Anzahl Digitalpins (Wert 54)
2
#define PIN    A0  // Analoger Pin A0    (Wert 54)

Und was mir noch -etwas- unklar ist:
PIN wird aber vom Parser bestückt, der den Wert A0 nicht erkennt.
Im Programm -runtime- hat PIN dann aber dann doch den korrekten Wert 54.

Das würde ich gerne verstehen.

von Dr. Sommer (Gast)


Lesenswert?

static_assert funktioniert mit Konstanten und Makros:
1
static_assert(PIN >= COUNT, "PIN ist zu klein");
Bei der Gelegenheit kann man auch direkt die dumme Textersetzung via 
Makro durch richtige Konstanten ersetzen:
1
static constexpr uint8_t COUNT = 54;
2
static constexpr auto PIN =  A0;

von at-user (Gast)


Lesenswert?

>Was "sieht" der Parser, wenn er A0 sieht?

Nichts, er ignoriert es, weil keine Zuordnung bekannt ist. Es existiert 
kein "#define A0", deswegen wird A0 niemals Aufmerksamkeit schenken.

von at-user (Gast)


Lesenswert?

>Im Programm -runtime- hat PIN dann aber dann doch den korrekten Wert 54.

Ja logisch, weil der Parser alles mit "PIN" durch "A0" ersetzt. Es ist 
so als hättest DU A0 statt PIN geschrieben!

Bitte hier die Grundlagen nachholen:
http://public.beuth-hochschule.de/~kempfer/skript_c/Kap10.html

von Dr. Sommer (Gast)


Lesenswert?

makroOderMeinFehler schrieb:
> OK noch eine Frage zum verständnis: Was "sieht" der Parser, wenn er A0
> sieht?

Der Parser vom Präprozessor und der vom Compiler sehen beide ein 
Terminalsymbol "A0".

makroOderMeinFehler schrieb:
> PIN wird aber vom Parser bestückt, der den Wert A0 nicht erkennt

Der Parser liest nur Dinge ein. Der verarbeitet und ersetzt gar nichts. 
Makro-Textersetzung würde der Präprozessor nach dem Parsen machen, 
wenn A0 denn ein Makro wäre. Der Präprozessor - welcher das #if und 
#error auswertet - sieht nicht dass die beiden A0 zusammen hängen.

Der Compiler sieht erst eine Definition von A0 als Konstante. Bei der 
Nutzung von A0 sucht er die gleichnamige Konstante (gäbe es eine lokale 
Variable namens A0, würde diese stattdessen gefunden). Das Constant 
Folding im Optimizer wird den Wert 54 an die Stelle der Nutzung 
übertragen und da in die "ldi"-Instruktion einsetzen, die hier 
wahrscheinlich genutzt wird. Ein sehr dummer Compiler der keinerlei 
Optimierung vornimmt, könnte die Konstante stattdessen in den RAM legen 
(beim Start initialisiert) und dann bei der Nutzung erst aus dem RAM 
laden (z.B. per "lds") und dann an println übergeben.

at-user schrieb:
> Ja logisch, weil der Parser alles mit "PIN" durch "A0" ersetzt

Der Parser ersetzt nichts. Das macht der Präprozessor.

von Stefan F. (Gast)


Lesenswert?

Der Präprozessor ersetzt Text. Wenn du schreibst:
1
#define PIN_A0   (54)
2
static const uint8_t A0 = PIN_A0;
3
#define PIN A0
4
Serial.println(PIN);

Wird daraus:
1
static const uint8_t A0 = (54);
2
Serial.println(A0);

Nach dieser Textersetzung wird dein Quelltext compiliert.

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.