Forum: Compiler & IDEs Codingstyle vs Makros


von Codingstyle (Gast)


Lesenswert?

Hallo,

ich frage mich gerade wie man das setzen von Portpins am elegantesten 
und generell allgemein akzeptiert umsetzt.

Variante 1:
1
#define POWERLED_PORT PORTA
2
#define POWERLED_PIN PA0
3
4
//-------------- main
5
6
POWERLED_PORT |= (1<<POWERLED_PIN);
7
POWERLED_PORT &= ~(1<<POWERLED_PIN);

Variante 2:
1
#define POWERLED_PORT PORTA
2
#define POWERLED_PIN PA0
3
#define SET_POWERLED (POWERLED_PORT |= (1<<POWERLED_PIN))
4
#define RESET_POWERLED (POWERLED_PORT &= ~(1<<POWERLED_PIN))
5
6
//-------------- main
7
8
SET_POWERLED;
9
RESET_POWERLED;

Variante 3:
1
#define POWERLED_PORT PORTA
2
#define POWERLED_PIN PA0
3
4
#define SET_PORT(port, pin) (port |= (1<<pin))
5
#define RESET_PORT(port, pin) (port &= ~(1<<pin))
6
7
//-------------- main
8
9
SET_PORT(POWERLED_PORT, POWERLED_PIN);
10
RESET_PORT(POWERLED_PORT, POWERLED_PIN);

Variante 1 ist denke ich mal das üblichste oder ? Dabei sehe ich 
allerdings zum einem Einschränkungen bei der Portierbarkeit des Codes 
und zum anderen wird es schnell unübersichtlich. Beispiel invertierte 
Led. Liest man im Quelltext LEDPORT |= (1<<LED_PIN) weiß man also nicht 
ob die Led wirklich ein- oder ausgeschaltet wird.

Variante 2 würde das Problem umgehen und man könnte das SET_POWERLED 
Define an die entsprechende Polarität anpassen. Allerdings ist es schon 
ein ganzer Batzen mehr Schreibarbeit.

Variante 3 würde zumindest die Portierbarkeit erleichtern das 
invertierte Logik Problem bleibt.

Wie macht man es am schlausten ?

von Sven P. (Gast)


Lesenswert?

Wird noch viel lustiger, wenn du den Port zwischen Ein- und Ausgang 
umschalten musst...

Man erspart sich allerdings vieles, wenn man vorher mal überlegt, wo die 
Abstraktion überhaupt sinnvoll eingezogen wird. D.h., was überhaupt und 
wie weit portabel sein soll.

Eine Status-LED gehört meistens nicht dazu, sodass es sich da nicht 
lohnt, den Zugriff auf den entsprechenden Pin projektweit mit Makros zu 
veröffentlichen. Eher würde ich den gesamten Statusakt wieder in ein 
Modul verpacken und dort dann zwei statische Funktionen led_on() und 
led_off() einbauen -- kostet ja nichts, wird ja als inline realisiert. 
Die LED wird dann indirekt gesteuert über Funktionen, die eine Ebene 
höher/abstrakter ansetzen.

von Fabian O. (xfr)


Lesenswert?

Eine Mischform wäre, den Port fest vorzugeben und nur die Pinnummer bzw. 
Bitmaske zu übergeben. Statt Makros sind Inline-Funktionen schöner:
1
#define LED_PORT  PORTA
2
#define LED_POWER (1 << PA0)
3
#define LED_BUSY  (1 << PA1)
4
// ...
5
6
static inline void leds_on(uint8_t mask)
7
{
8
  LED_PORT |= mask;
9
}
10
11
static inline void leds_off(uint8_t mask)
12
{
13
  LED_PORT &= ~mask;
14
}
15
16
static inline void leds_toggle(uint8_t mask)
17
{
18
  LED_PORT ^= mask;
19
}

Verwendung:
1
leds_on(LED_POWER | LED_BUSY);
2
leds_toggle(LED_BUSY);

Das kann man immer portieren. Falls die LEDs in einem anderen Projekt 
mal an verschiedenen Ports hängen sollten, braucht man in den Funktionen 
zwar Fallunterscheidungen, der Compiler optimiert die aber weg.

von Peter D. (peda)


Angehängte Dateien:

Lesenswert?

Ich mag lieber einfach und gut lesbar:
1
#include "sbit.h"
2
3
4
int main( void )
5
{
6
  DDR_B3 = 1;                   // output
7
  DDR_B7 = 1;
8
9
  for(;;){
10
    PORT_B3 = PIN_D0;
11
    PORT_B7 = !PIN_D0;
12
  }
13
}

von Codingstyle (Gast)


Lesenswert?

Vielen Dank für die Reihe nützlicher Tipps. Die Möglichkeit von inline 
Funktionen war mir garnicht bekannt. Das könnte an der ein oder anderen 
Stelle wirklich nützlich sein.

Jetzt hat es mir allerdings die sbit.h wirklich angetan. Auch wenn mir 
die Benennung über PORT_XX wieder zu distanziert ist. Aussagekräftigere 
Namen würden das ganze wirklich perfekt machen.
1
// Access bits like variables:
2
struct bits {
3
  uint8_t b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1;
4
} __attribute__((__packed__));
5
#define SBIT_(port,pin) ((*(volatile struct bits*)&port).b##pin)
6
#define SBIT(x,y)       SBIT_(x,y)
7
8
#define POWER_LED  SBIT(PORTA, PA0)
9
#define TASTER     SBIT(PINA, PINA1)
10
11
//--------------- main
12
13
POWER_LED = 1;
14
15
if (TASTER) {
16
  if (POWER_LED) {
17
    POWER_LED = 0; 
18
  }
19
}

Würde das obige Beispiel so funktionieren ?

von Klaus (Gast)


Lesenswert?

Codingstyle schrieb:
> Variante 1:#define POWERLED_PORT PORTA
> #define POWERLED_PIN PA0
>
> //-------------- main
>
> POWERLED_PORT |= (1<<POWERLED_PIN);
> POWERLED_PORT &= ~(1<<POWERLED_PIN);

Ich bevorzuge
1
#define POWERLED _LATA0
2
3
POWERLED = 1;

Alles übrige steht im Header File, der mit dem Compiler geliefert wird

MfG Klaus

von Oliver (Gast)


Lesenswert?

Klaus schrieb:
> define POWERLED _LATA0
> POWERLED = 1;

Je nachdem, wie die LED verschaltet ist, schaltest du sie mit der 
Anweisung ein oder aus. Das kann man im Programm nicht erkennen. Nur 
deshalb gibt es ja überhaupt das das Gehampel mit den Makros.

Oliver

von Peter D. (peda)


Lesenswert?

Codingstyle schrieb:
> Aussagekräftigere
> Namen würden das ganze wirklich perfekt machen.

Das bleibt Dir unbenommen, die vordefinierten Namen wollen Dir nur die 
Schreibarbeit erleichtern.
Statt:
1
#define TASTER     SBIT(PINA, PINA1)
Kannst Du auch schreiben:
1
#define TASTER     PIN_A1

von Codingstyle (Gast)


Lesenswert?

@ Peter stimmt so geht es natürlich auch.
Die Variante beseitigt die invertierte Logik aber auch nicht. Macht 
lediglich den Zugriff schön elegant.

Klar man könnte sowas machen:
1
#define POWER_LED  SBIT(PORTA, PA0)
2
#define LED_ON 0
3
#define LED_OFF 1
4
5
POWER_LED = ON;
6
POWER_LED = OFF;

Dann wäre wieder klar was ein und was aus ist.
Wie handhabst du das für gewöhnlich. Einfach mit der invetierten Logik 
leben man selber weiß ja was man tut. Oder einen kleinen Kommentar 
hinter ?

von Codingstyle (Gast)


Lesenswert?

Fast vergessen habe noch eine weitere Frage zu den inline Funktionen.
Wie "wild" kann man es da denn wirklich treiben damit die Funktion auch 
wirklich inline umgesetzt wird ?


Funktioniert inline auch bei Funktionen mit Rückgabewert und auch bei 
Funktionen mit mehr als einem Parameter ?

Sowas beispielsweise:
1
#define POWER_LED_PORT  PORTA
2
#define STATUS_LED_PORT PORTB
3
4
#define POWER_LED PA0
5
#define STATUS_LED PB0
6
7
// Leds mit invertierter Logik
8
static inline void set_led(uint8_t port, uint8_t pin)
9
{
10
  port &= ~(1 << pin);
11
}
12
13
static inline void reset_led(uint8_t port, uint8_t pin)
14
{
15
  port |= (1 << pin);
16
}

oder
1
#define TASTER_PIN  PINA
2
#define TASTER PINA1
3
4
// Eingang mit invertierter Logik auslesen
5
static inline uint8_t get_taster(uint8_t port, uint8_t pin)
6
{
7
  return (port & (1 << pin)) ? 0 : 1;
8
}

von Oliver (Gast)


Lesenswert?

Codingstyle schrieb:
> Funktioniert inline auch bei Funktionen mit Rückgabewert und auch bei
> Funktionen mit mehr als einem Parameter ?

Ja.

Codingstyle schrieb:
> // Leds mit invertierter Logik
> static inline void set_led(uint8_t port, uint8_t pin)
> {
>   port &= ~(1 << pin);
> }

Das geht, hat aber den Nachteil, daß der Compiler das nicht mehr zu 
einem einfachen sbi oder cbi optimieren kann. Da musst du schon bei der 
dem Makro entsprehenden Variante mit echten Konstanten bleiben:
1
static inline void power_led_on()
2
{
3
   POWER_LED_PORT  &=  ~(1 << POWER_LED_PIN);
4
}

Das wäre dann auch meine bevorzugte Alternative.

Oliver

von Codingstyle (Gast)


Lesenswert?

Bei der Taster Auslesevariante hat man das selbe Problem nehme ich an ? 
also müsste auch dort dann für jeden Taster eine Inline Methode her ?

Wobei mir nicht ganz klar ist wo das Problem für den Compiler besteht. 
Unter Inline hätte ich jetzt die Komplette Auflösung der Funktion 
erwartet. Und dabei müsstem dem Compilert die weiten doch bereits 
bekannt sein ?

von mfro (Gast)


Lesenswert?

Codingstyle schrieb:
> Funktioniert inline auch bei Funktionen mit Rückgabewert und auch bei
> Funktionen mit mehr als einem Parameter ?

Ja und ja.

Ob "geinlined" wird oder nicht, hängt u.a. vom Optimierungsgrad ab, der 
beim Compilieren gewählt wird. Mit -Os beispielsweise wird inlining 
WEITGEHEND vermieden.

Nicht eingebettete inlines kann man sich mit -Winline als Warnung 
ausgeben lassen.

Wenn man Inlining unabhängig vom Optimierungslevel erzwingen will, muß 
man die entsprechende Funktion mit

__attribute__((always_inline))

deklarieren.

von Peter D. (peda)


Lesenswert?

Codingstyle schrieb:
> Wie handhabst du das für gewöhnlich.

Man könnte es so machen:
1
#define ON      1       // non inverted
2
#define OFF     (!ON)
3
#define XON     0       // inverted
4
#define XOFF    (!XON)
5
//..
6
if( TASTER == XON )     // low active
7
  LED = ON;             // high active

: Bearbeitet durch User
von Codingstyle (Gast)


Lesenswert?

Ich habe gerade mal versucht folgenden Code zu simulieren bei -O2
1
#include <avr/io.h>
2
3
#define LED_PORT PORTA
4
#define LED PA0
5
6
#define  TASTER_PIN PINB
7
#define TASTER PINB0
8
9
static inline void set_io(uint8_t port, uint8_t pin) {
10
  port |= (1<<pin);
11
}
12
13
static inline uint8_t get_io(uint8_t port, uint8_t pin) {
14
  return (port & (1<<pin)) ? 0 : 1;
15
}
16
17
int main(void)
18
{
19
  if (get_io(TASTER_PIN, TASTER)) {
20
    set_io(LED_PORT, LED);    
21
  }
22
}

Da kommt folgedes im Dissassabmler raus.
1
{
2
00000088  SBIS 0x03,0    Skip if bit in I/O register set 
3
    set_io(LED_PORT, LED);    
4
00000089  IN R24,0x02    In from I/O location 
5
}
6
0000008A  LDI R24,0x00    Load immediate 
7
0000008B  LDI R25,0x00    Load immediate 
8
0000008C  RET     Subroutine return

Da sieht man schön das er die get_io trotz Parameter und und 
Rückgabewert in ein einfaches SBIS übersetzt hat. Was er da bei set_io 
macht kann ich allerdings nicht ganz nachvollziehen.

Versteht jemand was beim set_io passiert ?

von Oliver (Gast)


Lesenswert?

Da du nur get_io zeigst, lässt sich zu set_io nicht viel sagen.

Oliver

von Oliver (Gast)


Lesenswert?

Nachtrag:

Und da da deutlich sichtbar ein ret am Ende steht, ist das auch nicht 
ingelined.

Zeig doch mal das ganze Programm in Assembler.

Oliver

von Codingstyle (Gast)


Angehängte Dateien:

Lesenswert?

Das war eiegntlich alles was im bereich meiner "test.c" stand.

Im Anhang nochmal der komplette ASM Log.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Codingstyle schrieb:

> Wobei mir nicht ganz klar ist wo das Problem für den Compiler besteht.
> Unter Inline hätte ich jetzt die Komplette Auflösung der Funktion
> erwartet. Und dabei müsstem dem Compilert die weiten doch bereits
> bekannt sein ?

Nich alles glauben was hier geschrieben wird.  Wenn der Compiler die 
Werte bei einem Makro kenn, dann kennt er sie auch in einer 
entsprechenden inline-Funktion.

von Codingstyle (Gast)


Lesenswert?

Erklärt aber trotzdem nicht was mit dem set_io() in obigem Code passiert 
oder ?

Das ret am Ende des Codes wird der Rücksprung aus der main sein nehme 
ich jedenfalls stark an.

Zumindest sollte aus der set_io() aber in jedemfall doch entweder ein 
sbi oder ein or resultieren. Keines von beidem kann ich im assambler 
finden. Wo ist das hin verschwunden ?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Die set_io ist falsch geschrieben.  Es ist nicht der Wert des Ports zu 
übergeben, sondern dessen Adresse, z.B. als uint8_t volatile*.

von Codingstyle (Gast)


Lesenswert?

Oh natürlich das erklärt einiges.

von Sven P. (Gast)


Lesenswert?

Die Krücke mit dem 'sbit' wird insgesamt auch nicht besser, wenn man sie 
andauernd wiederholt.

Mit den Bit-Feldern nimmt man sich schließlich jegliche Möglichkeit, den 
Zugriff auf das Bit irgendwie durchzureichen. Es gibt nämlich keine 
Zeiger auf Bitfelder und man kann auch nur schwer wieder eine Bitmaske 
aus der Definition gewinnen.

Für mehr als den Zugriff auf die Pins sollte man das ohnehin nicht 
benutzen, andernfalls schleppt man sich schnell lustige Nebeneffekte 
ein.

von Codingstyle (Gast)


Lesenswert?

was war jetzt nochmal der unschlagbare Vorteil von inline functionen im 
Vergelich zu klassischen Makros ?

Über die "Pointerproblematik" die sich dadurch ergibt das eine Inline 
Funktion nach außen hin natürlich erstmal nichts anderes als eine 
klassiche Funktion ist hatte ich garnicht mehr nachgedacht.
1
static inline void set_io(uint8_t volatile* port, uint8_t pin) {
2
  *port |= (1<<pin);
3
}

Führt dann natürlich auch zu einem entsprechenden Aufruf mit 
set_io(&port, pin) das ist dann schonwieder eine merkwürdige Eigenart 
wenn nicht konsequent durchgezogen.

Ist dann nicht letzlich ein Makro in folgender Form doch wieder schöner 
?
1
#define POWER_LED_PORT PORTA
2
#define POWER_LED PA0
3
4
#define STATUS_LED_PORT PORTA
5
#define STATUS_LED PA1
6
7
// Led setzen invertierte Logik
8
#define SET_LED(port, pin) (port &= ~(1<<pin))
9
#define RESET_LED(port, pin) (port |= (1<<pin))
10
11
//-------------- main
12
13
SET_LED(POWER_LED_PORT, POWER_LED);
14
RESET_LED(POWER_LED_PORT, POWER_LED);

Bei der Variante hätte man den Vorteil für alle vorhanden Leds eine 
einzige Set und Reset "Funktion" zu haben.

Würde man es per inline umsetzen müsste man ja wie gesagt einen Pointer 
auf den Port übergeben. Und das hat man ja im obigen Beispiel schon 
schön gesehen ist man einfach nicht gewohnt. Da würde ich vermutlich 
einfach durch den Tunnelblick der klassichen Variante PORT |= (1<<pin) 
auch immer set_led(port,pin) schreiben und würde somit anstelle der 
Adresse den aktuellen Registerwert übergeben und dabei nichtmal 
Compilerseitig gewarnt.

Das wikte zwar anfangs wie eine für mich schöne Lösung nun nach der 
Einführung von Pointern aber nicht mehr.

Bliebe bei Inline wirklich nur die Variante für jede Led einzelne Set_ 
und Reset_ und eventuell Toggle_ inline Funktionen zu schreiben. Hat man 
5 Leds sind das aber schon 15 inline Methoden. Das sieht dann irgendwo 
auch nicht mehr wirklich schick aus. Also doch wieder zurück zum 
klassischen Makro ?

von Peter D. (peda)


Lesenswert?

Sven P. schrieb:
> Die Krücke mit dem 'sbit' wird insgesamt auch nicht besser, wenn man sie
> andauernd wiederholt.

Das muß auch nicht besser werden, das ist schon gut genug.
Es ist halt nur ziemlich unbekannt, daß es diese Möglichkeit in C gibt.

Es ist auch nicht auf IO-Pins beschränkt, man kann so auch interne 
Bitvariablen definieren.
Ich nehme es daher auch gerne in Steuerungen, wo logische Verknüpfungen 
auszuwerten sind. Denn oft braucht man nicht die Geschwindigkeit eines 
FPGA dafür.

von Codingstyle (Gast)


Lesenswert?

Hi,

ich habe mich jetzt für meinen Fall für folgende Variante entschieden.
Für Module die als solche einen eigenen Wert haben, so das man Sie in 
anderen Projekten wiederverwendet oder eventuell weitergibt verwende ich 
die klassische Vorgehensweise der standard Bitmanipulation. Da hat man 
Sicherheit das es allgemein akzeptiert und verstanden wird.

Für die konkrete speziell Hardware bezogene Implementierung sprich 
Tasterabfragen, Leds, Enable/Select Signale verwende ich die SBIT 
funktion mit dem Bitfeld.

Ich denke mit der Mischung fahre ich so ganz gut.
1
struct bits {
2
  uint8_t b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1;
3
} __attribute__((__packed__));
4
#define SBIT_(port,pin) ((*(volatile struct bits*)&port).b##pin)
5
#define SBIT(x,y)       SBIT_(x,y)
6
7
#define POWER_LED  SBIT(PORTA, PA0)
8
#define TASTER     SBIT(PINA, PINA1)


Eine Frage noch zu SBIT. Wieso wird aus POWER_LED = 1 eine SBI 0x02,0 
Anweisung aus if (TASTER) aber ein IN R24,0x00, SBRC R24,1 ?

von Sven P. (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Das muß auch nicht besser werden, das ist schon gut genug.
> Es ist halt nur ziemlich unbekannt, daß es diese Möglichkeit in C gibt.
Es gibt sie ja auch nur so unter der Hand...
Ohne Compiler-spezifisches Wissen gibt es sie nicht, denn zu Bitfeldern 
ist im Standard fast nichts festgelegt.

> Es ist auch nicht auf IO-Pins beschränkt, man kann so auch interne
> Bitvariablen definieren.
Natürlich, aber da der AVR keinen bitadressierbaren Speicher hat, wird 
immer ein Read-Modify-Write draus. Das kann bei SFR schonmal komische 
Sachen machen.

von Peter D. (peda)


Lesenswert?

Codingstyle schrieb:
> Eine Frage noch zu SBIT. Wieso wird aus POWER_LED = 1 eine SBI 0x02,0
> Anweisung aus if (TASTER) aber ein IN R24,0x00, SBRC R24,1 ?

Du nimmst den Port und castest ihn als Pointer auf eine Struct aus 8 
Bits.
Die Elemente der Struct haben zufälliger Weise eine Ziffer 0..7 am Ende.
Und die Definitionen wie z.B. PINA1 entsprechen einer Ziffer (1). Diese 
Ziffer wird nun mit dem Buchstaben b verbunden und dann wird daraus b1. 
Der Compiler weiß nun, daß er auf das Element b1 der Struct zugreifen 
muß und erzeugt den entsprechenden Code.

Und da die Elemente Bits sind, sind für sie nur die Werte 0 und 1 
zulässig.

von Klaus (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Du nimmst den Port und castest ihn als Pointer auf eine Struct aus 8
> Bits.

Das geht auch für komplexere SFRs
1
__extension__ typedef struct tagOC1CON2BITS {
2
  union {
3
    struct {
4
      unsigned SYNCSEL:5;
5
      unsigned OCTRIS:1;
6
      unsigned TRIGSTAT:1;
7
      unsigned OCTRIG:1;
8
      unsigned OC32:1;
9
      unsigned :3;
10
      unsigned OCINV:1;
11
      unsigned FLTTRIEN:1;
12
      unsigned FLTOUT:1;
13
      unsigned FLTMD:1;
14
    };
15
    struct {
16
      unsigned SYNCSEL0:1;
17
      unsigned SYNCSEL1:1;
18
      unsigned SYNCSEL2:1;
19
      unsigned SYNCSEL3:1;
20
      unsigned SYNCSEL4:1;
21
      unsigned :9;
22
      unsigned FLTMODE:1;
23
    };
24
  };
25
} OC1CON2BITS;
26
extern volatile OC1CON2BITS OC1CON2bits __attribute__((__sfr__));
Hier kann man auf SYNCSEL als 5 Bit Integer oder auch auf SYNCSEL0 bis 4 
als Einzelbits zugreifen. Da ist dann auch gleich ein Problem in der 
Doku gefixt worden, FLTMD kann auch als FLTMODE geschrieben werden.

Und wenn es Sinn macht, kann man sich via #define für 
OC1CON2bits.SYNCSEL einen eigenen Namen ausdenken.

Sven P. schrieb:
> Es gibt sie ja auch nur so unter der Hand...
> Ohne Compiler-spezifisches Wissen gibt es sie nicht, denn zu Bitfeldern
> ist im Standard fast nichts festgelegt.

IMHO ist da in neueren C Standards schon etwas beschrieben. Aber wenn 
das in den Headerfiles vom Chip und Compilerlieferanten so gemacht wird, 
hab ich damit kein Problem. Sollte sich da etwas ändern, wird sämtlicher 
(professioneller) C-Code obsolete und den Chiphersteller gibt es dann 
nicht mehr.

MfG Klaus

von Codingstyle (Gast)


Lesenswert?

Hm wie der Cast funktioniert war mir eigentlich schon klar soweit.
Was mir aber noch immer nicht klar ist wieso aus einem einfachen setzen 
des Bits ein schneller SBI Befehl wird. Aus dem auslesen aber kein SBIS 
und aus togglen kein EOR sonder sowas:

0000008A  IN R25,0x02    In from I/O location
0000008B  COM R25    One's complement
0000008C  ANDI R25,0x01    Logical AND with immediate
0000008D  IN R24,0x02    In from I/O location
0000008E  ANDI R24,0xFE    Logical AND with immediate
0000008F  OR R24,R25    Logical OR
00000090  OUT 0x02,R24    Out to I/O location

Klar macht es für die meisten Anwendungen absolut keinen Sinn jeden 
einzelnen Assamblerbefehl aufzuwiegen. Aber inperformanter als die 
standard Bitschubserei ist es schon oder ?

von Peter D. (peda)


Lesenswert?

Codingstyle schrieb:
> Aus dem auslesen aber kein SBIS
> und aus togglen kein EOR sonder sowas:

SBIS macht er, nur beim togglen ist er etwas umständlich:
1
      PORT_B0 = 1;
2
  84:  28 9a         sbi  0x05, 0  ; 5
3
      PORT_B1 = 0;
4
  86:  29 98         cbi  0x05, 1  ; 5
5
      if( PIN_B2 == 1 )
6
  88:  1a 99         sbic  0x03, 2  ; 3
7
        PORT_B3 = 1;
8
  8a:  2b 9a         sbi  0x05, 3  ; 5
9
      PORT_A0 ^= 1;
10
  8c:  82 b1         in  r24, 0x02  ; 2
11
  8e:  81 70         andi  r24, 0x01  ; 1
12
  90:  82 27         eor  r24, r18
13
  92:  92 b1         in  r25, 0x02  ; 2
14
  94:  9e 7f         andi  r25, 0xFE  ; 254
15
  96:  98 2b         or  r25, r24
16
  98:  92 b9         out  0x02, r25  ; 2
17
      PORTC ^= 1<<0;
18
  9a:  88 b1         in  r24, 0x08  ; 8
19
  9c:  82 27         eor  r24, r18
20
  9e:  88 b9         out  0x08, r24  ; 8

von Codingstyle (Gast)


Lesenswert?

Mit welchem Optimierungslevel hast du compiliert ?
Bei mir macht er bei if (PIN_B2) immer:
00000088  IN R24,0x00    In from I/O location
00000089  SBRS R24,1    Skip if bit in register set

Also nicht direkt SBSI aus Register sonder erst Register auslesen und 
dann SBSR.

von Peter D. (peda)


Lesenswert?

Codingstyle schrieb:
> Mit welchem Optimierungslevel hast du compiliert ?

Standard also -Os
Die schwächeren Optimierungen bringen nur ganz selten was.

: Bearbeitet durch User
von Codingstyle (Gast)


Lesenswert?

Mit -Os komme ich auch auf deine Befehlskette.

Vielen Dank für die Hilfe :)

von sebastian (Gast)


Lesenswert?

> was war jetzt nochmal der unschlagbare Vorteil von inline functionen im
> Vergelich zu klassischen Makros ?

Es gibt nicht den einen unschlagbaren Vorteil, und nicht jeder greift in 
diesem Use-Case.

Hier sind die, die mir gerade so einfallen:

- sie kümmern sich um namespaces. Nur für C++ relevant.
- du bekommst eine Typprüfung.
- Wenn du eine Compilerfehlermeldung bekommst, weil du sie falsch 
aufgerufen hast, dann musst du nur den Aufruf und den Prototypen 
anschauen. Bei Makros kanns sein, dass du viele Makros anschauen musst.
- sie werten ihre Parameter nur einmal aus (und haben nur einmal 
Seiteneffekte). Hier nicht relevant weil jeder Parameter nur einmal 
vorkommt.
- Der Fehler, dass du die Klammerung vergisst, passiert nicht. Die 
meisten hier sinnvollen Operatoren binden stärker als <<, aber der ?: 
operator könnte mal im pin vorkommen.

> #define SET_LED(port, pin) (port &= ~(1<<pin))
> #define RESET_LED(port, pin) (port |= (1<<pin))

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.