Forum: Mikrocontroller und Digitale Elektronik Kapazität messen, 400-700pF


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Hugo P. (portisch)


Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich möchte eine Wassersäule über die Kapazität bestimmen.
Ich habe ein Rohr (Durchmesser 20mm) das mir den Wasserstand im Pool 
anzeigt.

Nun habe ich am Rohr außen beidseitig ein Kupferband angebracht und 
diese Werte gemessen:

Rohr leer (0mm Wassersäule): ~400pF
Rohr voll (1500mm Wassersäule): ~610pF

(Gemessen mit Fluke)

Nun bin ich auf der Suche wie man das am besten und genau messen kann.

Die Messung befindet sich im Keller im Technikraum, also sollte die 
Luftfeuchtigkeit und Temperatur "fast" konstant bleiben.

Jetzt habe ich erste Versuche mit einem Atmega zur Kapazitätmessung 
gemacht:
Beitrag "Re: Ladekurve Kondensator, Analog Comparator, ACI"
Diese scheint mir aber zu ungenau. Umgerechnet komme ich auf eine 
Toleranz von +-15mm.

Nun will ich den Versuch wagen den Kondensator über einen Schwingkreis 
zu messen. Dazu habe ich den AD9533 entdeckt.


Bei einer Frequenz von 1kHz sollten ca. diese Werte rauskommen:
400pF: Xc == 397887,4 Ohm -> 0mm
610pF: Xc == 260909,7 Ohm -> 1500mm

Die echte Kapazität interessiert mich eigentlich nicht.
Ich brauche nur diese Werte um die Höhe rausrechnen zu können.
Die Kapazität ist ja linear proportional zur Wassersäule.

Also wäre das eine Differenz von 136977,6 Ohm was bei 1500mm Wassersäule 
91,318 Ohm/mm bedeutet.

Das könnte doch eigentlich recht gut funktionieren, oder?
Ich brauche vom AD9533 jedoch nur eine Messung mit konstanter Frequenz - 
kein Sweep. Gibt es da Alternativen?

Oder kann das auch mit einem NE555 und mit Input Capture des AVRs 
funktionieren um eine Auflösung von +-1-2mm zu bekommen?

Als Ausgang mache ich dann ein Analogsignal 0-5V was 0..1500mm 
entsprechen soll.

von Falk B. (falk)


Bewertung
0 lesenswert
nicht lesenswert
@Hugo Portisch (portisch)

>Rohr leer (0mm Wassersäule): ~400pF
>Rohr voll (1500mm Wassersäule): ~610pF

Geht so.

>Nun bin ich auf der Suche wie man das am besten und genau messen kann.

RC-Oszillator mit NE7555 oder TLC555, das ist die CMOS-Version des 
NE555.

>Jetzt habe ich erste Versuche mit einem Atmega zur Kapazitätmessung
>gemacht:
>Beitrag "Re: Ladekurve Kondensator, Analog Comparator, ACI"
>Diese scheint mir aber zu ungenau.

Naja, man muss es hat besser umsetzen. Im Prinzip geht das schon besser.

>Die echte Kapazität interessiert mich eigentlich nicht.

Eben. Also baut man es auf und kalibriert danach. Fertig.

>Also wäre das eine Differenz von 136977,6 Ohm was bei 1500mm Wassersäule
>91,318 Ohm/mm bedeutet.

Man nutzt die Kapazität zur Frequenzerzeugung. Ob nun ein RC oder 
LC-Oszillator ist egal.

>Oder kann das auch mit einem NE555 und mit Input Capture des AVRs
>funktionieren um eine Auflösung von +-1-2mm zu bekommen?

Kann sein. Aber man macht da eine Frequenzmessung, die ist genauer. 
Schließlich hast du alle Zeit der Welt.

>Als Ausgang mache ich dann ein Analogsignal 0-5V was 0..1500mm
>entsprechen soll.

Und wozu? Wenn du den Wert im AVR digital hast, wandelt den man doch 
nicht wieder in analog!

von Der Andere (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hugo P. schrieb:
> Nun habe ich am Rohr außen beidseitig ein Kupferband angebracht und
> diese Werte gemessen:

Wie hast du das Band aufgebracht?
Kannst du noch jeweils 2 Bänder daneben machen? Damit erhöht sich die 
Kapazität und du kannst ggf. genauer messen.

von foobar (Gast)


Bewertung
0 lesenswert
nicht lesenswert
BigClive hatte mal nen Wasserstandsensor einer Waschmaschine 
auseinandergenommen. Die benutzen ne Spule, nen "schwimmenden" Kern und 
einen 74HC4060 (Oszillator mit Teiler). Der Oszillator schwingt bei ca 
200kHz und wird dann auf die Ausgangsfrequenz von 8-13Hz runtergeteilt.

https://www.youtube.com/watch?v=O-0KGbd91_I

von Patrick B. (p51d)


Bewertung
0 lesenswert
nicht lesenswert
Wie währe es mit einer kapazitiven Messbrücke? Diese mit "genauen" NPO 
Kondensatoren bestücken und die Brückenspannung messen. Dann etwas 
rechnen und schon hast du einen sehr genauen Wert. Kannst das ganze 
durch eichen und Verstärker natürlich noch verbessern...

von Gerhard D. (gedu)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,
zur Wandfeuchtmessung habe ich mir sowas gebaut:
Mit einem ATMEGA48 wird ein astabiler Multivibrator programmiert, der 
über die Input Capture Funktion des Timers1 und den analogen Komparator 
die Periode(256 Perioden gemittelt) des AMV misst. Als stabiler 
Nullpunkt wird ein 100pF Kondensator(Syroflex o. ä.) fest an den Eingang 
geschaltet.
Die Auflösung ist besser als 0,1pF. Der Meßbereich ca. 0 ... 18000pF, 
kann durch Zählen der Überläufe von Timer1 erweitert werden.

Gerhard

: Bearbeitet durch User
von Alex E. (tecnologic) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Hi

ich habe eine ähnliche Anwendung, ich nutze dafür den FDC1004 siehe 
folgende AppNote:

http://www.ti.com/lit/ug/tidu736a/tidu736a.pdf

Gruß

Alex

von Info (Gast)


Bewertung
0 lesenswert
nicht lesenswert

von Harald (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Das sehr erfolgreiche Projekt des Transistortesters hat auch eine 
Kapazitätsmessung im Programm, die verblüffend genau ist. Die solltest 
du dir anschauen und ggf. übernehmen.

Artikel:

https://www.mikrocontroller.net/articles/AVR_Transistortester

Thread (lang & unübersichtlich):

Beitrag "Transistortester AVR"

von Hugo P. (portisch)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Also ich habe nun folgendes ausprobiert:
Oszilator mit NE555. Über den Kondensator wird dann die Frequenz 
gemessen.
Das ganze war wegen dem Jitter des NE555 zu unstabil.

Dann habe ich mir das mit dem 74HC4060 wie foobar vorgeschlagen hat 
angesehen.
Super Sache!

Ich greife das Signal bei Q11 ab was um die 450Hz liegt. Das Signal 
sollte also 450Hz * 2048 == 921600Hz haben.

Nun habe ich einen Laboraufbau mit zwei Flaschen gemacht die per 
Schlauch verbunden sind. Dann habe ich eine Aufnahme mit "virtuell" 0mm 
gemacht und dann 40mm:
mm  digits
0  27071
40  30335

Dadurch komm ich auf eine Auflösung von 81,6 Digits/mm was 
~0,012mm/Digit bedeutet.

Also habe ich dann Gain und Offset bestimmt und kann die Höhen von den 
Digits rausrechnen.

Dann habe ich aber eine Kurve aufgenommen wo ich nicht rausfinde wo der 
Fehler liegt. Man sieht das von 0mm auf 40mm gefüllt wird. Danach sollte 
es auf 2,5mm und 0mm runtergehen. Es bleibt aber bei 5,1mm und 2,9mm 
stehen!?

Warum kommt es nicht mehr auf 2,5 und 0mm?
Oder hängt das mit Oberflächenspannung usw. zusammen?

Werde noch einen Versuch machen wo ich eine Definierte Menge Wasser 
entferne und hinzufüge.

Wie wirkt es sich aus wie "schlampig" die Kupferbänder geklebt sind?
Sollte eigentlich nur die Linearität beeinflussen aber nicht den 
Absolutwert, oder?

Oder ist meine Messfrequenz zu hoch? Was wäre ein "brauchbarer" Wert, 
100kHz?

EDIT:
Habe gerade nochmal von 0mm auf 40mm getestet. Das Ergebnis liegt bei 
30313 Digits was 39,7mm entspricht... Warum nicht 40mm?

Verwendet wurde der Source von hier:
https://www.mikrocontroller.net/articles/High-Speed_capture_mit_ATmega_Timer

Abgeändert schaut er nun so aus und macht 5*100 Messungen nur auf die 
Positive Flanke:
1
/*
2
 * Created: 09.04.2018 11:06:58
3
 */ 
4
5
#include <avr/io.h>
6
#include <util/delay.h>
7
#include <avr/wdt.h>
8
#include <avr/interrupt.h>
9
#include "uart/uart.h"
10
#define BAUD  9600L
11
12
13
uint16_t single_capture[100];
14
uint16_t captures[5];
15
uint32_t result;
16
17
////////////////////////////////////////////////////////////////////////////////
18
// Helper macros
19
////////////////////////////////////////////////////////////////////////////////
20
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) // clear bit 
21
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))  // set bit
22
23
void io_init(void)
24
{
25
  // all pins output
26
  DDRB = 0xFF;
27
  DDRC = 0xFF;
28
  DDRD = 0xFF;
29
  
30
  PORTB = 0;
31
  PORTC = 0;
32
  PORTD = 0;
33
    
34
  /* disable pull up on analog channels */  
35
  cbi(DDRB, PB0);      // switch to input
36
  PORTB &= ~(1 << PB0);  // no Pull-up
37
}
38
39
// Wait for a signal on pin ICP1 and store the captured time values in the array 'captureData'
40
uint16_t startCapture(void)
41
{
42
  register uint8_t ices1_val = _BV(ICES1) | _BV(CS10); 
43
  register uint8_t tccr1b = TCCR1B | ices1_val; // trigger on rising edge
44
  TCCR1B = tccr1b;
45
  OCR1A = TCNT1 - 1;
46
  TIFR1 = _BV(ICF1) | _BV(OCF1A) | _BV(TOV1); // clear all timer flags
47
  register uint16_t prevVal = 0;
48
  register uint8_t tifr; // cache the result of reading TIFR1 (masked with ICF1 and OCF1A)
49
  int i;
50
51
  for(i = 0; i < sizeof(single_capture); i++)
52
  {
53
    // wait for edge or overflow (output compare match)
54
    while(! (tifr = (TIFR1 & (_BV(ICF1) | _BV(OCF1A)))));
55
    
56
    uint16_t val = ICR1;
57
    OCR1A = val; // timeout based on previous trigger time
58
59
    TIFR1 = _BV(ICF1) | _BV(OCF1A); // clear input capture and output compare flag bit
60
61
    uint16_t diffVal = val - prevVal;
62
    single_capture[i] = diffVal;
63
64
    prevVal = val;
65
  }
66
 
67
  // the first array entry contains only the starting time and no time
68
  // difference, therefore it is no longer needed and will be removed 
69
  uint32_t average = 0;
70
  for(i = 1; i < sizeof(single_capture); i++)
71
    average  += single_capture[i];
72
  
73
  average /= sizeof(single_capture) - 1;
74
 
75
  return (uint16_t)average;
76
}
77
78
int main(void)
79
{
80
  static char buff[6];
81
  
82
  cli();
83
  MCUSR = 0;
84
  wdt_disable();
85
  
86
  io_init();
87
  
88
  // initialize uart  
89
  uart_init((UART_BAUD_SELECT((BAUD),F_CPU)));
90
  
91
    while(1)
92
    {
93
        //TODO:: Please write your application code           
94
    static int i;
95
    
96
    for (i = 0 ; i < sizeof(captures); i++)
97
      captures[i] = startCapture();
98
    
99
    result = 0;
100
    for (i = 0 ; i < sizeof(captures); i++)
101
      result += captures[i];
102
103
    result /= sizeof(captures);
104
    
105
    sprintf(buff, "%05u", (uint16_t)result);
106
    buff[sizeof(buff) - 1] = '\n';
107
    
108
    for (i = 0; i < sizeof(buff); i++)
109
      uart_putc(buff[i]);    
110
    }
111
}

: Bearbeitet durch User
von Andre R. (ltisystem)


Bewertung
0 lesenswert
nicht lesenswert

von DerDaDrüben (Gast)


Bewertung
0 lesenswert
nicht lesenswert

von Harald W. (wilhelms)


Bewertung
0 lesenswert
nicht lesenswert
foobar schrieb:

> BigClive hatte mal nen Wasserstandsensor einer Waschmaschine
> auseinandergenommen. Die benutzen ne Spule, nen "schwimmenden" Kern und
> einen 74HC4060 (Oszillator mit Teiler). Der Oszillator schwingt bei ca
> 200kHz und wird dann auf die Ausgangsfrequenz von 8-13Hz runtergeteilt.

In den achtziger Jahren gab es mal viele Schaltungsvorschläge für
kapazitive Feuchtigkeitssensoren von Phillips. Die arbeiten in
einem ähnlichen Kapazitätsbereich wie der Sensor vom TE, sodas
man diese Auswerteschaltung, die man sicher auch im Netz finden
wird, ohne grössere Änderungen übernehmen könnte. Die Anzeige
hat man damals typischerweise per Zeigerinstrument gemacht.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.