unineffizienter Code in Arduino Beispiel "Blink without Delay" ?

Gast #5865377
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?
Gast #5865388
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.
Gast #5865424
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?
Gast #5865464
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.
Gast #5865535
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.
Gast #5865628
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;)
#5865640
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.
Gast #5865648
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)
#5865653
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.
Gast #5865664
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.
Gast #5865699
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)
Beitrag #5865771 wurde von einem Moderator gelöscht.
Gast #5865803
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
}
#5865811
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.
#5865821
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.
Gast #5865833
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
Gast #5865843
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 ...).
Gast #5868720
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.

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