test//gewollte Fehlermeldung wenn diese Stelle erreicht wird
16
#endif
17
18
#endif
ich will mittels glue das PCINT-Register je nach Port-Register
automatisch zuweisen.
Die Abfrage '#if dsz_port==B' funktioniert jedoch nicht. Obwohl
dsz_port==D ist, wird '#if dsz_port==B' angesprungen.
Was mache ich falsch?
gute Frage. D ist der Buchstabe D. Er wird nur für den GLUE-Macro
benötigt
#define PORT(x) GLUE(PORT, x)
#define PIN(x) GLUE(PIN, x)
#define DDR(x) GLUE(DDR, x)
und müsste eigentlich den ASCII-Wert 69 darstellen.
das hatte ich probiert.
#if dsz_port=='B'
#define dsz_vect PCINT0_vect
#endif
#if dsz_port=='C'
#define dsz_vect PCINT1_vect
#endif
#if dsz_port=='D'
#define dsz_vect PCINT2_vect
#endif
geht auch nicht.
grundschüler schrieb:> das hatte ich probiert.>> #if dsz_port=='B'> #define dsz_vect PCINT0_vect> #endif> #if dsz_port=='C'> #define dsz_vect PCINT1_vect> #endif> #if dsz_port=='D'> #define dsz_vect PCINT2_vect> #endif>> geht auch nicht.
sollte aber. Wie testest du, ob es funktioniert?
> was mach ich falsch?
1. den AVR erkennt man nicht am Vorgandensein von PORTA, denn den hat
auch ein Tiny24
2.
1
#if defined( __AVR_ATmega644__ )
2
#define DSZ_VECT PCINT0_vect
3
#define DSZ_PORT PORTA
4
#define DSZ_PIN PINA
5
#define DSZ_DDR DDRA
6
#define DSZ_BIT 5
7
#elif defined( __AVR_ATmega328__ )
8
#define DSZ_VECT PCINT0_vect
9
#define DSZ_PORT PORTB
10
#define DSZ_PIN PINB
11
#define DSZ_DDR DDRB
12
#define DSZ_BIT 1
13
#ekse
14
#error device Not supported (yet)
15
#endif
(die konkreten Werte sind mal so aus dem Höhlen Bauch)
Und als Tip (passend zum Nick):
Viel fremden Code anschauen. Die Anderen machen nicht alles falsch.
Carl D. schrieb:> den AVR erkennt man nicht am Vorgandensein von PORTA,
der AVR interessiert nicht. Wenn es PORTA gibt, ist die Zuordnung
PORTA => PCINT0 etc.
sonst um eins versetzt:
PORTB => PCINT0 etc.
Es geht mir im Prinzip nur darum, die Auswahl
#define dsz_int_port 2
einzusparen und in Abhängigkeit von
#define dsz_port D
zu bringen.
Scheint nicht so einfach zu sein.
lalala schrieb:> sollte aber. Wie testest du, ob es funktioniert?
ich setze einen Fehler in die betreffende Auswahl und schaue, ob es eine
Fehlermeldung gibt oder ob der Fehler übersprungen wird.
grundschüler schrieb:> das hatte ich probiert.>> #if dsz_port=='B'
Und wie hast Du dsz_port definiert? Da musst Du natürlich auch
Hochkommata verwenden. Sonst wird das nichts.
D (ohne Hochkommata) ist für den Präprozessor undefiniert (es sei denn,
Du hast ein #define D irgendwas irgendwo davor stehen).
'D' (mit Hochkommata) ist hingegen eine Konstante.
Rufus Τ. F. schrieb:> Du hast ein #define D irgendwas irgendwo davor stehen)
Nein. der Buchstabe D wird mittels GLUE mit der Buchstabenfolge
PIN,PORT,DDR verbunden. PIN ist für sich nix - zusammen mit D findet es
sich als Definition in io.h. mit 'D' würde GLUE nicht funktionieren.
Wahrscheinlich ist das die Besonderheit von GLUE, dass nix mit nix
verbunden wird und dann etwas ergibt. Nix ist dann aber für einen
Macro-Vergleich ungeeignet.
grundschüler schrieb:> Nein. der Buchstabe D wird mittels GLUE mit der Buchstabenfolge> PIN,PORT,DDR verbunden.
Nicht, wenn Du
#if bla===D
schreibst. Da ist kein "GLUE".
Rufus Τ. F. schrieb:> grundschüler schrieb:>> Nein. der Buchstabe D wird mittels GLUE mit der Buchstabenfolge>> PIN,PORT,DDR verbunden.>> Nicht, wenn Du>> #if bla==D>> schreibst. Da ist kein "GLUE".
Deswegen scheint es nicht so zu funktionieren, wie ich mir das gedacht
hatte.
Das merkwürdige ist, dass es bei der Verbindung von Ziffern im Vergleich
#if bla==2 und mit GLUE funktioniert.
lalala schrieb:> grundschüler schrieb:>> das hatte ich probiert.>>>> #if dsz_port=='B'>> #define dsz_vect PCINT0_vect>> #endif>> #if dsz_port=='C'>> #define dsz_vect PCINT1_vect>> #endif>> #if dsz_port=='D'>> #define dsz_vect PCINT2_vect>> #endif>>>> geht auch nicht.>> sollte aber.
Nein, sollte nicht.
Der Präprozessor kann nur numerische Werte vergleichen, keine Strings.
Johann L. schrieb:> lalala schrieb:>> sollte aber.>> Nein, sollte nicht.>> Der Präprozessor kann nur numerische Werte vergleichen, keine Strings.
'B', 'C', 'D', etc. sind in C ja auch keine Strings. Ist das im
Präprozessor anders?
Ich habe jetzt aber mal ein paar Codeschnipsel durch den GCC gejagt:
1
//#define TEST A //Option 1
2
#define TEST 'A' //Option 2
3
#if TEST=='A'
4
#warning TEST == 'A'
5
#else
6
#if TEST == A
7
#warning TEST == A
8
#else
9
#warning TEST ist was anderes
10
#endif
11
#endif
Mit Option 1: TEST == A
Mit Option 2: TEST == 'A'
Außerdem habe ich mal geraten, was der TO erreichen will und etwas in
die Richtung gebaut:
1
#define GLUE(X, Y) X ## Y
2
//#define TEST2A B //Option 1
3
#define TEST2A 'B' //Option 2
4
#define TEST2(X) GLUE(PORT, X)
5
#if TEST2(A)=='B'
6
#warning TEST2A == 'B'
7
#else
8
#if TEST2(A) == B
9
#warning TEST2A == B
10
#else
11
#warning TEST2A ist was anderes
12
#endif
13
#endif
Bei beiden Optionen ist das Ergebnis: TEST2A==B
Das hatte ich ehrlich gesagt nicht so erwartet. Falls ich einen Fehler
im Code habe, bitte melden :)
lalala schrieb:> Ich habe jetzt aber mal ein paar Codeschnipsel durch den GCC> gejagt://#define TEST A //Option 1> #define TEST 'A' //Option 2> #if TEST=='A'> #warning TEST == 'A'> #else> #if TEST == A> #warning TEST == A> #else> #warning TEST ist was anderes> #endif> #endif> Mit Option 1: TEST == A> Mit Option 2: TEST == 'A'
wenn Du
#if TEST == Z
schreibst kommt übrigens genauso
TEST == A
raus
Der Thread bestärkt meine Meinung, dass Anfänger nicht mit Macros
arbeiten sollten. Normaler C-Code würde das Problem auch lösen. Das
sieht villeicht nicht so elegant aus, dafür ist es für jeden zu
verstehen.
Anfänger: lasst einfach die Finger von #. Das einzige, was ihr braucht
ist #include.
Das funktioniert nicht, wenn man Code schreiben möchte, den man für
unterschiedliche AVRs übersetzen können möchte. Wenn der eine bestimmte
Register nicht hat, kann der Code für diesen Controller gar nicht erst
übersetzt werden; da ist bedingte (d.h. per #if / #ifdef gesteuerte)
Compilation zwingend erforderlich.
Obendrein würde eine Fallunterscheidung zur Laufzeit viel überflüssigen
Code erzeugen.
Der Präprozessor ist ein wichtiges Werkzeug; ihn verstehen und anwenden
können gehört dazu.
Man muss allerdings auch nicht ums Verrecken alles mit dem Präprozessor
erledigen.
Ist es wirklich nötig, Registernamen mit viel MagicFoo(tm) vom
Präprozessor zusammenbasteln zu lassen, nur weil man tippfaul ist?
Rufus Τ. F. schrieb:> Ist es wirklich nötig, Registernamen mit viel MagicFoo(tm) vom> Präprozessor zusammenbasteln zu lassen, nur weil man tippfaul ist?
Alles was der Präprozessor automatisiert erledigt, erzeugt keine Fehler.
Wenn ich den Pin wechsele, brauche ich nur die Defines
#define dsz_port D
#define dsz_pin 5
#define dsz_int_port 2
richtig zu machen. Der ganze PCINT-Code wird dann automatisch richtig
angepasst. Ohne Macros muss man den Code an vielen Stellen ändern.
Dadurch ergeben sich Fehlermöglichkeiten.
Das ist nicht nur Tippfaulheit sondern auch Fehlervermeidung.
Ich könnte das noch reduzieren indem ich nur
#define dsz_pin 5
#define dsz_int_port 2
definiere oder die Durchnummerierung von Arduino verwende:
#if dsz_int_port == 0
#define dsz_port B
#endif
#if dsz_int_port == 1
#define dsz_port C
#endif
#if dsz_int_port == 2
#define dsz_port D
#endif
Allerdings möchte ich den D5-Pin auch so bezeichnen, weil das bei AVRs
geläufig ist. Man weiß dann gleich welcher Pin gemeint ist.
grundschüler schrieb:> #define dsz_port D
Genau da liegt halt das Problem.
Hätte D einen Wert, könntest Du es auch inhaltlich (d.h. mit
Vergleichsoperationen) auswerten. Es hat aber keinen, es ist nur ein
symbolischer Name, und damit kannst Du außer mit Deiner "glue logic"
nichts weiter anfangen.
Rufus Τ. F. schrieb:> nichts weiter anfangen.
ja doch:
#define pinSET(x,y) PORT(x) |=(1<<y)
#define pinCLR(x,y) PORT(x)&=~(1<<y)
#define pinTOG(x,y) PORT(x)^=(1<<y)
#define pinVAL(x,y) (PIN(x)&(1<<y))
#define pinDIRin(x,y) DDR(x)&=~(1<<y)
#define pinDIRout(x,y) DDR(x)|=(1<<y)
#define pinPULLUP(x,y,z)
(z)?(PORT(x)|=(1<<y)):(PORT(x)&=~(1<<y))//0_no
wenn dsz_port einmal definiert ist, kann man da viel mit machen.
Kaj schrieb:> es sei aber trotzdem mal angemerkt im Zuge der "ohne geht es> nicht"-Behauptung
Das geht nur dann, wenn sämtliche symbolische Namen, die hier verwendet
werden, immer bekannt sind.
Gerade das aber ist im AVR-Umfeld nicht gegeben; für unterschiedliche
AVRs werden unterschiedliche Headerdateien eingebunden, die
unterschiedliche Peripherieregister definieren.
Versucht man nun, Code zu schreiben, der beispielsweise eine zweite, nur
bei einem bestimmten AVR-Typ vorhandene UART ansteuert, fliegt der
Compiler auf die Schnauze, wenn das für einen anderen AVR-Typ übersetzt
werden soll, weil die symbolischen Namen für die Register der zweiten
UART undefiniert sind.
Da muss dann der die zweite UART ansteuernde Code mit bedingter
Compilation, d.h. durch #if / #ifdef auskommentiert werden.