Hallo, ich habe leider noch wenig Erfahrung mit C und GCC und eine kleine "Ist das irgendwie möglich"-Frage zu Makros. Folgendes Problem: Ich habe angefangen für die Atmel AVRs zu programmieren, würde aber gerne den Sourcecode etwas einfacher, lesbarer und weniger auf eine spezielle Architektur zugeschnitten haben, was die einfache Ein/Ausgabe auf bestimmte IO-Ports betrifft. Genauer gesagt möchte ich zum Ein-/Aus-/Umschalten/Richtung bestimmen für ein bestimmtes Port-Pin im Quelltext nur eine einzige Variable benutzen. Mal ein Beispiel: Ich würde ich beispielsweise gerne so etwas wie SET_IO_PORT_TO_OUTPUT( PORT_C5 ) schreiben statt DDRC |= (1 << DDC5) oder SET_OUTPUT_PORT_LOW( PORT_D2 ) statt PORTD &= ~(1 << PD2) Allerdings hätte ich es gerne so, dass der kompilierte Code dadurch nicht grösser und langsamer wird; wenn es also beispielsweise möglich wäre dass der GCC-Preprozessor den Makroaufruf SET_IO_PORT_TO_OUTPUT( PORT_C5 ) automatisch in ein DDRC |= (1 << DDC5) umformt. Ist das irgendwie möglich? Das Problem das ich habe ist, dass er zu jeder Angabe wie PORT_C5 automatisch die passenden Werte der anderen DDR, PORT und PIN-Register wissen muss (bei PORT_C5 also z.B. DDRC, PORTC, PINC) Da DDRC, PINC etc. ja vermutlich letztlich nur Werte sind dachte ich ich löse das einfach, indem ich die entsprechenden Werte in eine grössere Zahl "hineinpacke" und sie daraus dann wieder extrahiere, z.B. #define PORT_C5 ((DDRC << 24) | (PINC << 16) | (PORTC << 8) | 5) [...] #define DDR(port) (uint8_t)(port >> 24) #define BITINDEX(port) (uint8_t)(port) #define SET_IO_PORT_TO_OUTPUT(port) DDR(port) |= (1 << BITINDEX(port)) War auch schön gedacht, funktioniert aber leider nicht - aufgrund der Fehlermeldung "invalid lvalue in assignment" gehe ich davon aus dass das Problem ist, dass nach allen Ersetzungen durch den Preprozessor ein Aufruf wie SET_IO_PORT_TO_OUTPUT( PORT_C5 ) nicht durch DDRC |= (1 << 5) ersetzt wird sondern durch sowas wie 12 |= (1 << 5) Hat Jemand eine Idee, wie ich das Problem trotzdem lösen könnte?
Nun ja, wenn du sowas akzeptierst:
1 | #define SET_IO_PORT_TO_OUTPUT(port,pin) DDR##port |= (1 << (pin))
|
2 | ...
|
3 | SET_IO_PORT_TO_OUTPUT(C,5); |
dann geht es. Das nennt man auch einen hardware abstraction layer (HAL).
Danke für den Tip, Jörn, auf die Idee bin ich nicht gekommen. Allerdings hätte ich dann ja trotzdem noch zwei Parameter in jedem Aufruf, und wenn es irgendwie mit einem ginge, das wäre halt noch schöner... Das praktische wenn ich nur einen Parameter hätte wäre halt auch, dass ich dann auch sowas schreiben könnte wie #define POWER_STATUS_LED_IO_PORT PORT_C5 [...] SET_IO_PORT_TO_OUTPUT( POWER_STATUS_LED_IO_PORT ); und falls ich mich dann entscheiden sollte die Power-LED an einen anderen IO-Pin zu klemmen, dann müsste ich nur einen einzigen Wert ändern.
1 | #define SET_IO_PORT_TO_OUTPUT_internal(port,pin) DDR##port |= (1 <<
|
2 | (pin)) |
3 | #define SET_IO_PORT_TO_OUTPUT(y) SET_IO_PORT_TO_OUTPUT_internal(y)
|
4 | #define POWER_STATUS_LED_IO_PORT C,5
|
5 | |
6 | SET_IO_PORT_TO_OUTPUT(POWER_STATUS_LED_IO_PORT); |
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.