Spannungs Mittelwert erfassen und ausgeben

Hallo,

ich bin neu bei dem Thema Arduino und habe so ein Problem gerade.
Ich will eine Spannung auslesen welche 20V beispielweiße beträgt.
Das Auslesen funktioniert gut und dass Umrechnen habe ich auch hinbekommen.
Mein Problem ist es, dass die Spannung ziemlich schwankt bei der Seriellen Ausgabe.
Ich möchte jetzt einen Mittelwert aus z.B. 10 Spannungen erfassen und am Seriell Monitor ausgeben. Aber bekomme das mit meinem jetzigen wissen noch nicht hin.

Hier mein Programmausschnitt:

void setup() 
{
  Serial.begin(9600);
}

void loop()
{
  int sensor = analogRead(A0);
  float spannung = sensor * (5.0 / 1023.0) * 6;
  Serial.println(spannung);
}

leonko12:
ich bin neu bei dem Thema Arduino und habe so ein Problem gerade.
...

Dann befasse Dich mal mit „Arrays“ (Feldvariablen).

Leg' ein Array mit z.B. 10 Werten an, das Du in den ersten 10 Schleifendurchläufen füllst. Ab dem 11. loop()-Durchlauf kannst Du dann einen Durchschnitt ausrechnen. Anschließend werden die einzelnen Werte „nach hinten“ weitergeschoben - der letzte Wert fällt raus, der erste wird mit dem nächsten Gelesenen befüllt.

Gruß

Gregor

Hallo,

such mal nach gleitendem Mittelwert, oder versuch mal das

Heinz

float puffer;

void setup()
{
  Serial.begin(9600);
}

void loop()
{
  int sensor = analogRead(A0);
  float spannung = sensor * (5.0 / 1023.0) * 6;

  float mwert = mittelwert(spannung, puffer, 10);

  Serial.println(mwert);
}

// Berechnung gleitender Mttelwert--------------
float mittelwert( float Rohwert, float &buff, float faktor)
{
  float mi ;
  buff = buff - buff / faktor;
  buff = buff + Rohwert;
  mi = buff / faktor;

  return mi;

}

danke für euren beiden Tipps
ich werde diese gleich mal testen.
In der Zwischenzeit habe ich es mal Selbstständig versucht und ich habe es mit dem Code eigentlich hinbekommen.

int millisec = 1000;
void setup()
{
  Serial.begin(9600);
}
int durchlaufe = 0;
float zaeler = 0;
void loop()
{
  while ( durchlaufe < millisec)
  {
    int sensorValue = analogRead(A0);
    float voltage = sensorValue * (4.99 / 1023.0) * 6;
    zaeler = zaeler + voltage;
    durchlaufe = durchlaufe + 1 ;
    delay(1);
  }
  if (durchlaufe >= millisec)
  {
    float mittelwert = zaeler / millisec;
    Serial.print(mittelwert);
    Serial.println("V");
    zaeler = 0;
    durchlaufe = 0;
    mittelwert = 0;
  }
}

dass Problem welches ich in habe ist, dass es nicht die gleiche Spannung ist, wie am Multimeter anzeigt wird.
Im Programm wird mir immer eine Spannung angezeigt die 0,1V höher ist.

Hallo,

na ja , wenn Du das Multimeter richtig ist , dann rechne doch einfach 0,1V runter , vermutlich liegt ein Offset vor.

Eventuell benennst Du Deine Variablen noch um , damit Du in 6 Monaten noch weisst was Du da gemacht hast. Dann kannst Du mal überlegen ob Du wirklich so schnell messen willst. Und das Du zwischendurch deinen Mittelwert wieder auf 0 setzt ist auch nicht so pickelnd. Es könnte ja sein das Du später den Wert noch für etwas anderes benötigst.

Zaeler würde ich z.B summe nennen und millisec anzahl.

ich hab noch mal in meiner Bastelkiste nachgesehen, und noch was gefunden. Einfacher geht es nicht. Schau Dir das mal an.

Die anzeige geht auf auf dem Plotter Werzeuge/serieller Plotter

Heinz

uint32_t altzeit;
float messwert, mittelwert;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
}

void loop() {
  // put your main code here, to run repeatedly:

  if (millis() - altzeit >= 100) { // alle 100 ms messen
    altzeit=millis();
    messwert = 100 + random(-10, 10); // Messwert simulieren 
    
    mittelwert = 0.9 * mittelwert + 0.1 * messwert;
    Serial.print (mittelwert); Serial.print('\t');
    Serial.println(messwert);
  }
}

leonko12:
Mein Problem ist es, dass die Spannung ziemlich schwankt bei der Seriellen Ausgabe.
Ich möchte jetzt einen Mittelwert aus z.B. 10 Spannungen erfassen und am Seriell Monitor ausgeben.

Warum willst Du 10 Werte im Kreis aufnehmen?
Warum musst Du alle Werte erst in float umrechnen?

Würde es nicht reichen, die Werte nur alle XX ms auszugeben?

Nur mal so als Idee:
merke die Zeit - Lese den Port - Addiere zum letzten Wert - teile durch 2 - ist Zeit abgelaufen, gebe aus - fange an von vorn.

const int readPin = A0;
int spannung = 0;
unsigned long lastmillis = 0;
void setup() {
  Serial.begin(115200);
  Serial.println(F("Start"));
  spannung = analogRead(readPin);
}

void loop() {
  if (millis() - lastmillis > 500) // Bedingung in ms
  { 
    Serial.println(spannung * 5.0 / 1023.0 * 6); // Ich gebe zu, hier ist Verbesserungsbedarf(!) u.a. DIV/0 wird nicht abgefangen ist aber egal für die Vorstellung
    lastmillis = millis();
  }
  spannung = ((spannung + analogRead(readPin)) / 2);
}

Ja, man kann natürlich auch noch festlegen, das der gelesene Wert nicht mehr als xxx vom letzten wert abweichen darf und was weiss ich nicht alles... Aber probier das mal aus.

mit den Libs INTERVAL.h und RunningMedian ist das effektiv und mit wenigen Zeilen Code erschlagen. Weiterer Vorteil, Ausreisser kann man damit sehr einfach unter den Tisch fallen lassen.
Man füllt z.B. 21 Werte, nimmt aber nur den Durchschnitt der 11 mittleren (sortierten) Werte.
Mit INTERVAL(zeit_in_ms) schreibt man eine Auslesung blockierungsfrei ins Array.

ElEspanol:
Man füllt z.B. 21 Werte, nimmt aber nur den Durchschnitt der 11 mittleren (sortierten) Werte.
Mit INTERVAL(zeit_in_ms) schreibt man eine Auslesung blockierungsfrei ins Array.

Das ist sicher alles schick für hochpräzise Aufgaben.
Aber für einen 10bit Analogwert umzurechnen in eine Momentananzeige?

Ich nehme 21 Werte, reduziere diese auf 11, aus denen der Durchschnitt, diesen dann auch noch in einen Ringspeicher und dann daraus den Mittelwert?
Für einen 10 bit Wert?
Der, ich sage mal im 500ms Takt, angezeigt wird?

Ich messe in 5oo ms blank weit über 4000 Werte

  • errechne daraus meinen Wert
  • und gebe den aus

Ich finde es noch immer absurd aus einem Wert zwischen 0 und 1023 einen Quotienten in float zu errechnen, der dann in den Ringspeicher gehen soll.

Ich nehme den Wert den ich aus A0 auslese, adiere in zu einer Summe dazu und adiere auch auf den Zähler 1 dazu. Sind 1000ms abgelaufen, nehme ich die Summe der ausgelesenen Werte, teile sie durch den Zähler, und rechne aus diesem Ergebnis die Spannung aus. Ergebnis anzeigen, Zähler, Summenspeicher und die Millis() auf Null stellen. Und fertig ist die Laube für die nächste Runde. Wenn ein 100ms oder ein 500ms Tackt für die Anzeige gewünscht ist, dann eben nach dieser Zeit Summe durch Zählerstand und daraus die Spannung, alles auf Null, fertig für den nächsten Durchgang. Zu kurze Abstände machen das ganze zu unruhig, also ich würde mindestens 500ms oder eben 1000ms bis zur Anzeige des neuen Wertes nehmen.

Franz

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.