Forum: Mikrocontroller und Digitale Elektronik #defines in C-Präprozessor Funktion


von Franz F. (franzman)


Lesenswert?

Hallo,

ich habe ein #define PINconf_SPI1_MISO 0x24 was heißt das SPI1 an Port B 
Pin 4 hängt.
Jetzt möchte ich die Information im Programm nutzen und z.B 
PIN_SPI1_MISO und PORT_SPI1_MISO verwenden.

Ich habe in einem Zentralen .h File alle PINconf* definiert, allerdings 
möchte ich jetzt nicht bei allen Pins ein extra define für Port und Pin 
machen.

Deswegen wollte ich das Problem so lösen:

DECLARE_PIN(SPI1_MISO, 0x24)

#define DECLARE_PIN(name,conf) { \
  #define PIN_##name conf && msk_GPIO_PIN\
  #define PORT_##name conf && msk_GPIO_PORT\
}

Dieser Ansatz verursacht diesen Fehler:
 error: '#' is not followed by a macro parameter

ich habe dann gelesen, dass man in defines keine defines machen kann, 
deswegen frage ich euch nach einem anderen Ansatz für mein Problem.

Habt ihr eine ander Idee?

PS: Ich programmiere einen Cortex M0 mit CoIDE

von grundschüler (Gast)


Lesenswert?

mit glue geht das:
1
  
2
  #define GLUE(a, b)  a##b
3
  #define PORT(x)    GLUE(PORT, x)
4
  #define PIN(x)    GLUE(PIN, x)
5
  #define DDR(x)    GLUE(DDR, x)
6
  #define sbi(var, bit) (var|=1<<bit)//set
7
  #define cbi(var, bit) (var&=~(1<<bit))//clear
8
  #define tbi(var, bit) (var^=1<<bit)//toggle
9
  #define gbi(var, bit) (var>>bit&1)//get
10
  #define wait  _delay_ms(1000)
11
  #define wait10  {_delay_ms(3333);_delay_ms(3333);_delay_ms(3333);}
12
  #define u8  uint8_t
13
  #define u16 uint16_t
14
  #define u32 uint32_t
15
  #define v volatile
16
...
17
#define pinSET(x,y) PORT(x) |=(1<<y)
18
#define pinCLR(x,y) PORT(x)&=~(1<<y)
19
#define pinTOG(x,y) PORT(x)^=(1<<y)
20
21
#define pinDIRin(x,y) DDR(x)&=~(1<<y)
22
#define pinDIRout(x,y) DDR(x)|=(1<<y)
23
//#define pinDIRaf(x,y) GPIO(x)->MODER |= (2<<(y*2))//
24
#define pinVAL(x,y) (PIN(x)&(1<<y))
25
//#define pinSPEED(x,y) GPIO(x)->OSPEEDR|=(GPIO_Speed_50MHz<<(y*2))//2=>50
26
#define pinPULLUP(x,y,z) PORT(x)|=(1<<y)//0_no 1_up

von Dr. Sommer (Gast)


Lesenswert?

Makros sind ein Relikt aus (Makro-)Assemblern, die es nach C geschafft 
haben. Man sollte sie einfach ganz weglassen. Du kannst beliebige 
Datenstrukturen als Konstanten definieren:
1
struct Pin {
2
  uint8_t port;
3
  uint8_t pin;
4
};
5
6
static const Pin SPI1_MISO { 3, 4 }; // Port 3, Pin 3

von (prx) A. K. (prx)


Lesenswert?

Franz F. schrieb:
> #define DECLARE_PIN(name,conf) { \
>   #define PIN_##name conf && msk_GPIO_PIN\
>   #define PORT_##name conf && msk_GPIO_PORT\

Geht nicht.

von Franz F. (franzman)


Lesenswert?

Dr. Sommer schrieb:
> Makros sind ein Relikt aus (Makro-)Assemblern, die es nach C geschafft
> haben. Man sollte sie einfach ganz weglassen. Du kannst beliebige
> Datenstrukturen als Konstanten definieren:
>
1
struct Pin {
2
>   uint8_t port;
3
>   uint8_t pin;
4
> };
5
> 
6
> static const Pin SPI1_MISO { 3, 4 }; // Port 3, Pin 3

Hallo,

wenn ich aber soetwas machen möchte muss ich immer 8 bit werte 
verwenden. Ich wollte es ungefähr so machen.
1
#define msk_GPIO_PIN     0b0000000000001111   //GPIO_Pin_0...15
2
#define msk_GPIO_PORT    0b0000000011110000  //GPIO_Port A...P
3
#define msk_GPIO_PuPd    0b0000001100000000  //00 No Pull
4
                        //01 Pulldown
5
                        //10 Pullup
6
#define msk_GPIO_Speed    0b0000110000000000  //00 GPIO_Speed_Level_1
7
                        //01 GPIO_Speed_Level_2
8
                        //10 GPIO_Speed_Level_3
9
#define msk_GPIO_OType    0b0001000000000000  //0  Push Pull
10
                        //1  Open Drain
11
#define msk_GPIO_Mode    0b0110000000000000   //00 Input
12
                        //01 Output
13
                        //10 Analog
14
                        //11 Alternate Function
15
#define msk_GPIO_Def_Out  0b1000000000000000  //Default state in Output
Deswegen würde es sich anbieten im Präprozessor die Port und Pin als 
eigene Defines zu definieren.

von Dr. Sommer (Gast)


Lesenswert?

Franz F. schrieb:
> wenn ich aber soetwas machen möchte muss ich immer 8 bit werte
> verwenden.
Hä, wieso das? Du kannst natürlich auch uint16_t und uint64_t oder was 
auch immer verwenden...

Franz F. schrieb:
> Deswegen würde es sich anbieten im Präprozessor die Port und Pin als
> eigene Defines zu definieren.
Voll kompliziert. Mach lieber ein Struct mit Portnummer, Pin-Nummer, 
PuPd-Wert, Speed-Wert etc. Dann machst du dir eine Init-Funktion, die 
diesen struct entgegennimmt und den Pin entsprechend initialisiert.

von Bernd K. (prof7bit)


Lesenswert?

Also bei avr-gcc mach ich das so:
1
#define FOO       A,2
2
#define BAR       A,3
3
#define BAZ       B,0
4
5
6
// helper macros
7
#define _SET(type,name,bit)    type##name |= _BV(bit)
8
#define _CLR(type,name,bit)    type##name &= ~_BV(bit)
9
#define _GET(type,name,bit)    (type##name & _BV(bit))
10
11
// use these macros in the application
12
#define SET_AS_OUTPUT(pin)     _SET(DDR,pin)
13
#define SET_AS_INPUT(pin)      _CLR(DDR,pin)
14
#define SET_HIGH(pin)          _SET(PORT,pin)
15
#define SET_LOW(pin)           _CLR(PORT,pin)
16
#define TOGGLE(pin)            _SET(PIN,pin)
17
#define IS_HIGH(pin)           _GET(PIN,pin)
18
19
20
21
[...]
22
23
24
int main(void) {
25
    SET_AS_OUTPUT(FOO);
26
    SET_AS_OUTPUT(BAR);
27
28
    SET_HIGH(FOO);
29
30
    [...]

Der gcc schluckt das anstandslos. Vielleicht kannst Du dieses Verfahren 
sinngemäß anpassen und anwenden. Der Trick besteht einfach im Umweg über 
die Helper-Macros und der Textersetzung die bei der Auflösung der Makros 
stattfindet und aus dem "scheinbar" nur einem Parameter und dem 
geschickt eingesetzten Komma "automagisch" wieder zwei Parameter macht.

von Franz F. (franzman)


Lesenswert?

Bernd K. schrieb:
> #define _SET(type,name,bit)    type##name |= _BV(bit)

Hallo,

das "##" ist ja nicht das Problem.
Der Präprozessor kann anscheinend keine defines in makros ausführen:

http://stackoverflow.com/questions/1135822/escaping-a-symbol-in-a-define-macro

von (prx) A. K. (prx)


Lesenswert?

Franz F. schrieb:
> Der Präprozessor kann anscheinend keine defines in makros ausführen:

So ist es. Und das war schon immer so. Weshalb dir Bernd eine 
Alternative zu deinem Ansatz präsentierte.

: Bearbeitet durch User
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.