Merkwürdiges Ergebnis bei einfacher Multiplikation

Hallo

Ich bin gerade dabei mir mit einem Arduino MEGA 2560 eine Aquariumsteuerung zu bauen. Ich habe gerade Probleme mit einer Funktion die mittels Dosierpumpen Zusätze ins Aquarium dosieren soll.
Dabei ist ein sehr komisches Problem aufgetreten. Jede 2. Pumpe wird zwar eingeschaltet aber nicht wieder abgeschaltet. Ich habe das Problem eingrenzen können und zwar tritt das an der Stelle auf wo die Laufzeit der Pumpe berechnet wird.
Das ist eine einfache Multiplikation von 2 positiven Werten. Das Ergebnis ist aber negativ und nicht ansatzweise richtig.

Hier mal ein Bild mit Serial-Monitor:

Ich habe auch mal eine zusätzliche Multiplikation 2er Werte eingefügt und da ist das gleiche Problem.

Jemand eine Idee was da los ist? Bei den Durchläufen wo i=ungerade Zahl ist, ist Alles super.

Hier die Funktion:

void dosAdditive()
{
	//Dosierung der einzelnen Zusätze erfolgt im Versatz von jeweils 1 Stunde.
	//Dosierpumpen müssenb alle gleich sein und bei gleicher Zeit, gleich viel dosieren.
	
	for (int i = 0; i < 10; i++)  
	{
		Serial.print("dosAdditive() Durchlauf ");
		Serial.println(i);
		if ((dosingPumpPin[i] != -1) && (dosage_settings[i] > 0)) //Wenn Dosierpumpe vorhanden und Dosiermenge > 0
		{ 
			Serial.print("Dosierpumpe vorhanden, Durchlauf ");
			Serial.println(i);
			if (hour() == (firstDosageHour + i))
			{ 
				Serial.print("Stunde für Dosierung Durchlauf ");
				Serial.println(i);
				Serial.print("firstDosageHour + i = ");
				Serial.println(firstDosageHour + i);
				//Wenn noch nicht dosiert wurde
				if ((dayDosageDone != day()) && (!dosAdditiveDone[i]))
				{
					Serial.print("Noch nicht dosiert Durchlauf ");
					Serial.println(i);
					if (digitalRead(dosingPumpPin[i]) == HIGH) //Wenn Dosierpumpe AUS
					{
						Serial.print("Pumpe einschalten Durchlauf ");
						Serial.println(i);
						dosageStartTime[i] = millis();
						Serial.print("dosageStartTime ");
						Serial.println(dosageStartTime[i]);
						Serial.print("Log Eintrag senden Durchlauf ");
						Serial.println(i);
						//Log Eintrag in Datenbank schreiben
						unsigned long t = dosageStartTime[i] + 500;
						char msg[100];
						snprintf(msg, sizeof(msg), "msg=Dosierung %d gestartet (%lu ms)", (i+1), t);
						strncpy(log_alarm_msg_str, msg, 100);
						sendMsg(0);
						delay(500);

						process = i + 1;
						Serial.print("process = ");
						Serial.println(process);
						runningProcesses = true;
						Serial.print("runningProcesses = ");
						Serial.println(runningProcesses);
						digitalWrite(dosingPumpPin[i], LOW); //Dosierpumpe EIN	
						maintenance[i + firstDosageRelay] = 1; //neuen Relaiszustand speichern
					}

					//RAM-Auslastung anzeigen
					int fm = freeMemory(); //freier Speicher in Byte
					fm = 8192 - fm;
					float mem = (float)fm / 8192.00;
					mem = mem * 100;
					fm = round(mem);
					Serial.print("RAM zu ");
					Serial.print(fm);
					Serial.println("% belegt.");

					int ml = 25*1800;
					Serial.print("ml = ");
					Serial.println(ml);

					//Laufzeit der Dosierpumpe berechnen
					int t = dosage_settings[i] * 1800; //1ml = 1500ms

					Serial.print("Soll-Laufzeit Durchlauf ");
					Serial.print(i);
					Serial.print(" = ");
					Serial.println(t);

					if ((unsigned long)(millis() - dosageStartTime[i]) >= t)
					{
						Serial.print("Laufzeit Durchlauf");
						Serial.print(i);
						Serial.println(" erreicht.");
						unsigned long et = millis();
						digitalWrite(dosingPumpPin[i], HIGH); //Dosierpumpe AUS

						//Log Eintrag in Datenbank schreiben
						unsigned long dt = (unsigned long)(et - dosageStartTime[i]);
						char msg[100];
						snprintf(msg, sizeof(msg), "msg=Dosierung %d beendet. Dosierzeit: %lu ms (%lu ms)", (i+1), dt, et);
						strncpy(log_alarm_msg_str, msg, 100);
						sendMsg(0);
						delay(500);

						maintenance[i + firstDosageRelay] = 0; //neuen Relaiszustand speichern
						dosAdditiveDone[i] = true; //Dosierung für aktuellen Tag durchgeführt
						process = 0;
						runningProcesses = false;
					}
				}
			}			
		}
		else
			dosAdditiveDone[i] = true; //Dosierung für aktuellen Tag auf "durchgeführt" setzen, da keine Dosierpumpe vorhanden
	}//for-Schleife

	int c = 0;

	for (int i = 0; i < 10; i++)
	{
		Serial.print("dosAdditiveDone[");
		Serial.print(i);
		Serial.print("] = ");
		Serial.println(dosAdditiveDone[i]);
		if (dosAdditiveDone[i])
			c++;
	}

	//Wenn alles dosiert wurde, nächsten Dosiertag setzen
	if (c == 10)
	{
		dayDosageDone = day();
		for (int i = 0; i < 10; i++)
			dosAdditiveDone[i] = false;
	}
		
}

Das ist eine einfache Multiplikation von 2 positiven Werten.

Eine Multiplikation ist nie einfach :wink:

Problem wird wohl sein, dass int * int als Ergebnis nur int liefert.
Undintist max 32767 auf einem 8 bit Arduino wie dem MEGA 2560.

Dein Code ist mir zu groß um die Stelle zu suchen, aber so kannst du mal rumspielen:

void setup () {
  Serial.begin(9600);
  int a = 500;
  int b = 100;

  Serial.println(a*b); // liefert was negatives
  Serial.println(a*100L); // long Berechnung, liefert (long)50000
}

Nachtrag: 180025 ist natürlich - 20536, und nicht 45500, wie kommst du darauf? :stuck_out_tongue:
Der Windows-Taschenrechner hat einen "Programmierer"-Modus, der zeigt dass
1800
25 in Hex AFC8 ergibt, was als WORD eben der -20536 entspricht.

Da ist übrigens jeder schonmal drauf reingefallen.

Der Fehler liegt hier:

int ml = 25*1800;

Das ist für int zu groß!

HotSystems:
Der Fehler liegt hier:

int ml = 25*1800;

Das ist für int zu groß!

Oh man so simpel :o
Da hätte ich jetzt erstmal nicht dran gedacht dass das schon zu viel ist...

zufällig hatte ich natürlich nur bei jeder 2. Pumpe die Angabe in ml bei 20 und mehr.

Danke!

Aber eben daran denken dass selbst wenn du die Variable in long änderst, trotzdem erst mal in int gerechnet wird. Es sei denn man macht es explizit anders.

Serenifly:
Aber eben daran denken dass selbst wenn du die Variable in long änderst, trotzdem erst mal in int gerechnet wird. Es sei denn man macht es explizit anders.

Ja stimmt! Danke für den Hinweis! Jetzt klappt alles :slight_smile: