Pin in abhängigkeit einer variablen ein/aus-schalten

Gast #7352781
Lesenswert?

guten abend, ich habe ein kleines logisches Problem.

Ich möchte den Pin (AVR) anhand einer variable setzen. Dies habe ich bisher mittels einer if-Bedingung

1
if(1 == ledOn)
2
{
3
  DDRD |= (1 << PIND3);
4
}
5
else
6
{
7
  DDRD &= ~(1 << PIND3);
8
}

gibt es da auch einen eleganteren weg, wo ich direkt den wert der Variable benutzen kann?

Gast #7353580
Lesenswert?

Dominik schrieb:

gibt es da auch einen eleganteren weg, wo ich direkt den wert der Variable benutzen kann?

Man kann den Code hinter einem Makro verbergen:

1
#define writeBit(port,bit,value) { if ((value)>0) (port) |= (1<<bit); else (port) &= ~(1<<bit); } 
2

3
writeBit(DDRD,3,ledOn)

Aber wirklich eleganter ist das auch nicht. Ich habe früher zu viele solcher Makros verwendet. Sie verschleiern, was wirklich passiert. Dadurch provozieren sie falsche Verwendung und machen Fehlermeldungen schwerer verständlich.

Eine ganz normale C Funktion ist gut lesbar und produziert in der Regel genau den gleichen Maschinencode, ist also nicht ineffizient:

1
void setze_status_led(bool ein) 
2
{
3
    if(ein)
4
    {
5
       DDRD |= (1 << PIND3);
6
    }
7
    else
8
    {
9
       DDRD &= ~(1 << PIND3);
10
    }
11
}
12

13
setze_status_led(ledOn);

Wobei man auch aufpassen muss, wie man die Variable nennt. "ledOn" kann die LED nämlich auch aus schalten. Gute passende Namen sind wichtig, falls es kein Wegwerf-Projekt ist.

#7353593
Lesenswert?

Jim M. schrieb:

Rolf M. schrieb:

Idealer- und ästhetischerweise nutzt man dafür einen bool, dann ist das automatisch gegeben.

Nö, ist es AFAIK nicht - und kann einem bei -Os oder -O3 auf die Füße fallen.

Nein.

Der Optimizer darf das in einem ganzen Register belassen, damit sind auch Werte <0 oder >1 möglich.

Der interne Wert, den der Compiler für einen bool nutzt, kann dir aber egal sein. Wenn man ihn in einen Integer konvertiert, kommt immer 0 für false und 1 für true raus. Das garantiert der Standard.

Gast #7353607
Lesenswert?

Stefan F. schrieb:

eleganter

Über "elegant" kann man streiten.

Hier ein eleganter und optimierter "Arduino" Code:

1
#include <CombiePin.h>
2

3
using Led = Combie::Pin::OutputPin<LED_BUILTIN>;
4

5
int main() 
6
{
7
   Led{}.init();
8
   Led{} = 1;
9
   while(1);
10
}

Und das zugehörige Kompilat:

1
00000080 <main>:
2
          #endif  
3
        }
4
        
5
        void  INLINE initOutput()
6
        {
7
            *getDdrPort(arduinoPin) |= getMaske(arduinoPin);
8
  80:  25 9a         sbi  0x04, 5  ; 4
9

10
00000082 <.LBB23>:
11
          return *getInPort(arduinoPin)  &  getMaske(arduinoPin);
12
        }
13
    
14
        void  INLINE setHigh()
15
        {
16
          *getOutPort(arduinoPin)  |=  getMaske(arduinoPin);
17
  82:  2d 9a         sbi  0x05, 5  ; 5
18

19
00000084 <.L2>:
20

21
int main() 
22
{
23
   Led{}.init();
24
   Led{} = 1;
25
   while(1);
26
  84:  ff cf         rjmp  .-2        ; 0x84 <.L2>
Gast #7353622
Lesenswert?

Die Frage ist also, was du eigentlich wolltest und warum das alles.

Das Problem ist doch gerade, jeder Programmiere wählt die Lösung, die ihm persönlich am besten gefällt.

Dominiks ursprüngliches Beispiel ergibt ewig langen Programmcode. Nach dem runter scrollen hat man schon wieder vergessen, was oben stand.

Arduinos digitalWrite() ist zwar kompakt, hat sich aber außerhalb der Arduino Welt nicht durchgesetzt.

Jeder bastelt da irgend etwas anderes. Der Code lässt sich nicht wiederverwenden. Nachvollziehen, was die Macros, Wrapper und Frameworks machen, wird aufwendiger als komplett neu entwickeln.

Nimm als Beispiel die Normen aus Maschinenbau oder Bauwesen. Alle Ingenieure benutzen die selben Symbole und die selben Bezeichnungen. Jeder sieht auf den ersten Blick, was der Kollege konstruiert hat.

Wieso können wir uns nicht auf einen einheitlichen Weg einigen?

Gast #7353623
Lesenswert?

EAF schrieb:

Und das zugehörige Kompilat:

Das der Compiler so etwas gut optimieren kann, brauchst du nicht zu beweisen. Das Thema hatten wir schon oft genug. Auch eine ganz normale Funktion erzeugt in der Regel den selben optimalen Maschinencode.

Die Frage nach der "Ästhetik" finde ich viel wichtiger.

Eine Anmerkung schrieb:

Arduinos digitalWrite() ist zwar kompakt, hat sich aber außerhalb der Arduino Welt nicht durchgesetzt.

Der Maschinencode der dabei heraus kommt ist aber alles andere als Kompakt. Wenn man sich mal den Quelltext der Funktion anschaut, wundert mich das auch nicht. Da passiert ja noch einiges mehr, als nur den einzelnen PIN auf HIGH oder LOW zu setzen. Womit wir wieder beim "verschleiern" sind. Die Funktion macht mehr, als ihr Name suggeriert, was ich nicht gut finde. Andererseits ist sie trotz der Verschleierung halbwegs deppensicher, das muss man auch mal würdigen.

Gast #7353749
Lesenswert?

Hi

Und doch gibt es hier weiterhin eine "Arduino Basher" und "C++ auf µC ist ineffektiv/unsinnig" Fraktion.

Immer noch die gleichen Phrasen, die du schon als 'Arduino Fanboy' von dir gegeben hast.

MfG Spess

#7354338
Lesenswert?

Dominik schrieb:

guten abend, ich habe ein kleines logisches Problem.

Ich möchte den Pin (AVR) anhand einer variable setzen. Dies habe ich bisher mittels einer if-Bedingung

1
> if(1 == ledOn)
2
> {
3
>   DDRD |= (1 << PIND3);
4
> }
5
> else
6
> {
7
>   DDRD &= ~(1 << PIND3);
8
> }
9
>

gibt es da auch einen eleganteren weg, wo ich direkt den wert der Variable benutzen kann?

DDRD setzt aber nur die Datenrichtung des angegebenen Pins, nicht seinen logischen Zustand. Was du wohl eher möchtest ist

1
if(1 == ledOn)
2
{
3
  PORTD |= (1 << PD3);
4
}
5
else
6
{
7
  PORT &= ~(1 << PD3);
8
}

Wenn ledOn nur den Zustand 0 oder 1 annehmen kann, dann kann man das verkürzt schreiben mit:

1
PORTD = PORTD & ~(1 << PD3) | (ledOn << PD3);

Das ist aber IMHO etwas schwerer zu lesen, die If-Bedingung ist meiner Ansicht nach für den Menschen übersichtlicher/einfacher zu lesen/verstehen und der Compiler wirds eh passend optimieren.

#7354643
Lesenswert?

EAF schrieb:

Stefan F. schrieb:

eleganter

Über "elegant" kann man streiten.

In der Tat!

Hier ein eleganter und optimierter "Arduino" Code:

1
> #include <CombiePin.h>
2
> 
3
> using Led = Combie::Pin::OutputPin<LED_BUILTIN>;
4
> 
5
> int main()
6
> {
7
>    Led{}.init();
8
>    Led{} = 1;
9
>    while(1);
10
> }
11
>

Wenn Du schon ein Monostate einsetzt, dann sollte man das auch richtig machen ;-) So ist das jedenfalls unnötiger Murks.

Gast #7354898
Lesenswert?

Peter D. schrieb:

Das ist egal, LED verlangt ein Bool, da Bitvariable. Bei Bedarf erfolgt eine automatische Umwandlung.

Nicht ganz, aber mein Durchblick bei sbit.h ist nicht so der Renner 😀.

Im Simulator sieht es zumindest so aus, als ob der Wert nur mit der Maske 0x01 behandelt wird. Heißt: LED = 1; // on LED = 2; // off LED = 3; // on - und so weiter. Das ist für mich keine automatische Umwandlung in Bool, denn es ist nicht das selbe wie: alles, was ungleich 0 (false) ist, ist dann 1 (true).

Deshalb war mein Hinweis nicht ganz unberechtigt.

#7354969
Lesenswert?

Eine Anmerkung schrieb:

Jeder bastelt da irgend etwas anderes. Der Code lässt sich nicht wiederverwenden. Nachvollziehen, was die Macros, Wrapper und Frameworks machen, wird aufwendiger als komplett neu entwickeln.

Nimm als Beispiel die Normen aus Maschinenbau oder Bauwesen. Alle Ingenieure benutzen die selben Symbole und die selben Bezeichnungen. Jeder sieht auf den ersten Blick, was der Kollege konstruiert hat.

Wieso können wir uns nicht auf einen einheitlichen Weg einigen?

Als Mädchen mit entsprechenden Erfahrungen sage ich es so: Jeder will den Größten haben...

Einheitlicher Weg würde ja bedeuten, dass niemand mehr "Java ist besser!", "Nein C ist besser!", "Nein Rust ist besser!" sagen dürfte, sondern dass sich alle einigen müssten auf ein gemeinsames Ziel. Aber das geht doch nicht! Nicht unter Jungs jedenfalls ^^

#7354985
Lesenswert?

Dominik schrieb:

guten abend, ich habe ein kleines logisches Problem.

Ich möchte den Pin (AVR) anhand einer variable setzen. Dies habe ich bisher mittels einer if-Bedingung

1
> if(1 == ledOn)
2
> {
3
>   DDRD |= (1 << PIND3);
4
> }
5
> else
6
> {
7
>   DDRD &= ~(1 << PIND3);
8
> }
9
>

gibt es da auch einen eleganteren weg, wo ich direkt den wert der Variable benutzen kann?

Der Code ist grundsätzlich scheiße.

Warum? Weil ihn niemand versteht, der nicht C-Experte ist so wie du.

Wenn ledOn bool ist, dann ist die if-clause schon falsch. Und zweitens gehört (1 << PIND3) in eine eigene Funktion verpackt, weil "don't repeat yourself".

#7354993
Lesenswert?

HildeK schrieb:

Peter D. schrieb:

Das ist egal, LED verlangt ein Bool, da Bitvariable. Bei Bedarf erfolgt eine automatische Umwandlung.

Nicht ganz, aber mein Durchblick bei sbit.h ist nicht so der Renner 😀.

Im Simulator sieht es zumindest so aus, als ob der Wert nur mit der Maske 0x01 behandelt wird. Heißt: LED = 1; // on LED = 2; // off LED = 3; // on - und so weiter. Das ist für mich keine automatische Umwandlung in Bool,

Anders herum wird ein Schuh draus. Auf der rechten Seite der Zuweisung muss ein bool stehen, und dann kommt in LED eine 0 an, wenn der false ist und eine 1, wenn er true ist. Eine 2 oder 3 gibt es dann gar nicht. Es ging doch darum:

HildeK schrieb:

#include "sbit.h" . . . LED = ledOn;

und um meinen Hinweis, ledOn dann als bool zu definieren.

Gast #7355046
Lesenswert?

Rolf M. schrieb:

Anders herum wird ein Schuh draus. Auf der rechten Seite der Zuweisung muss ein bool stehen, und dann kommt in LED eine 0 an, wenn der false ist und eine 1, wenn er true ist. Eine 2 oder 3 gibt es dann gar nicht.

Ja, richtig! Welcher Typ die Variable 'ledOn' beim TO jedoch hatte, ist unbekannt. Deshalb schrieb ich dazu:

HildeK schrieb:

wenn ledOn nur die Werte 0 und 1 annimmt.

also auf den boolschen Zahlenraum beschränkt ist. Du hast sinnvollerweise ergänzt, dass man für ledOn gleich eine Boolvariable nehmen sollte. Zumindest wäre einen Cast auf bool nötigt.

Nur Peter D. hatte gemeint:

Peter D. schrieb:

Bei Bedarf erfolgt eine automatische Umwandlung.

Diese Umwandlung sehe ich nicht. Deshalb hab ich das mal getestet.

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