Forum: Mikrocontroller und Digitale Elektronik unineffizienter Code in Arduino Beispiel "Blink without Delay" ?


von Karli (Gast)


Lesenswert?

In der Arduino Software findet sich im Beispiel "Blink without Delay" 
folgender Codeschnipsel:
1
    // if the LED is off turn it on and vice-versa:
2
    if (ledState == LOW) {
3
      ledState = HIGH;
4
    } else {
5
      ledState = LOW;
6
    }
Wäre es nicht sinnvoll, diesen durch
1
    ledState = !ledstate;
zu ersetzen?

von Karli (Gast)


Lesenswert?

Karli schrieb:
> ledState = !ledstate;
Es hätte
ledState = !ledState;
heißen müssen.

von Einer K. (Gast)


Lesenswert?

Karli schrieb:
> Wäre es nicht sinnvoll, diesen durch    ledState = !ledstate;
> zu ersetzen?

Ja.
Alleine schon wegen der Schreibfaulheit.

von H.Joachim S. (crazyhorse)


Lesenswert?

Woran machst du fest, was "uneffizienter code" ist? Am Schreibaufwand? 
Am vermuteten erzeugten Code? An der Lesbarkeit?

Es wird am Ende derselbe Maschinencode herauskommen :-)

von Einer (Gast)


Lesenswert?

unineffizienter Code
ergibt effizienter Code

Aber zum Thema.
Das ist ein Beispiel. Das soll Verständlich für Anfänger sein.

von holger (Gast)


Lesenswert?

>Es wird am Ende derselbe Maschinencode herauskommen :-)

Das ist nicht richtig.
Wenn LOW = 0 und HIGH = 1 wird ledState 0 oder 1.
Im zweiten Beispiel wird ledState 0 oder 0xFF wenn ledState uint8_t ist.

Beitrag #5865391 wurde von einem Moderator gelöscht.
von loeti2 (Gast)


Lesenswert?

holger schrieb:
> Das ist nicht richtig.
> Wenn LOW = 0 und HIGH = 1 wird ledState 0 oder 1.
> Im zweiten Beispiel wird ledState 0 oder 0xFF wenn ledState uint8_t ist.

Wohl kaum, mal in einem C-Buch den Unterschied zwischen logischer und 
Bit-Negierung nachlesen.

von foobar (Gast)


Lesenswert?

Die "Verbesserung" funktioniert nur identisch, wenn LOW 0 ist und HIGH 1 
oder umgekehrt.  Bei allen anderen Werten (evtl gibt es ja OFF, LOW, 
MEDIUM, HIGH?) klappt das "!" nicht.

Der Sinn und Zweck von benamten Konstanten ist es ja, dass einem der 
konkrete Wert nicht interessiert.  Durch das "!" machst du genau das 
Gegenteil, du verlässt dich auf konkrete Werte.

Bei numerischem LOW/HIGH (und nur die beiden) ginge:
1
ledState = LOW+HIGH - ledState;
2
// oder
3
ledState ^= LOW^HIGH;
Ob das aber, insbesondere für Anfänger, lesbarer wäre?

von googoo (Gast)


Lesenswert?

wie wär's mit led = led ^ 1 ? :)
oder auch led ^=1

von A. S. (Gast)


Lesenswert?

Arduino Fanboy D. schrieb im Beitrag #5865391:
> Es ist int.

Dann poste bitte den relevanten Code.

von Matthias S. (da_user)


Lesenswert?

Karli schrieb:
> Wäre es nicht sinnvoll, diesen durch    ledState = !ledstate;
> zu ersetzen?

Die Frage ist eher, was der bezweckte Sinn ist. Ist es, möglichst 
"effizienten" Code zu schreiben, oder Anfängern die Sprache 
beizubringen?

von Andre (Gast)


Lesenswert?

Karli schrieb:
> Wäre es nicht sinnvoll,

Komplett auf die Variable zu verzichten und das Bit im Ausgangsregister 
zu toggeln?

von GEKU (Gast)


Lesenswert?

googoo schrieb:
> wie wär's mit led = led ^ 1 ? :)
> oder auch led ^=1

Ich würde bit-weise invertieren, dann kann man die anderen PortPin's 
noch für andere Zwecke verwenden.
1
#define PP0 = 0x01;
2
#define PP1 = 0x02;
3
#define PP2 = 0x04;
4
#define PP3 = 0x08;
5
#define PP4 = 0x10;
6
#define PP5 = 0x20;
7
#define PP6 = 0x04,;
8
#define PP7 = 0x08;
9
10
port ~= PP5;   // für PortPin 5

Durch Addition, z.B.  (PP3+PP5+PP7), können mehrere PortPin's 
angesteuert werden.

von GEKU (Gast)


Lesenswert?

GEKU schrieb:
> #define PP6 = 0x04,;
> #define PP7 = 0x08;

natürlich:
1
#define PP6 = 0x40;
2
#define PP7 = 0x80;

von The Mule (Gast)


Lesenswert?

#define in dem Zusammenhang ist Rückschritt. Dann lieber den originalen 
Syntax.

von GEKU (Gast)


Lesenswert?

The Mule schrieb:
> #define in dem Zusammenhang ist Rückschritt.

Dient nur zur Erklärung. Man kann natürlich auch eine Konstante 
definieren.
Reine Geschmackssache!

von GEKU (Gast)


Lesenswert?

The Mule schrieb:
> Dann lieber den originalen
> Syntax.

Und wie wurde LOW & HIGH definiert?

von Christopher B. (chrimbo) Benutzerseite


Lesenswert?

GEKU schrieb:
> port ~= PP5;   // für PortPin 5

was soll das tun?
das wäre ja ausgeschrieben
1
port = port ~0x20; ->
2
port = port 0xDF;
Ich würde sowas wie missing operator erwarten. Oder ist ~ in CPP anders 
definiert?

--- Probieren ---
GCC (C) sagt:
error: expected ';' before '~' token

von Einer K. (Gast)


Lesenswert?

Liebe Leute, aller Arduino Quellcode liegt im Internet öffentlich aus.

GEKU schrieb:
> Und wie wurde LOW & HIGH definiert?
https://github.com/arduino/ArduinoCore-avr/blob/master/cores/arduino/Arduino.h

und:
A. S. schrieb:
> Arduino Fanboy D. schrieb im Beitrag #5865391:
>> Es ist int.
>
> Dann poste bitte den relevanten Code.
https://github.com/arduino/Arduino/tree/ee1967cd530ceb9a1d638875e385157e90d532e8/build/shared/examples/02.Digital/BlinkWithoutDelay

----------

Ich finde das Beispiel übrigens auch nicht sonderlich schön.
Und hätte sicherlich bool als Datentype für die Variable verwendet.

von Einer K. (Gast)


Lesenswert?

GEKU schrieb:
> natürlich:#define PP6 = 0x40;
> #define PP7 = 0x80;

? ? ?
Was soll das = da, oder das ;
Welche Sprache ist das?

von Roland P. (pram)


Lesenswert?

Andre schrieb:
> Karli schrieb:
>> Wäre es nicht sinnvoll,
>
> Komplett auf die Variable zu verzichten und das Bit im Ausgangsregister
> zu toggeln?

Oder noch effizienter: Die LED direkt an einen Timer-PWM hängen, dann 
blinkt die sogar ohne Code (und der TO lernt, wie man einen Timer 
aufsetzt)

VG
Roland

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Sowas geht auch
1
// toggle ledstate
2
ledstate = 1 - ledstate;

: Bearbeitet durch User
von Philipp_K59 (Gast)


Lesenswert?

Oder ganz easy..

ledState = !ledState?HIGH:LOW;

wäre nach dem Beispiel gekürzt:

digitalWrite(ledPin, (!ledState?HIGH:LOW));

von gurgl (Gast)


Lesenswert?

GEKU schrieb:
> Ich würde bit-weise invertieren

GEKU schrieb:
> port ~= PP5;   // für PortPin 5

Was du meinst ist XOR, ^

Die Tilde die du verwendest ist Bitweise-Invertieren und ein unärer 
Operator, dh. er erwartet EINEN Operanden

zB
~ 00 ergibt FF
~ 88 ergibt 77  usw

Theoretisch müsste "port~=;" funktionieren ;) kann das aber grad nicht 
testen;)

von Philipp K. (philipp_k59)


Lesenswert?

Philipp_K59 schrieb:
> wäre nach dem Beispiel gekürzt:
>
> digitalWrite(ledPin, (!ledState?HIGH:LOW));

Eher so.. bin da nicht so der Short-If Profi.

digitalWrite(ledPin, (ledState=!ledState?HIGH:LOW));

von Sebastian S. (amateur)


Lesenswert?

Irgendwie komme ich mit dem Hingucken einfach nicht nach!

Ich assoziiere "Blink" mit etwas, was man sehen kann.

Die Code-Fragmente flackern mir zu schnell.

Der Ansatz: "Ohne Delay" ist ein Witz, wenn dieses einfach, ersatzlos 
weggelassen wird.

von Mark B. (markbrandis)


Lesenswert?

Karli schrieb:
> In der Arduino Software findet sich im Beispiel "Blink without Delay"
> folgender Codeschnipsel:
>
1
>     // if the LED is off turn it on and vice-versa:
2
>     if (ledState == LOW) {
3
>       ledState = HIGH;
4
>     } else {
5
>       ledState = LOW;
6
>     }
7
>
> Wäre es nicht sinnvoll, diesen durch
>
1
>     ledState = !ledstate;
2
>
> zu ersetzen?

Was genau wäre dadurch gewonnen?

Der generierte Maschinencode wird genau der gleiche sein.

von gurgl (Gast)


Lesenswert?

Sebastian S. schrieb:
> Der Ansatz: "Ohne Delay" ist ein Witz, wenn dieses einfach, ersatzlos
> weggelassen wird.

Die Idee dahinter ist, den Code für´s Bit-Toggeln so ineffizient langsam 
zu machen, daß ein extra Delay unnötig wird :P

von gurgl (Gast)


Lesenswert?

Mark B. schrieb:
> Der generierte Maschinencode wird genau der gleiche sein.

Es geht grundsätzlich um eine Designentscheidung: 
Kurz-und-knapp-mathematisch oder eher in Prosaform.

Spätestens wenn man ein Programm mit sagen wir 300 Zeilen durcharbeiten 
(zB Bugs finden) muss, macht es nen Unterschied ob es 300 oder 1500 
Zeilen sind

(sprich 3000, 30000 Zeilen usw obwohl das dann schon pervers ist)

von Mark B. (markbrandis)


Lesenswert?

gurgl schrieb:
> Mark B. schrieb:
>> Der generierte Maschinencode wird genau der gleiche sein.
>
> Es geht grundsätzlich um eine Designentscheidung:
> Kurz-und-knapp-mathematisch oder eher in Prosaform.
>
> Spätestens wenn man ein Programm mit sagen wir 300 Zeilen durcharbeiten
> (zB Bugs finden) muss, macht es nen Unterschied ob es 300 oder 1500
> Zeilen sind

Wenn die einzelnen Funktionen kurz und übersichtlich sind, weil man 
vernünftig programmiert hat, ist es relativ egal ob die gesamte Software 
nun aus 300 oder 3.000 Zeilen Code besteht.

Code wird jedenfalls nicht automatisch besser, wenn man mehr davon in 
eine Zeile packt. In dem Beispiel oben mag es okay sein, aber oft genug 
führt "Zeilenquetscherei" eher zu schlechter lesbarem und wartbarem 
Code.

von Einer K. (Gast)


Lesenswert?

Philipp_K59 schrieb:
> Oder ganz easy..
>
> ledState = !ledState?HIGH:LOW;

? ?

 ledState = !(ledState?HIGH:LOW);
 ledState = (!ledState)?HIGH:LOW;

 ledState = ledState?LOW:HIGH);

 ledState = !ledState;

Naja, ob der Trenäre Operator in einem "Blink without delay" gut 
aufgehoben ist, möchte ich bezweifeln.

von vodoo (Gast)


Lesenswert?

Mark B. schrieb:
> aber oft genug
> führt "Zeilenquetscherei" eher zu schlechter lesbarem und wartbarem
> Code.

Das liegt immer am Programmierer selbst.

von vodoo (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Trenäre Operator

ledState = (ledState == HIGH) ?  LOW : HIGH ;

da müsste ich jetzt auch 2 mal hinsehen, schön isses nicht aber wenn 
schon so dann so.

von Einer K. (Gast)


Lesenswert?

vodoo schrieb:
> (ledState == HIGH)

vodoo schrieb:
> aber wenn schon so dann so.

Da bin ich gegen...
Ein Vergleich mit HIGH ist unsinnig, wenn die Variable sowieso nur HIGH 
und LOW werden kann.

(ledState == HIGH)
Würde zu
(HIGH == HIGH)
oder
(LOW == HIGH)

Einfach nur (ledState) ist an der Stelle völlig ausreichend
(Die Klammern sind auch noch über)

von imKeller (Gast)


Lesenswert?

Arduino erregt die Geister

Ah , die kostbare Zeit !!!

von MaWin (Gast)


Lesenswert?

Arduino ist gut! Ebenso Bascom!

von vodoo (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> (Die Klammern sind auch noch über)

klammern waren ja wegen dem vergleich und an dem würde ich unbedingt 
festhalten da sich ja high, low verändern könnten in anderen 
arduinoversionen, so ist dat sicher!



Nehmt den Arduino, er ist sehr gut!

von Einer K. (Gast)


Lesenswert?

vodoo schrieb:
> so ist dat sicher!

Ob du hier
ledState = (ledState == HIGH) ?  LOW : HIGH ;
oder
ledState = ledState == HIGH ?  LOW : HIGH ;
oder
ledState = ledState ?  LOW : HIGH ;
oder
ledState = not ledState;
schreibst ist völlig irrelvant.
Komme was wolle

Beitrag #5865771 wurde von einem Moderator gelöscht.
von Einer K. (Gast)


Lesenswert?

Karl Max schrieb im Beitrag #5865771:
> und/oder in der Variablendeklaration

Wenn das auf meinen Mist gewachsen wäre, würde sicherlich sowas da 
stehen:
> bool ledState;

von Farim (Gast)


Lesenswert?

Man sollte sich den ganzen Code ansehen:
1
// constants won't change. Used here to set a pin number:
2
const int ledPin =  LED_BUILTIN;// the number of the LED pin
3
4
// Variables will change:
5
int ledState = LOW;             // ledState used to set the LED
6
7
// Generally, you should use "unsigned long" for variables that hold time
8
// The value will quickly become too large for an int to store
9
unsigned long previousMillis = 0;        // will store last time LED was updated
10
11
// constants won't change:
12
const long interval = 1000;           // interval at which to blink (milliseconds)
13
14
void setup() {
15
  // set the digital pin as output:
16
  pinMode(ledPin, OUTPUT);
17
}
18
19
void loop() {
20
  // here is where you'd put code that needs to be running all the time.
21
22
  // check to see if it's time to blink the LED; that is, if the difference
23
  // between the current time and last time you blinked the LED is bigger than
24
  // the interval at which you want to blink the LED.
25
  unsigned long currentMillis = millis();
26
27
  if (currentMillis - previousMillis >= interval) {
28
    // save the last time you blinked the LED
29
    previousMillis = currentMillis;
30
31
    // if the LED is off turn it on and vice-versa:
32
    if (ledState == LOW) {
33
      ledState = HIGH;
34
    } else {
35
      ledState = LOW;
36
    }
37
38
    // set the LED with the ledState of the variable:
39
    digitalWrite(ledPin, ledState);
40
  }
41
}

von Maxim B. (max182)


Lesenswert?

Karli schrieb:
> Wäre es nicht sinnvoll, diesen durch    ledState = !ledstate;
> zu ersetzen?

Am besten kuckt man Assembler-Code von beiden übersetzten Varianten.
Ich denke, deine Variante erzeugt mehr Code, da zuerst Pin-Zustand 
gelesen sein muß, danach invertiert und wieder in Port geschrieben.
Etwa so:
1
in r16, PORTB
2
ldi r17, BITMASK
3
eor r16, r17
4
out PORTB, r16
insgesamt 4 Word 4 Cycles

Wenn einfach auf 0 oder 1 setzen, dann wird für die meisten ATMega-Ports 
kürzere Behehl von Compiler gewählt. Z.B.
1
clr PORTB, PB5
oder
1
setb PORTB, PB5
Jeweils 1 Word 2 Cycles.

Das ist immer so: wenn zu Compilieren-Zeit alle Daten bekannt sind, 
bekommt man kürzere Maschinencode als mit Variablen.

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Maxim B. schrieb:
> Ich denke, deine Variante erzeugt mehr Code, da zuerst Pin-Zustand
> gelesen sein muß, danach invertiert und wieder in Port geschrieben.

Da ist nix mit Port!
Eine einfache Variable, es ist.

von Maxim B. (max182)


Lesenswert?

Ist ledState eine Variable in RAM, die nichts außen macht?
Wenn man damit LED ansteuern will, dann ist das bestimmt Portpin.

Es ist besser, keine Variablen dort zu benutzen, wo es um im voraus 
bekannte Ports geht. So wird Programm schneller und kürzer.

Sonst bekommen wir 2000 Worte in Code, wo auch 5 genügt.

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Farim schrieb:
> Man sollte sich den ganzen Code ansehen:

Oer es gleich anders machen....
1
    class SimpleTimer
2
    {
3
      private:
4
      uint32_t timeStamp;      // Zeitmerker
5
      bool reached;            // default Status: timer abgelaufen
6
    
7
      public:
8
      SimpleTimer():timeStamp(0),reached(true){}
9
      
10
      void start()
11
      {
12
        timeStamp   = millis();
13
        reached     = false;
14
      }
15
      
16
      void reset()
17
      {
18
         reached     = true;
19
      }
20
    
21
      bool operator()(const uint32_t interval) 
22
      {
23
        if(!reached) reached = millis() - timeStamp >= interval;
24
        return reached;
25
      }
26
    };
27
28
const byte led  =  LED_BUILTIN;
29
const unsigned long interval = 500UL;
30
SimpleTimer timer;
31
32
void setup() 
33
{
34
 pinMode(led,OUTPUT);
35
 // timer.start(); // wenn der Timer mit Wartezeit beginnen soll
36
}
37
38
void loop() 
39
{
40
  if(timer(interval))
41
  {
42
    digitalWrite(led,!digitalRead(led));
43
    timer.start();
44
  }
45
46
  // hier tue anderes Zeugs
47
}

Natürlich kann die Ausgabe durch direkte Registerzugriffe deutlich 
beschleunigt werden.
> PORTB = _BV(PB5); // toggelt den Pin in einem Takt

von Stefan F. (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Natürlich kann die Ausgabe durch direkte Registerzugriffe deutlich
> beschleunigt werden.
>> PORTB = _BV(PB5); // toggelt den Pin in einem Takt

Möp. Dazu musst du das PINB Register beschreiben. Aber erkläre das mal 
einem Prinzipienreiter (wenn man einen Output machen will, soll das auch 
so heissen ...).

von Einer K. (Gast)


Lesenswert?

Stefanus F. schrieb:
> Möp. Dazu musst du das PINB Register beschreiben.

Da hast du wahr!

Arduino Fanboy D. schrieb:
>> PORTB = _BV(PB5); // toggelt den Pin in einem Takt

PINB = _BV(PB5); // toggelt den Pin in einem Takt
Muss es heißen.

von GEKU (Gast)


Lesenswert?

gurgl schrieb:
> Was du meinst ist XOR, ^

Der Unterschied zwischen ^ und ~ ist:

^ ändert das ganz Port (XOR) und
~ nur ein Bit (NOT)

https://de.m.wikibooks.org/wiki/C-Programmierung:_Liste_der_Operatoren_nach_Priorität

von leo (Gast)


Lesenswert?

GEKU schrieb:
> Der Unterschied zwischen ^ und ~ ist:
>
> ^ ändert das ganz Port (XOR) und
> ~ nur ein Bit (NOT)

Bitte poste keinen Unsinn.
leo

von GEKU (Gast)


Lesenswert?

Sorry die Hitze

leo schrieb:
> Bitte poste keinen Unsinn.

von Hummelfan (Gast)


Lesenswert?

Wenn ich beim Arduino schnell nen einfachen Blinker brauche, nehm ich 
folgende Zeile:
digitalWrite(LED_BUILTIN, millis() & 0x80); // Blinken mit 4Hz Takt

von Matthias S. (da_user)


Lesenswert?

Hummelfan schrieb:
> Wenn ich beim Arduino schnell nen einfachen Blinker brauche, nehm ich
> folgende Zeile:
> digitalWrite(LED_BUILTIN, millis() & 0x80); // Blinken mit 4Hz Takt

Das erinnert mich an den "Blink-Merker" bei der S7 ;-)

von Maxim B. (max182)


Lesenswert?

Hummelfan schrieb:
> Wenn ich beim Arduino schnell nen einfachen Blinker brauche, nehm ich
> folgende Zeile:
> digitalWrite(LED_BUILTIN, millis() & 0x80); // Blinken mit 4Hz Takt

Klar: man kann auch mit einem Mikroskop statt Hammer die Nägel 
einschlagen...

von A. S. (Gast)


Lesenswert?

Mark B. schrieb:
> Wenn die einzelnen Funktionen kurz und übersichtlich sind, weil man
> vernünftig programmiert hat, ist es relativ egal ob die gesamte Software
> nun aus 300 oder 3.000 Zeilen Code besteht.

Das sehe ich genauso. Auch 30.000 Zeilen kann man noch nach Lehrbuch 
coden, so mit McCabe einstellig und nur eine Bildschirm-Seite. Skalieren 
tut es aber (leider) nicht.

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.