Hallo zusammen,
ich habe bei mir die folgenden Definitionen:
1
#define PA0 GPIOA, GPIO_Pin_0
2
#define PA1 GPIOA, GPIO_Pin_1
3
4
[...]
5
6
#define HW_X1_PIN PA0
7
#define HW_X2_PIN PA1
Die Makros in den oberen Zeilen sind wiederum in den Headern der
Standard Peripheral Library für die STM32 festgelegt.
Sinn der Sache war es, in den Pinout-Konfiguration sinnvoll nach ganzen
Pins durchsuchen zu können ("Ist PA0 schon belegt, oder was war da
nochmal dran?".
In manchen, seltenen Fällen, will man dann doch die Standard Peripheral
Funktionen nutzen, in denen man Ports und Pins wieder einzeln benötigt.
Das hier funktioniert:
Die Fehlermeldung "macro "PIN" requires 2 arguments, but only 1 given"
verrät mir auch den Grund. Zum Zeitpunkt, an dem der Präprozessor
arbeitet, ist diese Komma-Liste nur ein einziges Argument. Wenn der
Präprozessor fertig ist, sieht die Funktion wieder zwei Argumente.
Nur aus Neugier: Gibt es eine Möglichkeit, in der Präprozessor-Magie
diese Komma-Sachen wieder aufzulösen?
Irgendwie geht das vielleicht, aber alleine schon die Tatsache, dass du
nicht innerhalb weniger Sekunden von selbst drauf kommst verleitet mich
zu dem Ratschlag: lass' es bleiben
Der Punkt ist, das solche Makros-Tricks dem Quelltext am Ende schlechter
lesbar machen. Hier im Forum wurden schon viele Ansätze präsentiert, wie
man Port und Pin Nummer zusammen bekommt, aber es läuft am Ende immer
auch (für nicht eingeweihte) schlecht lesbaren Code hinaus oder
funktionale Einschränkungen - insbesondere wenn du Dinge ansprichst, die
mehrere Pins haben (z.B. Displays mit 4/8bit Anschluss).
Wesentlich sinnvoller finde ich ganz normale Funktionen oder meinetwegen
auch Makros mit lesbaren Namen, wie:
- powerLedOn();
- powerledOff();
- sendCharToDisplay(c);
- leftButton();
- rightButton();
usw. Innerhalb dieser Funktionen dürfen dann gerne die üblichen
Bezeichner (PORTx, PINx, DDRx, PBx) verwendet werden. Ich sammle solche
Funktionen gerne in einer oder wenigen Quelltext-Dateien, damit ich sie
schnell wieder finde falls ich mal die Pin-Zuordnung ändern muss.
Wenn du mal solche Funktionen mit Makros vergleichst wirst du
feststellen, das das (zumindest beim gcc) performance-mäßig keinen
nennenswerten Unterschied macht. Die ganz kleinen Funktionen werden vom
Compiler automatisch ge-inlined, genau wie bei Makros. Oft läuft es im
Maschinencode auf nur 1-3 Opcodes hinaus (was will man mehr)?
Ich mache mir erstmal einen Schaltplan, d.h ich plaziere das MC-Symbol
und schreibe dann an alle belegten Pins die Netznamen dran.
Dann schreibe ich alle Netznamen in eine "hardware.h" und weise ihnen
dann die Portpins zu. Für die zusätzlichen Register hänge ich dann
Endungen an, _in (Input), _oe (direction), _pu (pullup).
Z.B.:
Wie gesagt halte ich nicht viel von diesen Pin-Listen. Die funktionieren
nur bei einfachen alleine stehenden GPIO Pins. Das Konzept versagt
schon, sobald du SPI, I²C, parallele Ports, teilweise auch PWM usw.
verwendest.
Schreibe lieber Funktionen mit aussagekräftigen Namen.
foobar schrieb:> Die Magie lautet hier Indirektion:
Danke! Ich bin zwar mit der Inline-Funktion nicht unglücklich, aber die
Makro-Variante hat den angenehmen Nebeneffekt, daß man sie bei
"static_assert()" nutzen kann.
Peter D. schrieb:> Ich mache mir erstmal einen Schaltplan,
Bei eigenen Boards: Ich auch. Bei Eval-Boards gibt es nur eine
(hoffentlich) gut gepflegte Liste.
Peter D. schrieb:> Dann schreibe ich alle Netznamen in eine "hardware.h" und weise ihnen> dann die Portpins zu.
Ich auch. Nur wird die (bei mir heißt sie "hw_config.h") bei einem
64-Pinner doch lang genug, daß man froh ist, wenn man darin (optisch
oder mit Strg-F) nach "PC1" suchen kann, anstelle der zwei Zeilen
#define HW_X1_GPIO GPIOC
#define HW_X1_Pin GPIO_Pin_0
Stefanus F. schrieb:> Das Konzept versagt> schon, sobald du SPI, I²C, parallele Ports, teilweise auch PWM usw.> verwendest.
Eigentlich funktioniert das ganz genauso:
1
#define I2C_SDA_PIN PB9
2
#define I2C_SCL_PIN PB8
3
4
#define HARD_ENC0 encoder_STM32F4XX_TIM5_PA0_PA1
5
6
#define USART_NO uart_STM32F4XX_USART2_PA2_PA3
7
#define USART_NO_BAUDRATE 1843200
8
9
#define BUZZER_PWM buzzer_STM32F4XX_TIM4_PB7
So habe ich weniger Probleme, die Übersicht über bereits belegte
Peripherie zu verlieren.
Stefanus F. schrieb:> Schreibe lieber Funktionen mit aussagekräftigen Namen.
Diese Aussage klingt für mich wie "Pizza ist besser als Rotwein."
Pinlisten und Funktionsnamen sollten meiner laienhaften Meinung nach
nichts miteinander zu tun haben.
Egal. Das ist irgendwie hier sowieso Off-Topic.
Warum funktioniert:
> Warum funktioniert: [...] und nicht: [...]. Woran liegt das> und wo lernt man das?
Das liegt daran, zu welchem Zeitpunkt Makros bzw ihre Argumente ersetzt
werden. Ein Anfang wäre z.B.
http://gcc.gnu.org/onlinedocs/cpp/Macro-Pitfalls.html
Ansonsten mal nach "C-Preprocessor magic" suchen.