Increment und Decrement Variable!

Hallo liebe Community!
Ich habe ein kleines Problem und finde es nicht heraus wie ich diesen Code umschreiben müsste um die Variable “Gewicht” genau bei 0,2g zu stoppen doch er hüpft immer beim Dekrementieren auf 0,19g und sobald ich wieder Inkrementieren auf 0,21g und nicht auf 0,2g :confused:

Ich hoffe irgendwer kann mir dabei weiterhelfen.

const int  buttonPin = 2;
const int  buttonPin1 = 3;
const double Milli = 1000.0;
double Gewicht = 0.0002;  
int buttonState5 = 0;
int buttonState6 = 0;
int lastButtonState = 0;

void setup() {  
   pinMode(buttonPin, INPUT);
   pinMode(buttonPin1, INPUT);
   Serial.begin(115200);
}


void loop() {
   buttonState5 = digitalRead(buttonPin);
   if (buttonState5 != lastButtonState) {
     if (buttonState5 == HIGH){ 
      Gewicht = Gewicht + 0.00001;
      Serial.println(String("Gewicht: ")+Gewicht*Milli+String("g"));
     }
     delay(100);
   }
   lastButtonState = buttonState5;
   
   buttonState6 = digitalRead(buttonPin1);
   if (buttonState6 != lastButtonState) {
     if (buttonState6 == HIGH){
      Gewicht = Gewicht - 0.00001;
      Serial.println(String("Gewicht: ")+Gewicht*Milli+String("g"));
     }
     delay(100);
     if (Gewicht < 0.00019){
      Gewicht = 0.0002;    
     }
   }
   lastButtonState = buttonState6; 
}

Gleitkommazahlen haben systembedingt Rundungsfehler: https://www.h-schmidt.net/FloatConverter/IEEE754de.html

0.0002 ist z.B. nicht genau darstellbar sondern wird zu 0.00019999...

Hallo,

das mit float dachte ich auch erst, dass klappt hier jedoch. Das Problem liegt in der Reihenfolge der Abfrage, der Wertzuweisung auf 0.2 und der Anzeige. Die Anzeige kommt vor der Wertänderung. Intern ist alles korrekt nur man sieht es nicht. Beim nächsten + kommt 0.01 zu 0.2 dazu. Der Sketch arbeit so wie er aufgebaut ist 100% korrekt. Nimm das *Milli raus, dann siehste das besser.

Ich würde dennoch wie schon von Serenifly angesprochen alles soweit es geht in Ganzzahlen rechnen und erst für die Anzeige in Kommastellen darstellen/umrechnen. Bei Ganzzahlen gibts keine Rundungsfehler. Es ist ja kein Problem intern mit Zahlen von 2000 für Gramm zu hantieren für eine Anzeige von 2kg.

Es gibt nicht nur Rundungsfehler sondern auch , wenn 2 verschieden große Gleitkommazahlen zusammengezählt werden einen Punkt wo das Dazuaddieren die größere Zahl nicht mehr verändert. Ok, das ist auch ein Rundungsfehler aber daran denkt man nicht. Grüße Uwe

Hallo,

habe mir mal erlaubt das umzubauen mit Tendenz zum aufräumen. Kann als Basis zum weiteren Ausbau dienen.

unsigned long Gewicht = 20;

struct Taster
{
  byte pin;
  bool zustand = false;
};

Taster taster2;
Taster taster3;

void setup() {

  taster2.pin = 2;
  taster3.pin = 3;
  
  pinMode(taster2.pin, INPUT);
  pinMode(taster3.pin, INPUT);
  Serial.begin(115200);
}


void loop() {

  update_Taster();
  
  if (taster2.zustand) {
    Gewicht++;
    taster2.zustand = false;
  }

  if (taster3.zustand) {
    Gewicht--;
    if (Gewicht < 20) {
      Gewicht = 20;
    }
    taster3.zustand = false;
  }

  anzeige(Gewicht);
}



void update_Taster ()
{
  static unsigned long last_ms = 0;
  unsigned long ms = millis();

  if (ms - last_ms >= 40) {
    last_ms = ms;

    taster2.zustand = digitalRead(taster2.pin);
    taster3.zustand = digitalRead(taster3.pin);
  }
}


void anzeige (unsigned long gewicht)
{
  static unsigned long altesGewicht = 0;

  if (gewicht != altesGewicht)
  {
    Serial.print(F("Gewicht: "));
    Serial.print(gewicht);
    Serial.print("g");
    Serial.print("\t\t");
    Serial.print((gewicht/1000.0),3);
    Serial.println("kg");
    altesGewicht = gewicht;
  }
}

Edit: Anzeige verfeinert

Okay Danke für die Hilfe werde es gleich mal ausprobieren und halt wie ihr gesagt habt den Code etwas Umschreiben

Vielen Dank für die Hilfe derweil!

Doc_Arduino:
Hallo,

habe mir mal erlaubt das umzubauen mit Tendenz zum aufräumen. Kann als Basis zum weiteren Ausbau dienen.

unsigned long Gewicht = 20;

struct Taster
{
  byte pin;
  bool zustand = false;
};

Taster taster2;
Taster taster3;

void setup() {

taster2.pin = 2;
  taster3.pin = 3;
 
  pinMode(taster2.pin, INPUT);
  pinMode(taster3.pin, INPUT);
  Serial.begin(115200);
}

void loop() {

update_Taster();
 
  if (taster2.zustand) {
    Gewicht++;
    taster2.zustand = false;
  }

if (taster3.zustand) {
    Gewicht–;
    if (Gewicht < 20) {
      Gewicht = 20;
    }
    taster3.zustand = false;
  }

anzeige(Gewicht);
}

void update_Taster ()
{
  static unsigned long last_ms = 0;
  unsigned long ms = millis();

if (ms - last_ms >= 40) {
    last_ms = ms;

taster2.zustand = digitalRead(taster2.pin);
    taster3.zustand = digitalRead(taster3.pin);
  }
}

void anzeige (unsigned long gewicht)
{
  static unsigned long altesGewicht = 0;

if (gewicht != altesGewicht)
  {
    Serial.print(F(“Gewicht: “));
    Serial.print(gewicht);
    Serial.print(“g”);
    Serial.print(”\t\t”);
    Serial.print((gewicht/1000.0),3);
    Serial.println(“kg”);
    altesGewicht = gewicht;
  }
}



Edit: Anzeige verfeinert

Funktioniert Eins A nur mir etwas zu schnell um von 1Gramm auf 2 Gramm umschalten zu können es sollte Machbar sein es mit einem Taster zu um eins zu erhöhen und verringern.
Muss ich dazu einfach ein Delay im Code setzen oder??

Habe gerade herausgefunden das ich einfach die Zahl die du vergleichst in "update_Taster" einfach erhöhen muss um die Reaktionszeit zu verringern. Habe ich dabei Recht oder ist meine Vermutung dabei Falsch??

Hallo,

genau das hatte ich mir auch soeben gedacht das es stören könnte.
Delay? Um Himmelswillen, bloss nicht. Dann wäre der Aufwand mit millis für die Katz.
Das bekommste hier nebenbei frei Haus geliefert.

Zum Verständnis warum, weshalb und wie:
Theseus erklärt millis()

GuntherB - BlinkwithoutDelay - Die Nachtwächtererklärung

Hier der geänderte Code. Ich verwende Pullup und muss dann immer nochmal vorm posten umarbeiten. Müssen deine Taster auf High reagieren? Ich hoffe ich habe nichts vergessen. Es reagiert nur auf erneuten Tastendruck. Rasselt also nicht mehr durch.

unsigned long Gewicht = 20;

struct Taster
{
  byte pin;
  bool read = false;
  bool oldRead = false;
  bool state = false;
};

Taster taster2;
Taster taster3;

void setup() {

  taster2.pin = 2;
  taster3.pin = 3;

  pinMode(taster2.pin, INPUT);
  pinMode(taster3.pin, INPUT);
  Serial.begin(115200);
}


void loop() {

  update_Taster();

  if (taster2.state) {
    Gewicht++;
    taster2.state = false;
  }

  if (taster3.state) {
    Gewicht--;
    if (Gewicht < 20) {
      Gewicht = 20;
    }
    taster3.state = false;
  }

  anzeige(Gewicht);
}



void update_Taster ()
{
  static unsigned long last_ms = 0;
  unsigned long ms = millis();

  taster2.state = false;
  taster3.state = false;

  if (ms - last_ms >= 40) {
    last_ms = ms;

    taster2.read = digitalRead(taster2.pin);
    taster3.read = digitalRead(taster3.pin);

    if (taster2.read && (!taster2.oldRead) ) {
      taster2.state = true;
    }
    
    if (taster3.read && (!taster3.oldRead) ) {
      taster3.state = true;
    }

    taster2.oldRead = taster2.read;
    taster3.oldRead = taster3.read;
  }
}


void anzeige (unsigned long gewicht)
{
  static unsigned long altesGewicht = 0;

  if (gewicht != altesGewicht)
  {
    Serial.print(F("Gewicht: "));
    Serial.print(gewicht);
    Serial.print("g");
    Serial.print("\t\t");
    Serial.print((gewicht/1000.0), 3);
    Serial.println("kg");
    altesGewicht = gewicht;
  }
}

Wenn es läuft, mach das Beste daraus. Verstehe den Ablauf. :wink:

Edit:
wegen “der Erhöhung”, probiere es aus, spiele rum, damit lernt man auch, teste auch größere Werte und merke was sich in der Bedienung verändert. Danach kannste den neuen Code testen.

Edit 2:
mal wieder was “vergessen”, die Zeilen 31 und 39 können raus, dass rücksetzen auf false macht die update_Taster Funktion schon

Also ich muss sagen das Verständnis hätte ich ja wenn ich mir so den Code anschaue und nebenbei es praktisch Überprüfe aber so alleine ist es für mich etwas schwierig vor allem so einen Code wie diesen zu schreiben :D

So nun habe ich noch eine kurze Frage. Ich habe noch einen Code und ich möchte nun den Code den @Doc_Arduino mit diesen hier verbinden um das Gewicht (Varibale) per Tasten druck zu erhöhen oder verringern. Um anschließend bei der Auslösung der beiden Sensoren (Zeitmessung) die richtige Berechnung zu erhalten.

#define Button1  2
#define Button2  3
long int elapsedtime, starttime;
const double Milli = 1000.0;
const double Micro = 1000000.0;
const double Gewicht = 0.0002;            // Gewicht in Kilogramm
const double Multiplikator = 0.5;
const double Abstand = 50.0;              // Abstand in Meter 
const double fps = 3.2808399;            // Umrechnungsfaktor (so genau wie möglich)
double Time;
double Speed;
double Energie;
double FPS;

void setup() {
 pinMode(Button1, INPUT);
 pinMode(Button2, INPUT);
 Serial.begin(115200);
}

void loop() {
  while (digitalRead(Button1) == false){ 
  }

    starttime = micros();

  while (digitalRead(Button2) == false){  
  }

    elapsedtime = (micros() - starttime);
    Time = elapsedtime / Micro;
    Speed = Abstand / Time;
    FPS = Speed * fps;
    Energie = Multiplikator * Gewicht * (Speed * Speed);

  Serial.println("");
  Serial.println(String("Gewicht: ")+Gewicht*Milli+String("g"));
  Serial.println("");
  Serial.println(String("Geschwindigkeit: ")+Speed+String("m/s"));
  Serial.println("");
  Serial.println(String("Geschwindigkeit: ")+FPS+String("fps"));
  Serial.println("");
  Serial.println(String("Energie: ")+Energie+String("J"));
  Serial.println("");
}

Edit: Falls hier in diesem Code schon irgendwas euch auffallen sollte bitte verbessert mich :d

Edit: Es ist eigentlich egal ob es Pullup oder Pulldown wäre ich habe es nur deswegen da ich es in diesem Code so Programmiert habe sonst wäre es egal.

Hallo,

ich hoffe das war nun alles nicht umsonst.

Schau dir den Code an, schau wie die update_Taster Funktion arbeitet.
Warum überhaupt Funktionen? Code ist lesbarer und einfacher wartbar.

Wenn das verstanden ist, ist die Ergänzung der Zeitmessung mit 2 weiteren Taster ein Kinderspiel.
Viel machen musst du eigentlich nicht, nur abgucken und sanft erweitern.

Pullup:
gut, dann die Pullup Variante. Macht vieles leichter, weil das bei den meisten Programmierern die Standardeinstellung ist. Spart den externen Widerstand, Taster zwischen Pin und Masse.

// https://forum.arduino.cc/index.php?topic=617098.0

unsigned long Gewicht = 20;

struct Taster
{
  byte pin;
  bool read = true;
  bool oldRead = true;
  bool state = false;
};

Taster taster2;
Taster taster3;

void setup() {

  taster2.pin = 2;
  taster3.pin = 3;

  pinMode(taster2.pin, INPUT_PULLUP);
  pinMode(taster3.pin, INPUT_PULLUP);
  Serial.begin(115200);
}


void loop() {

  update_Taster();

  if (taster2.state) {
    Gewicht++;
  }

  if (taster3.state) {
    Gewicht--;
    if (Gewicht < 20) {
      Gewicht = 20;
    }
  }

  anzeige(Gewicht);
}


void update_Taster ()
{
  static unsigned long last_ms = 0;
  unsigned long ms = millis();

  taster2.state = false;
  taster3.state = false;

  if (ms - last_ms >= 40) {
    last_ms = ms;

    taster2.read = digitalRead(taster2.pin);
    taster3.read = digitalRead(taster3.pin);

    if (!taster2.read && (taster2.oldRead) ) {
      taster2.state = true;
    }
    
    if (!taster3.read && (taster3.oldRead) ) {
      taster3.state = true;
    }

    taster2.oldRead = taster2.read;
    taster3.oldRead = taster3.read;
  }
}


void anzeige (unsigned long gewicht)
{
  static unsigned long altesGewicht = 0;

  if (gewicht != altesGewicht)
  {
    Serial.print(F("Gewicht: "));
    Serial.print(gewicht);
    Serial.print("g");
    Serial.print("\t\t");
    Serial.print((gewicht/1000.0), 3);
    Serial.println("kg");
    altesGewicht = gewicht;
  }
}

Okay ich werde mich mal damit bis morgen auseinandersetzen. Falls ich noch fragen habe oder ich es nicht Akzeptabel zusammen bringe hoffe ich das ich auf die Hilfe der Community zählen kann?? :D

Was bedeutet "long int"?? Ist damit gemeint das die erste Variable den Datentyp "Long" besitzt und die zweite dann den Datentype "Int" oder bedeutet das was anderes??

"long int" ist nur eine umständliche Schreibweise für "long". Du kannst auch "signed long int" schreiben um es noch deutlicher zu machen

Achso also sind beide Variablen zwei einfache Long Datentypen

Hi

Oder Du schreibst int32_t (für signed) oder uint32_t (für unsigned). Gleiches geht auch mit 64,16,8 und bestimmt, wie viele Bit diese Variable breit ist. Das U sagt, daß die Variable kein Vorzeichen hat, also keine negativen Werte annehmen kann. Byte (=uint8_t) 0...255 (8 Bit) char (=int8_t) -128...127 (8 Bit, davon 7 für den Wert und das MSB für das Minus)

Persönlich finde ich diese Schreibweise 'eingängiger'/logischer. Ein int ist hier auf dem normalem Arduino 16 Bit, auf den ARM-Typen 32, wenn ich das Gelesene recht interpretiert habe. Mein uint16_t bleibt 16 Bit, egal auf welcher Hardware.

MfG

So habe eine kleine Frage da ich schon fast fertig bin mit dem Umschreiben der beiden Codes. Wie würde der Code aussehen das ich einen Taster abfragen kann der schon benutzt ist ob dieser statt nur einmal zweimal in einer kurzen Zeit gedrückt wurde?? Möchte nämlich eine Variable auf True setzen wenn dies zutrifft und wenn ich dann den Taster nochmals in kurzer Zeit doppelt Drücke wieder zurück auf False.

Edit: Dabei wäre es oder besser gesagt möchte ich den Taster mit dem ich Inkrementiere verwenden.

Hi

Du merkst Dir, wann Du zuletzt den Tastendruck erkannt hast. Wenn zwischen dem Letzten und diesem Tastendruck eine vorgegebene Zeit nicht überschritten wurde, ist Das Dein Doppel-Klick. Was Du dann machst, unterliegt einzig Deiner Phantasie. Klar: Wenn Doppelklick, dann keine Einzel-Klick-Events auslösen.

Das gibt's aber bereits fertig, such Mal nach "Button" in den Libs in der IDE - dort sollte sich was finden lassen.

MfG

Du könntest Dir die Bibliothek OneButton ansehen.