Forum: Mikrocontroller und Digitale Elektronik Arduino Merkwürdiges verhalten


von Enrico S. (key-board)


Lesenswert?

Hallo
Ich will mir mit LEDs eine Ladezustandsanzeige basteln

Ansteuern will ich die mit:
1
byte Zustand =0;
2
byte anz=0;
3
anz = (etwas zwischen 0 und 8);
4
Zustand = byte(pow(2,anz)-1);
Wenn ich anz direkt etwas zwischen 0 und 8 setze leuchten die leds so 
wie sie sollen.
z.B.
1
anz = 4;
2
println(anz,DEC); ->4 angezeigt
3
println(Zustand,DEC); -> 15 angezeigt(leds leuchten entsprechend dem Binärmuster)
Fange ich jetzt an anz zu berechnen aus einem SOC
1
anz=byte(map(SOC,0,100,0,Aufloesung));
oder
1
anz=byte(SOC*Aufloesung/100);
wobei mir Aufloesung angibt ob ich 4 oder 8 oder... LEDs für die Anzeige 
zur Verfügung habe.
kommt die falsche anzeige bei raus obwohl ich an der Zustand berechnung 
nichts ändere kommt z.B. bei SOC 50 folgendes raus
println(anz,DEC); ->4 angezeigt
println(Zustand,DEC); -> 14 angezeigt(leds leuchten entsprechend dem 
Binärmuster)

kann mir mal einer sagen warum einmal
2^4-1=15
und einmal
2^4-1=14
rauskommt?????
und das nur weil die 4 einmal fest geschrieben und einmal ausgerechned 
wird?

beim ausrechnen entsteht ein fehler bei jedem SOC

PS:
Der fehler tritt auch auf wenn ich die einzelnen Schwellen mit if und 
else if bedingungen mache... und immer setze z.B. if(SOC > 45) anz = 4;
nur wenn ich wieder ganz kurz vor dem ausrechnen des Zustandes anz auf 
einen wert z.B. 4 setze, dass wird alles richtig angezeigt...

es ist zum verrückt werden...

von Karl H. (kbuchegg)


Lesenswert?

Enrico S. schrieb:

> kann mir mal einer sagen warum einmal
> 2^4-1=15
> und einmal
> 2^4-1=14
> rauskommt?????
> und das nur weil die 4 einmal fest geschrieben und einmal ausgerechned
> wird?

Da ist mit Sicherheit irgendwo wieder eine Floating Point Rechnung im 
Spiel. Die Details, wie zb Datentypen oder realen Code, hast du ja nicht 
gezeigt.

Dein Ergebnis ist eben nicht 4, sondern zb. 3.999999.
Bei der Ausgabe wird gerundet. Wenn du aber rechnest, wird tatsächlich 
mit 3.999999 gerechnet. Und das ist nun mal nicht dasselbe wie 4.0


Wo auch immer du mit Floating Point rechnest, füge beim Übergang zu int 
eine Rundungskorrektur ein
1
  int intWert;
2
  float floatWert;
3
4
  floatWert = 3.99999;
5
6
  // Rundungskorrektur
7
  intWert = floatWert + 0.5;

von Karl H. (kbuchegg)


Lesenswert?

Abgesehen davon, ist die Verwendung von pow hier mit Kanonen auf Spatzen 
geschossen.

Du hast 8 mögliche Ergebnisse.
Die kannst du auch ganz einfach als Fix und Fertiges Ergebnis in einem 
Array vorhalten.
1
  byte LedPattern[] = { 0b00000001,    // 0
2
                        0b00000010,    // 1
3
                        0b00000100,    // 2
4
                        0b00001000,    // 3
5
                        0b00010000,    // 4
6
                        0b00100000,    // 5
7
                        0b01000000,    // 6
8
                        0b10000000,    // 7
9
                        0b11111111,    // 8 -> zu gross
10
                      };
11
12
...
13
  if( anz > 7 )
14
    anz = 7;
15
16
  Zustand = LedPattern[anz];
17
...

keiner muss gross rumrechnen und du hast den Bonus, das Led Muster 
problemlos so anzupassen, wie du das möchtest. Möchtest du den Level als 
einzelne LED angeben, dann ist das kein Problem. Möchtest du ein 
LED-Band dann ist das auch kein Problem. Möchtest du den Level als 2 
nebeneinander liegende LED anzeigen, dann änderst du einfach das Muster 
im Array. Möchtest du anstatt 8 Levels deren 16, indem du zb Abwechselnd 
nur 1 und 2 LED leuchten lässt, dann geht auch das (wenn man das Array 
entsprechend größer macht und die Rechenfaktoren anpasst).

Alles in allem: win win

von Enrico S. (key-board)


Lesenswert?

OK Danke

die floating point operation kahm durch pow();
und habs jetzt gelößt mit
if (SOC > 90)
Zustand = 255;
usw

und die Anpassung an meine Auflösung mit
if (Aufloesung !=8)
SOC=SOC*Auflösung/8;

funktioniert mit alles Auflösungen die für meinen Einsatzzweck sinnvoll 
sind (3 bis 8 LEDs)

von Samuel C. (dragonsam)


Lesenswert?

Es wäre deutlich einfacher gewesen, einfach das
1
pow(2, anz)
durch
1
(1<<anz)
zu ersetzen.

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.