Variablenwert(0/1) einem Ausgangspin zuordnen

OP #2568314
Lesenswert?

Hallo,
ich wollte mal fragen, ob das auch eleganter geht:
1
if (anAus)
2
{
3
    PORTB |= (1<<PB0)
4
}
5
    else
6
{
7
    PORTB &= ~(1<<PB0)
8
}
Die Variable kommt aus einem größeren Programm, ich muss sie also in der 
Form haben.

Mir wäre etwas in dem Stiel:
"PinX = anAus" lieber.

Ich habe den Code gleich 10mal in einer ISR, deshalb hätte ich es gern 
etwas schlanker ;)

Für einen hilfreichen Tipp bin ich dankbar.

Gruß,
Tobi
#2568323
Lesenswert?

Ein Fest a. schrieb:

> Ich habe den Code gleich 10mal in einer ISR, deshalb hätte ich es gern
> etwas schlanker ;)

Das sieht nur in C so behäbig aus. Der Compiler macht das schon ziemlich 
schlank.

In C kannst du noch syntaktischen Zucker drüberstreuen, damit es nicht 
ganz so behäbig aussieht. Aber am Prinzip ändert sich dadurch nichts.

zb kannst du dir die Details in einem Makro verstecken.
#2568431
Lesenswert?

Karl Heinz Buchegger schrieb:
> In C kannst du noch syntaktischen Zucker drüberstreuen, damit es nicht
> ganz so behäbig aussieht. Aber am Prinzip ändert sich dadurch nichts.

Z.B. mit meiner sbit.h
1
if (anAus)
2
{
3
    PORT_B0 = 1;
4
}
5
    else
6
{
7
    PORT_B0 = 0;
8
}

Man könnte auch schreiben:
1
  PORT_B0 = !!anAus;
Aber das ergibt größeren Code.


Peter
Angehängte Dateien:
#2568449
Lesenswert?

Peter Dannegger schrieb:
> Karl Heinz Buchegger schrieb:
>> In C kannst du noch syntaktischen Zucker drüberstreuen, damit es nicht
>> ganz so behäbig aussieht. Aber am Prinzip ändert sich dadurch nichts.
>
> Z.B. mit meiner sbit.h
>
1
> if (anAus)
2
> {
3
>     PORT_B0 = 1;
4
> }
5
>     else
6
> {
7
>     PORT_B0 = 0;
8
> }
9
>

Was mich immer schon mal interessiert hat.
Kriegt der gcc das hin, dass er da Einzelbitoperationen draus macht, 
oder erledigt er das über Read/Modify/Update?
#2568827
Lesenswert?

>     PORT_B0 = 1;
>   86:   c0 9a           sbi     0x18, 0 ; 24

Hey. cool.

Deine Struktur-Geschichte hätte nämlich einen reisengroßen Vorteil. Man 
könnte für alle Hardwareregister eine entsprechende Struktur generieren, 
mit sauberen Bitnamen:

   TIMSK.TOIE0 = TRUE;

und wenn das TIEO1 Bit bei einem µC nicht im TIMSK Register ist, dann 
schreit der Compiler. Die "klassischen" Fehler, dass die WGM Bits in 2 
verschiedenen Config-Register sind, wären damit entschärft.

Bzw. dann weitergehend überhaupt nur noch

   TOIE0 = TRUE;

und der Compiler "sucht selber raus", in welchem Register das 
entsprechende Bit sitzt.

Das wär schon was.
#2570163
Lesenswert?

Ich häng' mich mal rein.
Könnte sowas in der ein oder anderen Situation nicht noch 
übersichtlicher sein:
1
//                      Access bits like variables:
2
// frei nach Peter Dannegger
3
struct bits {
4
  uint8_t b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1;
5
} __attribute__((__packed__));
6
/*
7
#define SBIT_(port,pin) ((*(volatile struct bits*)&port).b##pin)
8
#define SBIT(x,y)       SBIT_(x,y)
9
*/
10

11
#ifdef PORTD
12
#define PortD  (*((volatile struct bits*)&PORTD))
13
#endif // PORTD

Aufruf:
1
PortD.b2 = 1;
#2570195
Lesenswert?

Ralf G. schrieb:
> Ich häng' mich mal rein.
> Könnte sowas in der ein oder anderen Situation nicht noch
> übersichtlicher sein:

Läuft ja im Kern aufs selbe raus.


> Aufruf:
>
1
> PortD.b2 = 1;
2
>


So wie Peter das macht, geht das ja noch einen Schritt weiter. In einem 
realen Programm wirst du ja nicht, oder nur selten, an PortD.b2 etwas 
zuweisen. Denn an dem Pin hängt ja etwas. Zb eine Error Led oder eine 
Busy LED. D.h. du möchtest gerne schreiben:
1
#define ERROR_LED   SBIT( PORTD, 2 )
2
#define BUSY_LED    SBIT( PORTD, 3 )
3

4
...
5

6
   ERROR_LED = 1;
7
   BUSY_LED = 0;

Sein SBIT Makro dient dazu, eine Verknüpfung zwischen Port und Pin zu 
schaffen, damit man im eigentlichen Code überhaupt nichts nacharbeiten 
muss, wenn Funktionseinheiten ihre Pinzuordnung wechseln.
Gast #2570212
Lesenswert?

1
#define PortD  (*((volatile struct bits*)&PORTD))

Kann man wirklich immer so auch auf DDRD und PIND zugreifen??
ich mein so: (ich weiß nicht, ob die '+1' so stimmt, aber ich meine ja 
nr vom Prinzip her...
1
#define PinD  (*((volatile struct bits*)&(PORTD+1)))

Gruß Sepp
#2570304
Lesenswert?

Karl Heinz Buchegger schrieb:
>
> Läuft ja im Kern aufs selbe raus.
>
> ...
>
> So wie Peter das macht, geht das ja noch einen Schritt weiter. In einem
> realen Programm wirst du ja nicht, oder nur selten, an PortD.b2 etwas
> zuweisen.

Naja, es wird sozusagen aus dem Port dann eine Datenstruktur.
So wie bei:

Karl Heinz Buchegger schrieb:
> TIMSK.TOIE0 = TRUE;

Das 'PORT_D2' wollte ich vermeiden.

> Denn an dem Pin hängt ja etwas. Zb eine Error Led oder eine
> Busy LED. D.h. du möchtest gerne schreiben:
> #define ERROR_LED   SBIT( PORTD, 2 )
> #define BUSY_LED    SBIT( PORTD, 3 )
>
> ...
>
>    ERROR_LED = 1;
>    BUSY_LED = 0;
>
> Sein SBIT Makro dient dazu, eine Verknüpfung zwischen Port und Pin zu
> schaffen, damit man im eigentlichen Code überhaupt nichts nacharbeiten
> muss, wenn Funktionseinheiten ihre Pinzuordnung wechseln.

Das wäre dann mit direktem Zugriff auf SBIT. Mmh, auch eine Möglichkeit.

Vielleicht noch zur Disskusion:
1
#define PinB_(n)  ((*((volatile struct bits*)&PINB)).b##n)
2

3
// ...
4

5
 if ( PinB_(1 << B_EIGENES) == 0 )
6
 {
7
// ...
8
 }
Naja, vielleicht auch nicht besser als:
1
 if ( (~PINB) & (1 << B_EIGENES) )
2
 {
3
// ...
4
 }
#2570360
Lesenswert?

Ralf G. schrieb:

> Vielleicht noch zur Disskusion:

Wie immer du das machen willst.
Eines muss sowieso klar sein: Das alles ist nur syntaktischer Zucker auf 
C-Ebene. Wenn unten nach dem compilieren sowieso wieder das gleiche raus 
kommst, geht es nur darum, wie man das Zeugs dann im Code so verwenden 
kann, dass man möglichst wenig Fehler machen kann. Und wenn, soll der 
Compiler sie abfangen können.

>  if ( PinB_(1 << B_EIGENES) == 0 )

> Naja, vielleicht auch nicht besser als:

>  if ( (~PINB) & (1 << B_EIGENES) )


Der springede Punkt um den es mir an dieser Stelle geht besteht darin, 
dass du im Code hier 2 Informationen stehen hast, die zusammenstimmen 
müssen:

* welcher Port
* welches Bit an diesem Port

Du hast also eine mögliche Fehlerquelle, indem du zwar das richtige Bit 
aber am falschen Port angibst. Kein Compiler hilft dir dabei, wenn du 
schreibst

   if( PinD_( B_EIGENES ) == 0 )   // OOps, sollte eigentlich PinB sein!

Muss ich selber aber an dieser Stelle keine 2 Informationen in 
Übereinstimmung bringen

   if( B_EIGENES == 0 )

und durch die Makroexpansion expandiert das zum richtigen Bit am 
richtigen Port, dann hab ich eine potentielle Fehlerquelle weniger.

D.h. neben den syntaktischen Zucker, hat das ganze Abspecken durchaus 
einen ernsten Hintergrund in der passiven Programmierung.
#2570634
Lesenswert?

Ralf G. schrieb:
> Karl Heinz Buchegger schrieb:
>> if( B_EIGENES == 0 )
>
> Was ist jetzt schon wieder 'B_EIGENES'? Könnte man hier fragen.

:-)

Kann man.
Du bist doch mit dem B_EIGENES hochgekommen.

In der Realität steht dann da eben

   if( DRUCK_ALARM )


weil DRUCK_ALARM dann eben so definiert ist, dass das ein Eingangspin am 
Port C, Pin 5 ist, an dem der Wasserdrucksensor einen Überdruck anzeigt.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren