www.mikrocontroller.net

Forum: Compiler & IDEs Dumme? Frage zum Präprozessor


Autor: Rolle (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich bin noch relativer Anfänger und habe eine Frage:
Folgendes sollte funktionieren:

Am Anfang des Programms:

#define Ausgabeport1 PortB
#define Ausgabeport2 PortC
#define GLUE(a, b)     a##b
#define PORT(x)        GLUE(PORT, x)

#define SET(bit) Ausgabeport1 |= _BV(bit))
#define RESET(bit) Ausgabeport1 &= ~_BV(bit)
#define OUT_RESET 4
#define OUT_Start 5

Irgendwo im Programm:
SET(OUT_RESET)
RESET(OUT_RESET)
SET(OUT_START)

SET und RESET setzen also das definierte Bit in PortB.
Nun die Frage: Wie kann ich die Definition für den Präprozessor so 
abändern, dass durch Nutzung der definierten Port-Bits wie z.B. 
OUT_START auch der Port (Ausgabeport1 oder Ausgabeport2) vorab definiert 
werden kann?
Beispiel: OUT_RESET soll also z.B. Port B4 sein
und OUT_START soll Port C5 sein.

Ich möchte aber trotzdem eine Routine Set / Reset haben. D.h mit SET 
(OUT_START) wird C5 gesetzt und mit SET(OUT_RESET) wird B4 gesetzt. Ich 
komme hier nicht weiter. Danke für die Hilfe

Autor: die ??? (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
#define Ausgabeport1 PortB
#define Ausgabeport2 PortC
#define GLUE(a, b)     a##b
#define PORT(x)        GLUE(PORT, x)

#define SET((bit), (port))     ( (port) |= _BV(bit) )
#define RESET((bit), (port))   ( (port) &= ~_BV(bit) )
#define OUT_RESET 4
#define OUT_Start 5

// ...

SET(OUT_RESET, Ausgabeport1);

Autor: Rolle (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oh, die drei Fragezeichen sind auch hier :-)
Das ging ja fix.

Danke für die Hilfe. Das hilft mir schon mal weiter. Ich vermute also, 
dass es nicht möglich mittels #define OUT_RESET .... direkt den Port 
zuzuweisen, so dass ein einfaches
SET(OUT_RESET) für PortB.4 und ein
SET(OUT_START)  für Port C.5 reicht?

Danke nochmals

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
#define OUT_RESET B,4
#define OUT_START C,5

#define GLUE(a, b) a##b
#define PORT(x) GLUE(PORT,x)

#define SET_(p, b) PORT(p) |= (1 << (b))
#define RESET_(p, b) PORT(p) &= ~(1 << (b))
#define SET(...) SET_(__VA_ARGS__)
#define RESET(...) RESET_(__VA_ARGS__)

#include <avr/io.h>

void
foo(void)
{
        SET(OUT_RESET);
        RESET(OUT_START);
        SET(OUT_START);
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> #define SET(...) SET_(_VA_ARGS_)
> #define RESET(...) RESET_(_VA_ARGS_)

Jetzt bin ich verblüfft.
Das geht ?!?

Ist das Standard oder eine gcc Erweiterung?

#define OUT_RESET B,4
Mit derselben Idee habe ich auch rumgespielt, bin aber an der
falschen Makro Auswertereihenfolge gescheitert.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger wrote:

> Ist das Standard oder eine gcc Erweiterung?

C99, wobei's der GCC auch im gnu89-Mode (das ist der Default) bereits
kennt.

_VA_ARGS_ löst insbesondere endlich den gordischen Knoten mit den
Debug-printf()s.  Man möchte sie verwenden wie printf() (also mit
variabler Argumentliste), aber sie sollen so als Makro implementiert
sein, dass sie im Nicht-Debug-Code zu rein gar nichts evaluieren.
Das ging im C90 gar nicht.  Im C99 geht es als:
#if DEBUG
#  define DPRINTF(...) fprintf(stderr, __VA_ARGS__)
#else
#  define DPRINTF(...) /* nothing */
#endif

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
p.s.: Der Trick hier ist allerdings nur die doppelte Auswertung durch
den Präprozessor, ... und _VA_ARGS_ braucht man nicht unbedingt
dafür.  Das hier geht auch, und ist plain ISO C90 compliant:
#define OUT_RESET B,4
#define OUT_START C,5

#define GLUE(a, b) a##b
#define PORT(x) GLUE(PORT,x)

#define SET_(p, b) PORT(p) |= (1 << (b))
#define RESET_(p, b) PORT(p) &= ~(1 << (b))
#define SET(x) SET_(x)
#define RESET(x) RESET_(x)

#include <avr/io.h>

void
foo(void)
{
        SET(OUT_RESET);
        RESET(OUT_START);
        SET(OUT_START);
}

Ich hatte die __VA_ARGS__-Variante halt nur zuerst ausprobiert.

Autor: let (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das müßte portabel sein (geht zumindest auch mit Codevision):
/* Code to manipulate PORTx, PINx, and DDRx using definitions like those above */
#define PORT(port,pin)     (PORT##port)
#define DDR(port,pin)      (DDR##port)
#define PIN(port,pin)      (PIN##port)
#define PIN_MASK(port,pin) (1<<(pin))

/* Set a pin */
#define SETPIN(pindef)      PORT pindef |= PIN_MASK pindef

/* Clear a pin */
#define CLRPIN(pindef)      PORT pindef &= ~PIN_MASK pindef

/* Get pin value */
#define GETPIN(pindef)      (PIN pindef & PIN_MASK pindef)

/* Toggle a pin */
#define TOGGLEPIN(pindef)   PIN pindef |= PIN_MASK pindef

/* Set a IO to output */
#define SET_DDR_OUT(pindef) DDR pindef |= PIN_MASK pindef

/* Set a IO to input */
#define SET_DDR_IN(pindef)  DDR pindef &= ~PIN_MASK pindef

/* Read the value of a pin - a byte with the correspondig bit set or cleard is returned.
   Example:

   #define PIN7 (D, 7)
   ...
   SETPIN(PIN7);
   x = GETPIN(PIN7);
  { x = 128 }
*/

Autor: let (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ups, hatte ich vergessen:
/* Alternate port access macros from avr-gcc list */
/* http://lists.gnu.org/archive/html/avr-gcc-list/2004-12/msg00097.html */
/* Dave Hylands */
Ist also nicht auf meinen Mist gewachsen.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.