PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C-Messung



wurzn
22.09.2005, 13:39
Habe vor die sich ändernde Kapazität eines Kondensators zu messen, etwa über den sich ändernden Strom oder Phasenwinkel und suche hierfür einen IC der mir, wenn möglich, über Ausgangspegel mitteilt ob C einen bestimmten Wert erreicht hat.

Gibr es IC's in dieser Art?

Manf
22.09.2005, 14:29
So ungefähr, immerhin genau für den Zweck gebaut.
Manfred

Der UTI von Smartec ist ein universeller Messinterface Baustein der Kapazitäten im Bereich von 0-2 oder 0-12pF auch bis 300pF misst. Er ist auch für viele weitere Anwendungen wie für Widerstandsmessbrücken einsetzbar. ...
https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=22772#22772

SprinterSB
22.09.2005, 14:42
Hab ich mal mit einem Atmel AT90S2313 gemach, da reicht ein analog-Komparator aus. Die 3 Messbereiche reichen von 1pF bis ca 1µF.
Und das geht so (Die zu messende Kapazität ist C1)

C1 wird über R4 auf Vcc aufgeladen. Dazu wird AIN0 als OUT geschaltet und auf HIGH gelegt.
Ein paar ms warten.
AIN0 wird als hochohmiger IN geschaltet und gleichzeitig
Timer1 wird auf 0 gesetzt, gestartet und die CapturCompare-Einheit des 2313 aktiviert. Input von CapCom ist der AnalogComparaton AIN0/AIN1.
C1 entlädt sich über R5, R6 oder R7.
Wenn der Wert an AIN0 (=C1+) unter den Wert an AIN1 (=Vcc/2) fällt, wird der Wert von Timer1 automatisch gesichert.
Die gemessene Zeit ist proportional zur Kapazität C.
Ist Timer1 übergelaufen, weil die Kapazität zu groß ist, dann wird via Reed-Relais ein anderer Widerstand zum Entladen gewählt. Gehe dann zu 1.
Umrechnen der Zeit in die Kapazität und anzeige am Display.

Das Messen wird per Taster ausgelöst.
Kurzer Tastendruck --> Messen
Langer Tastendruck --> Messen und Wert merken zum Kalibrieren des Messgerätes, weil Leitungen schon Kapazitäten im pF-Bereich haben. Das wird später wieder rausgerechnet, damit parasitäre Effekte nicht das Messergebnis verfälschen.

H.A.R.R.Y.
22.09.2005, 15:32
Wie bekommst Du den Wert eines 1pF Kondensators reproduzierbar hin? Bei meinen Aufbauten dieser Empfindlichkeitsstufe langt es meist schon mit der Hand bis auf 10cm ranzukommen - der Wert driftet dadurch um etliche pF weg! Kapazitive Näherungssensoren nutzen solche Effekte gezielt aus.

Gruß René

wurzn
27.09.2005, 13:15
Danke erstmal für die Mühe!
Es hat sich jedoch ein neues Problem ergeben.
Ich beabsichtige Regen kapazitiv festzustellen, hierzu benutze ich 2 Alubleche die nebeneinander angebracht werden C beträgt ca. 14pF.
Beim Berechnen der C Änderung bei aufgebrachtem Wasser (ca. 100mm³) erhalte ich eine Änderung von C in der Femto Gegend.
Die aktualisierte Frage lautet also wie lässt sich die C Änderung erhöhen?

Es wäre natürlich auch denkbar einen Kondensator mit Femto F zu bauen, jedoch wäre die Messung den wohl etwas empfindlich.

Manf
27.09.2005, 13:49
Es gibt es hygroskopische Materialien die die Luftfeuchte konzentrieren. So ist sie in Luftfeuchtesensoren leichter zu messen.

Bei Regen hat man das Problem ja eigentlich nicht. Man kann ja das Wasser aufsammeln das herunterfällt, in einen Gefäß, dass sich automatisch in einem Kippvorgang entleert.
(shishi odoshi) https://www.roboternetz.de/phpBB2/viewtopic.php?t=10940
Manfred

14.11.2005, 14:20
@Sprinter:
Kannst Du dein Programm mal hier zur V erfügung stellen, es muß ja nicht jeder das Rad neu erfinden ??

felack

SprinterSB
14.11.2005, 15:37
@Sprinter:
Kannst Du dein Programm mal hier zur V erfügung stellen, es muß ja nicht jeder das Rad neu erfinden ??

Jo, bei Gelegenheit kram ich das Zeugs mal wieder raus und poste die Quelle des entsprechenden Moduls. Ist in C für avr-gcc.


Wie bekommst Du den Wert eines 1pF Kondensators reproduzierbar hin? Bei meinen Aufbauten dieser Empfindlichkeitsstufe langt es meist schon mit der Hand bis auf 10cm ranzukommen - der Wert driftet dadurch um etliche pF weg!

Wie gesagt, der Messbereich fängt bei 1pF an, nicht die Messgenauigkeit. Dazu kommen noch Ungenauigkeiten durch Rundungsfehler. Der kleinste C, den ich hab, ist ein 6.8pF und da werden brav 7+-1 pF angezeigt. Sooo genau brauch ich's auch nicht. Für nen Feuchtigkeitssensor reichts aber IMHO nicht aus, da muss wohl ein Schwingkreis her?

Messung/Kalibrieren wird gestartet über Taster, und beim Start hab ich die Hand ja immer an der selben Stelle. Das hab ich nur mal probeweise gebaut, weil an vielen C die Größe nicht mehr lesbar ist. Ging dann ganz gut.

Als Anzeige ist ein VFD dran, das zur Messung abgeschaltet werden muss.

Die Bereichsumschaltung hab ich mit Reed gemacht. Mit Transen ging das nicht so wie geplant.

Messprobleme gibt es eher mit grösseren Kapazitäten, speziell bei Elkos. Die Ladung scheint langsam zu wachsen. Ein nicht-vollständiges Entladen kann dafür kaum verantwortlich sein, denn dann wäre der Effekt ab der dritten Messung nicht mehr zu beobachten. Liegt wohl an dielektrischer Absorption (memory-Effekt, auch 'recovery voltage').

SprinterSB
14.11.2005, 23:29
So, hier die versprochenen Code-Schnippsel.
Das ganze ist eher als Anregung gedacht und eigentlich nur Pseudo-Code, weil nicht alle Haeder dabei sind. Es sind nur die relevanten stellen, die für ne C-Messung gebraucht wurden. Der Code ist recht antik, undokumentiert und war auch nicht für's breite Publikum gedacht...

Das ganze drumrum hab ich weggelassen wie Taster abfragen, VFD-Routinen, etc

Laufen tut das auf einem AT90S2313 mit 8MHz Keramik.

Hier wird nur der C geladen und die Zeit in Ticks gemessen.


#include "capacity.h"
//#include "morse.h"

extern void ioinit();
extern void wait_10ms (const byte);

// Multiplikator:
// k = (ny * R * ln 2)^{-1}
// mit ny = 8MHz und R = 10k:

// k = 18pF / Inkrement

word measure_time (byte loadTime)
{
// Load capacity via AIN+ push-pull
SET (PORT_AIN_POS); MAKE_OUT (PORT_AIN_POS);
wait_10ms (loadTime);

// disable all interrupts
cli();

// stop timer1
TCCR1B = 0;

// enable AC (ACD = 0)
// AC Input Capture on -> connect to Input Capture of Timer/Counter1
// AC Interrupt on Falling Output Edge
ACSR = _BV(ACIC) | _BV (ACIS1);

// disconnect timer1 from output pin OC, no PWM
TCCR1A = 0;

// reset timer1 to 0
TCNT1 = 0;

// clear Timer1 Overflow and InputCapture Flags
TIFR = _BV (TOV1) | _BV (ICF1);

// start timer 1 at full speed
// no clear on compare match
// no noise cancel
// input capture edge = falling
TCCR1B = _BV (CS10);

// here we go!
// start discharging via external resistor
// AIN+ to high Z
MAKE_IN (PORT_AIN_POS); CLR (PORT_AIN_POS);

byte flag;

do
{
flag = TIFR & (_BV (TOV1) | _BV (ICF1));
} while (flag == 0);

if (flag & _BV (TOV1))
return 0xffff;

return ICR1;

// restore status of machine
// ioinit();

// morse (_O_);
// if (flag & _BV (ICF1))

// morse_dec (capture-4);
// morse (_FRAGE_);
}

Und hier etwas von dem Geklimper drumrum: Umrechnen in Kapazität, Messbereich auswählen, Kalibrierung, etc

#include "ports.h"
#include "main.h"
#include "util.h"
#include "taster.h"
#include "timer.h"

#include "vfd.h"
#include "capacity.h"

extern void ioinit();

static unsigned long mul_ww (word, word);
static void measureC (byte doCallibrate);
static void put_decimal (byte pos, word val, byte dot);
static word callibra[3] = {3, 3, 3};

enum
{
OHM_1M = 0,
OHM_47K = 1,
OHM_1K5 = 2
};


#define CONST_1M 687995. /* 0M993 */
#define CONST_47K 32140. /* 46K8 */
#define CONST_1K5 759.5 /* 1K49 */

// doCallibrate == 0: C bestimmen und anzeigen
// doCallibrate != 0: C bestimmen und callibrate[] damit besetzen
void measureC (byte doCallibrate)
{
word capval;

char dim;
char toobig;
byte ohm;
word const_R;
byte loadTime;
byte dot;

ioinit();
#if VFD
vfd_reset (1);
#endif
vfd_clear();
vfd.bright = 0;
vfd.cursor_on = 0;
vfd.cursor_blink = 0;
vfd_init ();

for (ohm = OHM_1M; ohm <= OHM_1K5; ohm++)
{
switch (ohm)
{
default:
case OHM_1M:
MAKE_IN (PORT_RELAIS1); CLR (PORT_RELAIS1);
MAKE_IN (PORT_RELAIS2); CLR (PORT_RELAIS2);
const_R = (word) (1.01*1e12*65536./(XTAL_PHI * CONST_1M)); // 1pF
loadTime = 20;
dot = 0;
dim = 'p';
break;
case OHM_47K:
MAKE_OUT (PORT_RELAIS1); SET (PORT_RELAIS1);
MAKE_IN (PORT_RELAIS2); CLR (PORT_RELAIS2);
const_R = (word) (1.01*1e10*65536./(XTAL_PHI * CONST_47K)); // 100pF
loadTime = 40;
dot = 1;
dim = 'n';
break;
case OHM_1K5:
MAKE_OUT (PORT_RELAIS1); SET (PORT_RELAIS1);
MAKE_OUT (PORT_RELAIS2); SET (PORT_RELAIS2);
const_R = (word) (1.17*1e9*65536./(XTAL_PHI * CONST_1K5)); // 1nF
loadTime = 150;
dot = 0;
dim = 'n';
break;
}

wait_10ms (10);

capval = measure_time (loadTime);

toobig = (0xffff == capval);

if (doCallibrate)
{
if (toobig)
break;
callibra[ohm] = capval-3;
}
else
{
if (!toobig)
{
capval -= callibra[ohm];
capval = (word) (mul_ww (const_R, capval) >> 16);
break;
}
}

ioinit();
}
ioinit();

vfd.bright = 4;
vfd_init ();

if (toobig)
{
static const prog_char STR_C_ZU_GROSS[] = "C zu groß";
if (doCallibrate)
{
vfd_pos_string_P (0x03, STR_C_ZU_GROSS);
vfd_pos_string_P (0x40, PSTR("zum kalibrieren"));
}
else
vfd_pos_string_P (0x43, STR_C_ZU_GROSS);

return;
}

if (doCallibrate)
{
vfd_pos_string_P (0x03, PSTR("Kalibriert"));
return;
}

if (ohm == OHM_1K5)
{
if (capval > 1000)
{
capval = (word) (mul_ww (capval, (word) (65536./10.)) >> 16);
dim = 0xe4; // my
dot = 2;
}
}
if (ohm == OHM_1M)
{
if (capval > 1000)
{
dim = 'n';
dot = 3;
}
}
vfd_pos_char (0x40, '0'+ohm);
put_decimal (0x48, capval, dot);
vfd_pos_char (0x4a, dim);
vfd_pos_char (0x4b, 'F');
}

void put_decimal (byte pos, word val, byte dot)
{
byte i = 0;
do
{
word r,d;
divmod10 (d, r, val);
vfd_pos_char (pos--, '0' + (byte) r);
val = d;
i++;
if (i == dot)
vfd_pos_char (pos--, '.');
} while (val);
}

#if 1
// return (a*b) >> 16
unsigned long mul_ww (word _a, word b)
{
unsigned long ab = 0;
unsigned long a = _a;

while (1)
{
if (b & 1)
ab += a;

b >>= 1;
if (b==0)
return ab;
a <<= 1;
}
}
#endif