einfache Verständnisprobleme beim Messen von Kapazitäten

Guten Tag!
Ich bin noch ziemlich neu in der Welt der Microcontroller, deshalb arbeite ich momentan noch an einfachen Projekten.
Momentan versuche ich mithilfe des Arduinos eine Kapazitätsmessung/-bestimmung durchzuführen.

Dabei richte ich mich nach folgendem Tutorial:

Ich kann jedoch zwei Abschnitte des Codes nicht ganz nachvollziehen!

1.:

elapsedTime= millis() - startTime;

Theoretisch kann “elapsedTime” ja nicht negativ werden, muss also mindestens einen Wert von 0 oder 1 haben.
Ich habe die Vermutung, dass diese Zeile mit der Zeitkonstante Tau und den 63,2% aufladen nach 1 Sekunde zusammenhängt. Ich kann es mir jedoch leider nicht selbst herleiten und im Internet kann ich dazu leider auch nichts finden.

2.:

while(analogRead(analogPin) < 648){       // 647 is 63.2% of 1023, which corresponds to full-scale voltage
  }

  elapsedTime= millis() - startTime;
 // convert milliseconds to seconds ( 10^-3 ) and Farads to microFarads ( 10^6 ),  net 10^3 (1000)  
  microFarads = ((float)elapsedTime / resistorValue) * 1000;  
  Serial.print(elapsedTime);       // print the value to serial port
  Serial.print(" mS    ");         // print units and carriage return

Die “while(analogRead(analogPin) < 648){}”-Schleife ist leer. Bedeutet dies, dass “elapsedTime= millis() - startTime;” erst startet, sobald “while(analogRead(analogPin) < 648){}” nicht mehr erfüllt ist?

Ich hoffe, dass meine Fragen verständlich sind (und jemand die Antwort kennt :smiley: ).

Vielen Dank!

(PS: Falls ich Fehler bei der Schreibweise von Codes etc. in meinem Topic gemacht habe, würde ich mich über Hinweise freuen, damit ich dies in Zukunft korrekt machen kann.)

Hi,

ich bastle gerade wieder nebenbei an meinem R & C - Mess-Dingens, arbeitet nach gleichem Prinzip.

Sobald die 5V über den Messwiderstand auf den Kondensator geschalten werden, wird die StopUhr gestartet, und die while-Schleife ist so lange am Schleifen basteln, bis die Bedingung ADC misst mehr als 648 rawADC erfüllt ist. Dann wird die StopUhr angehalten, die Startzeit abgezogen. Die 648 entsprechen den 63,2% entsprechen 1 Tau.

Gruß André

PS: Wer mag kann die 2x "p" verteilen ;-)

Bedeutet dies, dass “elapsedTime= millis() - startTime;” erst startet, sobald “while(analogRead(analogPin) < 648){}” nicht mehr erfüllt ist?

Logisch richtig.

Wobei mich das Wort “startet” extrem stört.

Ersetze “startet” durch “ausgeführt wird”, denn von einem “Start” kann man da nicht reden.
Eher von einem Ende (der leeren) Schleife.

elapsedTime= millis() - startTime;

millis() ist eine Funktion die die Millisekunden zurückgibt, die seit Einschalten vergangen sind. startTime wird eine Variable sein in die am Anfang der Messung (in der Vergangenheit) die Millis() -Zeit abgespeichert wurde. Darum ist dieser Wert immer kleiner als der aktuelle millis() Wert. Dies gilt auch beim Überlauf des millis() der nach ca 49,5 Tagen eintritt.

https://www.leifiphysik.de/elektrizitaetslehre/ladungen-felder-oberstufe/ein-und-ausschalten-von-rc-kreisen
Steht irgenwo in der Mitte:

Nach der Zeitkonstante τ=R⋅C ist UC auf ca. 63% von |U0| angestiegen.

Das heißt daß beim Aufladen eines leeren Kondensators über einen Widerstand R wenn die Spannung am Kondensator 63% von der Ladespannung (in unserm Fall 5V) erreicht hat, die Zeit tau = R*C vergangen ist. C errechnet sich aus tau/R.

while(analogRead(analogPin) < 648){       // 647 is 63.2% of 1023, which corresponds to full-scale voltage  }

Der Controller ist solange in der Schleife gefangen bis der Analogwert größer gleich 648 wird.

Danach wird die Ladezeit elapsedTime des Kondensators bestimmt und mit dem Ladewiderstand in eine Kapazität umgerechnet.

Grüße Uwe

Vielen Dank für eure Antworten!

Ich habe schon etwas mehr verstanden als vorher! :D

Nach meinen folgenden zwei Fragen müsste ich eigentlich auch alles verstanden haben:

1.: Müsste aus physikalischer (bzw. elektrotechnischer) Sicht die "elapsedTime" nicht immer gleich 1 sein, sobald der Kondensator auf 63,2% geladen wurde?

2.: Wieso benötige ich eigentlich noch einen entladePin mit 220 Ohm? Kann man den Kondensator sich nicht einfach über den GND entladen lassen?

Hi,

die gemessene Zeit ist direkt proportional zu C, wenn immer bis zum erreichen von 1Tau gemessen wird.
Z.Bsp. ergeben 1µF mit 100kOhm aufgeladen bis 1Tau immer 100ms, 10µF / 100kOhm immer 1s …

Über den zweiten, niederohmigen Widerstand wird der Kondensator schneller gegen GND entladen, dauert sonst zu lange, da ein geladener Kondensator ca. 7 oder 8Tau bis auf 0V benötigt.

Gruß André

1) Der Kondensator wird zuerst bis 63% geladen und dann entladen (auch wenn ich die Reihenfolge umkehren würde). Danach startet der Zyklus von neuem. Darum hast Du keine 2 aufeinanderfolgenden schnellen Messungen mit einer 63% Spannung.

pinMode(dischargePin, OUTPUT);            // set discharge pin to output
  digitalWrite(dischargePin, LOW);          // set discharge pin LOW
  while(analogRead(analogPin) > 0){         // wait until capacitor is completely discharged
  }
  pinMode(dischargePin, INPUT);            // set discharge pin back to input

2) Irgendwie muß man den + Pol des Kondensators ja mit Masse verbinden. Dieser Sketch sieht vor, daß es mittels eines Pins gemacht wird (siehe obrigen Auszug). Damit der Strom nicht zu groß für das Pin wird ist ein 220Ohm Widerstand da. Wenn man einen Starken MOSFET nimmt, dann kann man das auch mit kleineren Widerständen machen. Null Ohm würde ich aber nie vorsehen.

Grüße Uwe

Hallo,

meine Meinung: Da man einen Kondensator nicht absolut entladen kann, weil auf 0V entladen unendliche Zeit bedeutet, hat man damit immer Rechnenfehler drin. Die sich dann bei Messwiederholungen bemerkbar machen.

meine Lösung: Wenn ich das machen müsste. Um Rechenfehler zu kompensieren, weil man nicht von idealen Zuständen ausgehen kann, rechnet man nur mit Differenzen. Man entlädt C auf einen unkritischen Bereich. Legt man mit einem A/D Digit Schwellwert fest. Merkt sich die Ladespannung Uc1 zum Zeitpunkt t1 und lädt ihn auf Spannung Uc2 zum Zeitpunkt t2 auf. Für Uc2 und t2 legt man ebenfalls Schwellwerte fest. Je nach Kondensatorkapazität wird das eine oder andere zuerst gültig, sonst wartet man womöglich ewig. Für Uc1 und Uc2 würde ich direkt die Digits vom A/D nehmen. Nicht erst in Spannung umrechnen. Der Rest ist rechnen. ;)

C = -(t2-t1) / R / ( ln(1-(Uc2/Ub)) - ln(1-(Uc1/Ub)) )

Damit ist man nur noch von der R Genauigkeit und Ub Stabilität/Genauigkeit abhängig. Für die Zeitmessung würde ich µs nehmen statt ms.

Hallo Doc,

Du hast Recht! Und ich finde Deine Ausführungen toll und auch für mich hilfreich! Nur schau mal auf den 1. Satz, 2. Hälfte des TO. Auch ich habe vor einem Jahr damit angefangen, ein Mess-Dingens auf Lochraster zu löten, und daran immer mal was rumzuprogrammieren. Wer aber mit sowas anfängt, möchte nicht Mathematik der 12. Klasse wiederholen, und wenn doch, dann zumindest nicht mit dem ersten Projekt. Wenn man aber das Kondensator-MessDing (Gerät will ich es bei mir nicht nennen) immer weiter treibt, um auf möglichst genaue Messergebnisse zu kommen, stolpert man über ganz andere Dinge, nicht nur das bei "0" anfangen, das ist das kleinste Übel. Ich kann zumindest zwischen 10pF und 10mF recht genau messen, und kämpfe zur Zeit mit den letzten 0,5% bis 0,1% Genauigkeit, aber immer im Rahmen dessen was ein Arduino-ADC so kann. Deine Formel "C = -(t2-t1) / R / ( ln(1-(Uc2/Ub)) - ln(1-(Uc1/Ub)) )" werde ich nach dem roten Mann mit weißem Bart mal ausprobieren.

@ TikiMaske, wenn es mehr als nur mal antesten werden soll, dann löte Dir was auf eine Lochrasterplatte. Mit dem Steckbrett kann man sowas gut testen, aber messen nicht, das wird eher schätzen!

Gruß André

Doc_Arduino: Für die Zeitmessung würde ich µs nehmen statt ms.

Ich würde auch verschiedene Ladewiderstände nehmen um die Messzeit in einem gewissen Ramen zu halten. Natürlich wird dadurch der Sketch komplizierter da man mehrere (vor)Messungen machen muß um zu wissen welcher Ladewiderstand der beste für die unbekannte Kapazität ist.

Bei Kondensatoren mit üblichen Genauigkeiten von +/-20% bis Elektrolytkondensatoren von typisch +80%/-20%

Grüße Uwe

Hallo,

das ist natürlich sinnvoll. Je mehr man sich reinkniet umso komplizierter wird es. ;)

Vieleicht sollte ich den Satz fertigschreiben:

Bei Kondensatoren mit üblichen Genauigkeiten von +/-20% bis Elektrolytkondensatoren von typisch +80%/-20% ist eine “genaue” Messung der Kapazität sowieso wenig sinvoll. Eine grobe Abschätzung der Kapazität ist in den meisten (fast allen) Fällen ausreichend.

Grüße Uwe

umso komplizierter wird es

Wer es komplizierter mag, kann sich ja mal den Transistor und Komponenten Tester ansehen, der im Nachbarforum entwickelt wurde und jetzt zigtausende mal vom Chinamann, weltweit, für ne kleine Mark verschachert wird.
Eine geniale keine Kiste, kann ich jedem Bastler empfehlen!
https://www.mikrocontroller.net/articles/AVR-Transistortester
Ein Ebay Beispiel für genau den Tester(viele verschiedene es gibt)

Quellcode und Schaltplan liegen öffentlich aus.
Da kann man sich sicherlich viel abschauen.
Gerade auch die Kondensator Messung ist recht ausgefuchst.

Hallo,

ich sehe das noch etwas anders. Gerade weil die Kapazitäten in der Fertigung so streuen sollte man genauer messen können um selektieren zu können wenn man es benötigt.

So einen AVR Transistortester habe ich auch. Ist schon erstaunlich was die alles für Messfunktionen eingebaut haben. Alle Features kann man aber nur nutzen wenn man es selbst baut. Ich habe ein Fertigteil gekauft. Ich ziehe auch den Hut das die Entwickler das alles offen gelegt haben und ohne Ende Support leisten, wenn man den Thread verfolgt. Geld verdienen damit nur die Chinesen.

Vielen Dank für eure schnellen und zahlreichen Antworten! Ihr wart wirklich sehr hilfreich.

Momentan versuche ich die Schaltung um weitere Referenzwiderstände und einen Taster zu erweitern.

Ich kann irgendwie nicht verstehen, warum startTime kleiner als millis() ist.

startTime beginnt doch früher als millis(), wie kann es dann kleiner sein?

Vielen Dank für alles Grüße Joachim

millis() ist ein Zähler, der die Millisekunden seit dem Start des Prozessors zählt. Der wird also immer größer, bis er überlauft und wieder bei 0 beginnt.

Gruß Tommy

unsigned long startTime;
unsigned long duration;
unsigned long stopTime;
  
[...]

void loop(){
  digitalWrite(aufladePin, HIGH);  
  startTime = millis();

  while(analogRead(analogPin) < 648){       
  }

  stopTime = millis();  
  duration= stopTime - startTime;
[...]

Dies ist ein Ausschnitt, aus meinem Sketch.
Zeitlich betrachtet müsste startTime doch während der gesamten while()-Schleife laufen und stopTime startet erst danach. Deshalb müsste startTime doch größer sein, oder nicht?
Und falls millis() seit Start des Prozessors zählt, müssten doch beide gleich groß sein.

Ich kann nicht verstehen, warum stopTime größer als startTime ist.
Irgendwie schaffe ich es nicht, die Lösung (im Sinne von wie es funktioniert) zu sehen.

Grüße und vielen Dank!

Ein Zähler ist etwas, was seinen Wert immer erhöht. (Lassen wir zum Verständnis den Überlauf erst mal weg). Also 1, 2, 3 …

  startTime = millis(); // <<<<***** hier ist millis() z.B. 43

  while(analogRead(analogPin) < 648){       // hier zählt millis() weiter
  }

  stopTime = millis();  // <<<<<*********** hier ist millis() z.B. 1234

Gruß Tommy

Vielen vielen Dank, Tommy!

Ich habe es endlich verstanden! Die Kommentare waren sehr hilfreich!

Ich bin euch allen zu großem Dank verpflichtet!

Grüße Joachim