Arduino Durchschnitt von Werte ermitteln

merlin123

Lt. Commander
Registriert
Jan. 2018
Beiträge
1.808
Guten Morgen!

Ich habe vor mittles eines Tasters, die Durchschnittstemperatur auszulesen und diese an ein LC-Display anzuzeigen. Verwendet wird der DTH22 Sensor, der bisher Luftfeuchtigkeit und Temperatur messen kann sowie ein Drehencodermenü hat, nur fehlt die Idee den Durchschnitt auszugeben. Bisher habe ich folgenden Code:

Code:
  // Bei Tastendruck Ausgabe der Durchschnittstemperatur
  buttonState = digitalRead(knopf);
  if (buttonState == HIGH) {
    /*
    for(int j; j>59;j++)
    {
      if(tempSchnitt[j]=-30){
        j = 59;
        }
     gesamt = gesamt+tempSchnitt[j];
     k++;   
      }
    if(k = 59){
      durchschnitt=gesamt/60;
      }
    else{
      durchschnitt=gesamt/k;
      }

    */

Kann mir bitte jemand der Ahnung hat, erklären warum dieser nicht funktioniert? Bei Tastendruck kriege ich eine Ausgabe mit Durchschnitt: 0.
Ich habe keine Lust irgendwas aus dem Netz zu kopieren, sondern wirklich zu verstehen was ich mache. Wäre über Hilfe dankbar
 
Kleiner Tipp: Wenn du die Schleife vorzeitig verlassen willst (ich nehme an -30 ist dein default wert, wenn noch keine Temperatur geschrieben wurde) nutze den "break" Befehl, anstatt den Zähler künstlich zu erhöhen.
Darüber hinaus, gehe sicher, dass du die Variablen/Zähler wie j, k, und gesamt sauber initialisierst ("int j = 0" etc.)

Dazu musst du zum Vergleichen zwei = (==) nehmen (für die Zeile : (tempSchnitt[j]=-30)

Darüber hinaus, solltest du dir eine Flankenerkennung bauen, sodass die Schleife beim Drücken nur einmal durchlaufen wird.

Und deine Abbruchbedingung für die Schleife ist falsch.
 
Zuletzt bearbeitet:
Als was sind die Variablen deklariert?
 
wieso lautet die schleifenbedingung j > 59? die ist ja direkt false. die schleife wird gar nicht durchlaufen. außerdem wird j nicht initialisiert. es muss lauten

Code:
for(int j = 0; j < 60; j++) {}

und noch dazu das doppelte istgleich beim vergleichen, das @Nilson angesprochen hat! du machst in den ifs zuweisungen anstatt vergleiche ;) die sind somit im moment immer true.
der teil mit if tempSchnitt == -30 die schleife abbrechen durch j = 59 ist leider wirklich unschön, das kann man mit break besser lösen. noch dazu ist ja der komplette code innerhalb der if buttonState == HIGH auskommentiert und die schließende geschweifte klammer fehlt! :D

Code:
// Bei Tastendruck Ausgabe der Durchschnittstemperatur
buttonState = digitalRead(knopf);
if (buttonState == HIGH) {
    int j = 1;
    for(; j <= 60; j++)
    {
        if(tempSchnitt[j] == -30){
            break;
        }
        gesamt += tempSchnitt[j];
    }
    durchschnitt = gesamt / j;
}

jetzt kannst du k weglassen. j wird mit 1 initialisiert, damit es nachher kein division by zero gibt. dafür ändern wir die schleifenbedingung von j < 60 zu j <= 60, damit j bis 60 hochgeht und nicht bis 59. wenn tempSchnitt[j] -30 ist, bricht die schleife ab, ansonsten wird gesamt um den wert erhöht. anschließend wird gesamt / j (j Element von [1; 60]) in durchschnitt gespeichert.
 
Zuletzt bearbeitet:
Die Formulierung der for-Schleife strotzt vor Fehlern. Das hat Caipi dir ja schon erklärt.

Wie werden denn die Messwerte erfasst? Werden die zeitlich äquidistant eingelesen? Dann kannst du eigentlich dort an der Stelle schon die Mittelwerte immer mitberechnen anstatt erst bei Knopfdruck.

Zum Knopfdruck: So ein Taster ist nicht ideal. In der Regel prellen die (es sei denn sie haben einen analogen Tiefpass verbaut). Also wenn du den Taster mit hoher Frequenz abtastest wirst du ggf. mehrere Flanken/EinAus während des Druckvorganges bekommen. Auch hier muss man mehr oder weniger einen Tiefpassfilter bauen durch eine Art Mittelwertbildung. Gibt glaube auch ein Beispiel-Sketch zum Debouncing in der Arduino-IDE.
 
ich tippe mal darauf, das das tempSchnitt-Array ein int[60]-Array ist, richtig?
Im jetzigen Code müsstest du jedes mal, wenn du die Array-Größe anpasst die for-Schleife mitanpassen.
-> nimm als Abbruchgedingung: j<= sizeof(tempSchnitt)/sizeof(tempSchnitt[0]) - 1

@Cai-pirinha: wenn du die Schleife so durchlaufen lässt, wird tempschnitt[0] nicht beachtet und du rennst in einen Fehler rein (oder du liest Mist), wenn das Programm versucht tempSchnitt[60] zu lesen (das Array geht von 0-59).
Also brauchst du entweder eine Abfrage j != 0 oder du schreibst j vor dem break.

Generell ist der Code trotzdem Fragwürdig, wie die anderen gesagt haben. Warum ist die gesamte weitere Messreihe ungültig, wenn nur ein Wert -30 ist? Warum fragst du das mit einem Taster ab?
 
ja, stimmt, sorry, man betrachte innerhalb der schleife dementsprechend tempSchnitt[j-1]. der autor ist ja sowieso scheinbar brennend an den gewünschten erklärungen interessiert..
 
Danke für die Antworten, bin schon ein ganzes Stück weitergekommen
 
Die Entschuldigung gleich vorweg: Ich drifte gerne mal ins over engineering ab...

Hi, also wenn ich das bis hierhin richtig verstanden habe, ist dein Setup folgendes:
Arduino + Sensor
Wird ein Knopf betätigt, dann sollen Werte gesammelt werden, vermutlich willst du 60 Werte haben
Aus der Datensammlung sollen dann Durchschnittswerte berechnet werden

Anhand deines Codes kann ich dir ein paar hoffentlich hilfreiche Dinge aufzeigen:

Das Grundgerüst ist schon richtig gewesen:
Code:
if (buttonState == HIGH) {...}
Wird ein Button betätigt, dann... Ich sehe hier aber ein großes Problem, denn der Aruduino läuft in seiner ewigen Loop-Schleife immer durch den Programm Code, das macht er, indem er von oben nach unten den Code durchläuft. Aber naja, das nur als Hinweis. So ein Button verursacht oft mehr Probleme als gedacht, da kann man nun viele Begründungen nennen. Ich kann die Idee eines Buttons aber durchaus verstehen, in der Praxis scheitert das nur extrem häufig...

Jetzt werden 60 Werte gesammelt:
Code:
for(int j; j>59;j++){}
Das Problem hierbei ist, j ist nicht initialisiert, das sollte so normalerweise nicht funktionieren. Zusätzlich fängt deine Zählung an, wenn j echt größer als 59 ist.

Die Korrektur (ACHTUNG DAS IST JAVA! FÜR C entsprechend anpassen!!!)
Wir haben ein Array mit Temperaturen
Code:
double[] arr = {1,2,3,4,5,6};
double sum = 0;				
double durchschnitt = 0;	
for(int i = 0; i < arr.length; i++) {
	sum = sum + arr[i];
}
durchschnitt = sum/arr.length; // Das könnte man nochmal zusätzlich absichern 0/6 geht nicht!!!
System.out.println("Summe der Werte: " + sum + "\n" + "Durchschnitt: " + durchschnitt);
Wichtig auch hier nochmal: Der Datentyp ist wichtig, beim double (in C von mir aus float..) bekomme ich den exakten Wert:
21/6 = 3.5 // Das sollte richtig sein
Beim int hingegen:
21/6 = 3
Das macht schon einen Unterschied...

Jetzt benötigt man eigentlich nur noch eine Schleife, die die Daten in das Array packt, das mache ich mal im Pseudocode:
double neues_array
Für i = 0 bis Arraylänge-1
... neues_array = Wert_auslesen //lese Wert aus, da gibt es gute Mittel speziell für den Sensor (Passende Lib)
end

Mit diesem Array kann man nun weiterrechnen.

Ich habe aber eine Grundsätzliche Frage, warum machst du das so kompliziert?
Also diese Idee mit dem gedrückten Button, ich weiß nicht genau, ich finde das extrem statisch. Und auch von der Praktischen Seite ist das nicht so sauber. Ich würde einfach ein Timer Modul anfügen, das geht am Arduino auch sehr einfach, dann liest du die Zeit ab und zu jeder vollen Stunde, oder was auch immer machst du dann eine Messung.
Ich muss auch sagen, dass diese Berechnungen auf dem Arduino sehr Fehleranfällig sind (Array Übergabe und Arraylänge...). Wenn ich das implementieren würde, dann hätte der Arduino ein Funkmodul und würde die Werte an eine Datenbank schicken, da kann man dann eine richtige Langzeitstatistik führen und richtig interessante Berechnungen durchführen. Also Streuweite, Min und Max, Temperaturverlauf. (Mir läuft gerade das Wasser im Mund zusammen).

Warum sammelst du 60 Werte, da erkenne ich die Semantik nicht so ganz 60, weil es 60 Minuten in einer Stunde gibt? 60 Verteilt auf den Tag?


Für den Arduino könnte das circa so aussehen (Das müsste man dann noch mit dem if Button pressed ummanteln)
Code:
int sensor_name = A0; // Am analog Anschluss 0 
float temperatur = 0;
float sum = 0;
float temp_arr[61];

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  for(int i = 0; i < 61; i++){
      temp_arr[i] = analogRead(sensor_name); // Wichtig oft gibt es hier noch Umrechnungen
    }

    for(int j = 0; j < 61; j++) {
      sum = sum + temp_arr[j];
    }
    temperatur = sum/60;
    Serial.print(temperatur);
}

Ich hoffe, dass das irgendwie für dich konstruktiv war. :)
 
Zuletzt bearbeitet:
Dankeschön, hat geklappt
 
Zuletzt bearbeitet:
Zurück
Oben