Forum: Mikrocontroller und Digitale Elektronik cleveres gpio macro for c


von HansImGlück (Gast)


Lesenswert?

... nichts für Macro Hasser und simple Thinker!
Hat so einen Hauch von objektorientierter Programmierung ...

Verwendungsbeispiel:
 gpioPIN(LED, B, 1); //"object/methodes" creation, name/port/pin
 writeLED(0); //init as output, led off
 toggleLED();
 clearLED();
 setLED();

 gpioPIN(BUTTON1, B, 2);
 BUTTON1onPUP();
 uint8_t key = readBUTTON1();
 ...

AVR/GCC inline Syntax
1
#define gpioPIN(name, port, pin) \
2
  inline uint8_t __attribute__((always_inline)) read##name() { \
3
    DDR##port &= ~(1<<PIN##port##pin); \
4
    PORT##port |= (1<<PIN##port##pin); /* dedicated pull-up on */ \
5
    /*MCUCR &= ~(1<<PUD);*/ /* enable pull-up globally */\
6
    return PIN##port & (1<<PIN##port##pin); \
7
  } \
8
  inline void __attribute__((always_inline)) write##name(uint8_t val) { \
9
    PORT##port |= (1<<PIN##port##pin); /*trisate*/\   
10
    if (!val) PORT##port &= ~(1<<PIN##port##pin); \
11
    DDR##port |= (1<<PIN##port##pin); \
12
  } \
13
  inline void __attribute__((always_inline)) onPUP##name() { \
14
    MCUCR &= ~(1<<PUD); \
15
  } \
16
  inline void __attribute__((always_inline)) offPUP##name() { \
17
    MCUCR |= (1<<PUD); /* tristate if input */\
18
  } \
19
  inline void __attribute__((always_inline)) set##name() { \
20
    PORT##port |= (1<<PIN##port##pin); \
21
  } \
22
  inline void __attribute__((always_inline)) clear##name() { \
23
    PORT##port &= ~(1<<PIN##port##pin); \
24
  } \
25
  inline void __attribute__((always_inline)) toggle##name() { \
26
    PIN##port |= (1<<PIN##port##pin); \
27
  } \

von Veit D. (devil-elec)


Lesenswert?

Hallo,

mach aus
1
#define gpioPIN(name, port, pin)
eine richtige Funktion oder gleich eine Klasse und du bist auf dem 
richtigen Weg.  :-)

von Walter T. (nicolas)


Lesenswert?

Langweilig. Geht alles ohne Makro-Magie mit normalen Inline-Funktionen.
1
    #ifndef static_inline
2
        #define static_inline static inline __attribute__((always_inline))
3
    #endif
4
5
  /** Byte strecken, indem jedes Bit verdoppelt wird (16 -> 32 Bit)
6
   *
7
   * z.B.: 01001100 01001100 -> 0011000011110000 0011000011110000
8
   * Die Funktion sollte mit konstantem Parameter aufgerufen werden, damit sie
9
   * statisch wegoptimiert werden kann.
10
   *
11
   * @param[in] byte: Bitmaske
12
   * @return gestreckte Bitmaske */
13
  static_inline uint32_t stretch2bitmask16(const uint16_t word)
14
  {
15
      uint32_t out = 0;
16
      out |= word & 0x0001U ?  0x00000003U : 0;
17
      out |= word & 0x0002U ?  0x0000000CU : 0;
18
      out |= word & 0x0004U ?  0x00000030U : 0;
19
      out |= word & 0x0008U ?  0x000000C0U : 0;
20
      out |= word & 0x0010U ?  0x00000300U : 0;
21
      out |= word & 0x0020U ?  0x00000C00U : 0;
22
      out |= word & 0x0040U ?  0x00003000U : 0;
23
      out |= word & 0x0080U ?  0x0000C000U : 0;
24
      out |= word & 0x0100U ?  0x00030000U : 0;
25
      out |= word & 0x0200U ?  0x000C0000U : 0;
26
      out |= word & 0x0400U ?  0x00300000U : 0;
27
      out |= word & 0x0800U ?  0x00C00000U : 0;
28
      out |= word & 0x1000U ?  0x03000000U : 0;
29
      out |= word & 0x2000U ?  0x0C000000U : 0;
30
      out |= word & 0x4000U ?  0x30000000U : 0;
31
      out |= word & 0x8000U ?  0xC0000000U : 0;
32
      return out;
33
  }
34
35
36
37
38
    /** Einzelne Pins eines Ports per Bitmaske als open-drain-Output setzen.
39
     *
40
     * Funktioniert auch mit GPIO-Pin-Paerchen-Makros, z.B. io_setOutputOD(PA0)
41
     *
42
     * @param[in] GPIOx: GPIO
43
     * @param[in] pin: Pins als Bitmaske */
44
    static_inline void io_setOutputOD(GPIO_t * GPIOx, const IOPin_t pin)
45
    {
46
        GPIOx->MODER  |= stretch2bitmask16(pin) & 0x55555555;
47
        GPIOx->OTYPER |= pin;
48
    }

: Bearbeitet durch User
von Michael B. (laberkopp)


Lesenswert?

HansImGlück schrieb:
> Verwendungsbeispiel

gpio ist aber auch ein I und nicht nur ein O

Was macht MCUCR bei PullUps/Downs ?

von HansImGlück (Gast)


Lesenswert?

Michael B. schrieb:
> gpio ist aber auch ein I und nicht nur ein O
ja!

> Was macht MCUCR bei PullUps/Downs ?
io-pin pull-up on/off!


3 comments und nur Mist, diese Mittelmässigkeit tut richtig weh!

von sid (Gast)


Lesenswert?

HansImGlück schrieb:
> diese Mittelmässigkeit tut richtig weh!

..immer geil wenn man sich selber für den Grössten hält ...
..immer blöd wenn niemand anderes das auch so sieht ...
..immer schlau mal selbstreflektierend zu ergründen warum dem so ist

Shalömmchen

von A. S. (Gast)


Lesenswert?

So ganz pfiffig. Würde ich aber nicht verwenden, weil die IDE die 
Funktionen nicht findet. Wenn ich irgendwo "writeLED(0);" sehe im Code, 
möchte ich wissen, was genau da passiert und da hinspringen können.

Deshalb (und nur deshalb) würde ich hier statt Präprozessor einen 
Textfresser bemühen, der mir aus z.B. einer Leds.txt mit entsprechen 
Einträgen wie "LED B 1" eine Leds.h mit Deinen Funktionen explizit 
macht.

Ja, ist quasi copy and paste, aber kein Codesmell, wenn es 
automatisiert erfolgt.

von Rolf M. (rmagnus)


Lesenswert?

sid schrieb:
> HansImGlück schrieb:
>> diese Mittelmässigkeit tut richtig weh!
>
> ..immer geil wenn man sich selber für den Grössten hält ...
> ..immer blöd wenn niemand anderes das auch so sieht ...
> ..immer schlau mal selbstreflektierend zu ergründen warum dem so ist

Ob das so ist, kann ich nicht beurteilen. Aber diese drei Antworten sind 
tatsächlich alle unsinnig. Die Antwortenden haben sich das Makro 
offenbar entweder nicht wirklich angesehen oder es nicht verstanden.

A. S. schrieb:
> Deshalb (und nur deshalb) würde ich hier statt Präprozessor einen
> Textfresser bemühen, der mir aus z.B. einer Leds.txt mit entsprechen
> Einträgen wie "LED B 1" eine Leds.h mit Deinen Funktionen explizit
> macht.

Genau. Man muss nicht für alles den Präprozessor verwenden. Gerade für 
solche automatische Codegenerierung sind Skriptsprachen wie z.B. python 
prädestiniert.

von sid (Gast)


Lesenswert?

Rolf M. schrieb:
> Aber diese drei Antworten sind
> tatsächlich alle unsinnig. Die Antwortenden haben sich das Makro
> offenbar entweder nicht wirklich angesehen oder es nicht verstanden.
findste? Ich find
Veit D. schrieb:
> mach aus...eine Klasse und du bist auf dem
> richtigen Weg.  :-)

war garnicht so verkehrt,
denn ich stimme

A. S. schrieb:
> weil die IDE die
> Funktionen nicht findet. Wenn ich irgendwo "writeLED(0);" sehe im Code,
> möchte ich wissen, was genau da passiert und da hinspringen können.

dem durchaus zu, besonders bei umfangreicherem Quelltext ist das ganz 
hilfreich mindestens n paar Monate später..
und wenn ich Dich recht verstehe bist Du nicht völlig anderer Ansicht

Rolf M. schrieb:
> Genau. Man muss nicht für alles den Präprozessor verwenden.

Das nervtötende am TO ist "guck wie clever" und "nix für Weichhirne"
"schau wie geil ich bin" "Ihr seit alle nur Mittelmass, ich bin alpha!"

selbst wenn die Idee richtig (oder sagen wir nicht völlig blödsinning) 
ist bringt mich das zum Augenrollen..
(um nicht "kotzen" zu sagen ;))

'sid

PS ADC mit zehn/zwölf bit... super Sache... achje...uiuiui

Beitrag #6215122 wurde von einem Moderator gelöscht.
von DasTutWeh (Gast)


Lesenswert?

... der sinile Männerklub führt wieder seine Selbstgespräche!

Mir gefällt die Idee des To und wann begreifen die Macroahnungslosen 
mal, dass der Präprozessor Teil der C Programmiersprache ist und kein 
Spielzeug für Verwirrte.

Für blinky Led braucht es auch keinen ARM oder C++ ...

von A. S. (Gast)


Lesenswert?

DasTutWeh schrieb:
> Mir gefällt die Idee des To und wann begreifen die Macroahnungslosen
> mal, dass der Präprozessor Teil der C Programmiersprache ist und kein
> Spielzeug für Verwirrte.

Das es funktioniert, geschenkt. (bzw. Egal, ich hab den Code nicht 
ausprobiert). Und ich nutze den präprozessor weit mehr als jeder 
Standard erlaubt. Aber wenn ich so kryptischen Code wollte (im Sinne 
von: writeLED?, suche über alle sourcen, was das denn ist), dann könnte 
ich auch C++ nehmen.

von DasTutWeh (Gast)


Lesenswert?

A. S. schrieb:
> Aber wenn ich so kryptischen Code wollte (im Sinne
> von: writeLED?,

Ja stimmt, der Bezeichner macht keinen Sinn, da clear/set() das 
abdecken.
@To, Dann wohl eher es initLed(...) nennen!

von Rolf M. (rmagnus)


Lesenswert?

sid schrieb:
> Ich find
> Veit D. schrieb:
>> mach aus...eine Klasse und du bist auf dem
>> richtigen Weg.  :-)
>
> war garnicht so verkehrt,

Abgesehen davon, dass wir über C sprechen, wie würdest du das als Klasse 
genauso effizient umsetzen? Da könnte man höchstens mit Templates was 
basteln, was aber auch nicht einfacher werden wird als das Makro.

> und wenn ich Dich recht verstehe bist Du nicht völlig anderer Ansicht

Richtig. Ich hätte aber wie gesagt eher ein Skript geschrieben, das den 
Code generiert, statt das über Makro-Magie zu machen. Ist leichter 
lesbar und flexibler.

> Das nervtötende am TO ist "guck wie clever" und "nix für Weichhirne"
> "schau wie geil ich bin" "Ihr seit alle nur Mittelmass, ich bin alpha!"

Ich hatte ehrlich gesagt die erste Zeile des Ursprungspostings 
übersehen. Vielleicht hätt ich sonst auch anders reagiert.

> selbst wenn die Idee richtig (oder sagen wir nicht völlig blödsinning)
> ist bringt mich das zum Augenrollen..

Also ich finde die Idee jetzt nicht völlig blödsinnig, aber auch nicht 
unbedingt supergenial.

von foobar (Gast)


Lesenswert?

Ich find die Idee an sich nicht verkehrt - das sind Templates in C.  Die 
API gefällt mir nicht, aber jeder nach seiner Façon ...

Und weil's noch keiner erwähnt hat: das "|=" in der Toggle-Funktion ist 
falsch - muss "=" sein.

von sid (Gast)


Lesenswert?

Rolf M. schrieb:
> Abgesehen davon, dass wir über C sprechen, wie würdest du das als Klasse
> genauso effizient umsetzen?

Ohje.. mein Fehler.. ich lese "GCC" und denke "C++"
stimmt.. wird ..uhm...eher "unhandlich" :D
Anderenfalls wär es ja Hupe ob ich LEDwrite(0) oder LED.write(0)
tippe gell ;)

'sid

von sid (Gast)


Lesenswert?

foobar schrieb:
> Und weil's noch keiner erwähnt hat: das "|=" in der Toggle-Funktion ist
> falsch - muss "=" sein.

vielleicht hat's keiner erwähnt weil's nicht falsch ist ;)
Ich zitiere mal aus einem Wahllosen Datenblatt (attiny13a in dem fall)
-------Zitat-------
The Port Input Pins I/O location is read only, while the Data Register
and the Data Direction Register are read/write. However, writing a logic
one to a bit in the PINx Register, will result in a toggle in the
corresponding
bit in the Data Register.
-------Zitatende-------
steht so in jedem das mir bisher unterkam...

'sid

von Oliver S. (oliverso)


Lesenswert?

sid schrieb:
> steht so in jedem das mir bisher unterkam...

Das steht so in jedem Datenblatt bei den Prozessoren, die das Feature 
haben. Die älteren haben das nicht.

Oliver

von S. R. (svenska)


Lesenswert?

sid schrieb:
> steht so in jedem das mir bisher unterkam...

Die Toggle-Funktionalität gibt es m.W. nicht auf jedem AVR.

von foobar (Gast)


Lesenswert?

> However, writing a logic one to a bit in the PINx Register, will
> result in a toggle in the corresponding bit in the Data Register.

Und wieviele Einer-Bits schreibst du bei z.B. "PINx |= 1" oder 
ausgeschrieben "PINx = PINx | 1"?

von Rolf M. (rmagnus)


Lesenswert?

foobar schrieb:
>> However, writing a logic one to a bit in the PINx Register, will
>> result in a toggle in the corresponding bit in the Data Register.
>
> Und wieviele Einer-Bits schreibst du bei z.B. "PINx |= 1" oder
> ausgeschrieben "PINx = PINx | 1"?

Das kommt drauf an, welche Instruktion der Compiler draus macht. Bei 
einem sbi genau eines. Bei einem in/ori/out (bzw. ld/ori/st) mindestens 
so viele, wie vorher Pins gesetzt waren.

: 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.