Запис невеликої ємності

Я вимірюю ємність системи, використовуючи мультиметр, і виявив, що значення дуже мало (коливається від 50pF до 100 pF). Система динамічна, тому змінюється ємність з часом.

Тепер мені потрібно записати це значення в якийсь текстовий файл (наприклад, csv). Як я можу це зробити з Arduino? Якщо це опір, я міг би побудувати простий дільник напруги і відчути напругу за допомогою АЦП. Також C дуже маленький, я не зміг побудувати деякі вимірювальні схеми для C.

5
Це ємнісне зондування.
додано Автор roetnig, джерело
Скільки потрібно точності? Вам потрібно мати точну міру ємності, або виявлення стану поїздки було б достатньо? Яка ваша заявка?
додано Автор Arperum, джерело

6 Відповіді

The standard way to measure a resistance with an Arduino is to build a voltage divider by putting it in series with a known resistance. I have tried the same approach for measuring capacitances, and it turns out it works well in the 100 pF range! The circuit is like this:

  ┌───────────── Arduino digital output
  │
──┴── known
──┬── cap
  │
  ├───────────── Arduino analog input
  │
──┴── unknown
──┬── cap
  │
 GND

Єдиним висновком є ​​те, що ви повинні робити вимірювання відносно швидко, в іншому випадку слід вимірювати співвідношення опорів витоку. Ось протокол вимірювання:

  1. Set both pins to OUPUT LOW in order to discharge both capacitors.
  2. Delay for one or two CPU cycles to make sure they are fully discharged.
  3. Set the analog input pin to INPUT mode: this will make it high impedance and isolate the node connected to it.
  4. Set the digital output to HIGH: this will charge the two capacitors in series to 5 V.
  5. Delay for one or two CPU cycles for the voltage to stabilize.
  6. Take an analog reading.

Тепер ви можете отримати ємність від читання, використовуючи те ж саме Формула, яку ви використовуєте з резисторами, тільки з імпедансами (або просто 1/C) замість опорів:

C_unknown = C_ref × (1024 − reading) ÷ reading;

Таку ж формулу можна отримати, вважаючи, що вузол з'єднаний до аналогового входу, що включає в себе одну пластину кожного конденсатора, має нульовий чистий заряд.

Декілька речей, які варто відзначити:

  • You will get the best resolution by choosing the reference capacitance close to the one you want to measure.
  • The delays are not actually needed: as the capacitors charge and discharge very fast, a single CPU cycle is about 24 time constants.
  • If you were to measure large capacitances (several nanofarads) with this setup, you would want protective resistors in series with the Arduino pins, but then the delays become mandatory. In the 100 pF range I would not worry about the in-rush currents.
  • If the delay in step 5 is too long, your measurement will be affected by the leakage of the caps and the analog input pin.
  • You need not worry about the 14 pF cap on the sample and hold circuit: it will slightly affect the very first measurement but, once that cap is charged, subsequent measurement will not be affected as long as the unknown cap does not change to much between consecutive measurements. You do need to calibrate out the stray capacitance of the pin and probes.
2
додано

Вимірювання величини малої ємності за допомогою постійної оцінки RC по суті вимагає точного вимірювання часу. Чіпи ATmega мають таймер TCNT1 , який можна запрограмувати для збільшення кожного тактового циклу, і може бути зупинено компаратором, використовуючи біт ACIC у реєстрі ACSR . Запуск лічильника на частоті 16 МГц дасть вам роздільну здатність 62,5 нс, що достатньо для вимірювання потужності в діапазоні пікофарад. Тут приклад коду, який використовує це техніка вимірювання.

AnalogRead is about 1000 times slower, so you'll be limited to nF range if you use it.

Зверніть увагу, що ви повинні калібрувати вашу систему при вимірюванні такої малої ємності. Це робиться за допомогою вимірювання з підключеними зондами , але без цільової системи. Ви будете потім відняти це значення ємності (зазвичай 20-50 пФ, залежно від зондів, які ви використовуєте) від ваших сировинних вимірювань, щоб отримати ємність вашої системи поодинці.

2
додано

Для ємності, як мало, як pF, метод постійного часу RC дає брудні результати на платі Arduino.

Ви можете використовувати Arduino штифти побудовані в невеликій ємності (яка знаходиться в Pf себе), щоб створити "ємність дільник" ланцюга і розрахувати так само, як ви б опір від дільника напруги ланцюга.

See this excellent post by Nethercott for reference Arduino capacitance meter

1
додано
Дякую вам :-) Я думаю, ви маєте рацію, хоча я ніколи не мав можливості розтягнути цей метод до його меж. З мого досвіду з нею, я був в змозі виробляти задовільні результати, використовуючи плату Arduino Uno і 15 см довго регулярні перемички дроту в повсякденному оточенні.
додано Автор christoff, джерело
Приємний пошук, + 1! Я здивований, наскільки точно цей метод, здається, з урахуванням його на основі паразитних властивостей PIN-коду. Хоча, я припускаю, що це добре працює тільки з хорошим захистом EMI або в умовах, вільних від EMI.
додано Автор nreich, джерело

(коливається від 50 до 100 пФ).

a few ways for such small values -> assuming you can really read it like a capacitor.

1) form a lc tank and measure its frequency -> most effective in measuring small value capacitance. but needs precision inductor/calibration, and is subject to parasitics.

2) заряджати/розряджати його через CCS: і вимірювати час. Найпростіший, як ccs може бути сформований через великий резистор. не ефективний при дійсно малій ємності;

3) charge transfer: using the capacitance of the adc. very effective against small capacitance: < 10x of adc capacitance. needs calibration.

у кожного є свої проблеми.

1
додано
Що таке CCS ?
додано Автор nreich, джерело

Оскільки ємність, що підлягає вимірюванню, значно нижче 1 нФ (50-100 пФ), ви зіткнетеся з серйозними проблемами, намагаючись виміряти її з АЦП Arduino через його вхідну ємність (14 пФ відповідно до таблиці). Додайте блукаючі ємності проводів, заголовків і самої плати Arduino, і ви легко вийде з вхідною ємністю 25 пФ, яка знаходиться в тому ж порядку, що й ви намагаєтеся виміряти (= ДУЖЕ ПОРУЧЕННЯ).

Що ж робити? Ну, основні варіанти це ...

Використовуйте зовнішню схему вимірювання

Це означатиме включення активних пристроїв (операційні підсилювачі, компаратори, таймери ...) і точні пасивні компоненти. Істинне рішення на основі HW.

Точність вимірювання в цьому випадку була б повністю залежати від конструкції (топологія та вибір компонентів) зовнішнього контуру. Схема буде забезпечувати або аналогову напругу, або сигнал, частота якого може бути виміряна Arduino без додаткових значних помилок.

Приклад з використанням таймера 555 (необхідний додатковий компенсаційний конденсатор на 4 пФ між OUT і TH для підвищення точності):

555 timer capacitance meter

Frequency vs capacitance

Source: Use Analog Techniques To Measure Capacitance In Capacitive Sensors, an article by Martin Tomasz published in Electronic Design.

Подумайте про зовнішній контур як про «датчик» або про схему підготовки сигналу для «датчика» (ємність, яку потрібно виміряти). Насправді, динамічна ємність, яку ви намагаєтеся виміряти, ймовірно, надходить від датчика (вологість, вологість?), Чи не так?

Підключіть конденсатор безпосередньо до аналогових контактів Uno і калібруйте показання

Це може здатися дивовижним, але чимось простим, як це працює (за рахунок точності, звичайно):

Uno as capacitance meter

Як це? Тому що проблема вхідної ємності, яку ми виявили на початку, достатньо велика, щоб серйозно пошкодити точність, але не робить вимірювання абсолютно неможливим. Таким чином, ми можемо відкалібрувати цей ефект і все ще мати дійсний (хоча і з пониженою точністю) вимірювач в цільовому діапазоні (50-100 пФ).

Калібрування виконується через деякі типові значення за замовчуванням у наступному ескізі Arduino (джерело тут з braulio777). Для більшої точності ви повинні калібрувати значення IN_STRAY_CAP_TO_GND і R_PULLUP в ескізі, порівнюючи вимірювання деяких конденсаторів з їх вже відомими значеннями ємності (за умови, що це можна зробити).

//Digital Capacitance Meter
//Measuring from 0.000pF to 1000uF

#include 
LiquidCrystal lcd(11, 9, 5, 4, 3, 2);
const int OUT_PIN = A4;
const int IN_PIN = A0;
const float IN_STRAY_CAP_TO_GND = 24.48;
const float IN_CAP_TO_GND  = IN_STRAY_CAP_TO_GND;
const float R_PULLUP = 34.8;  
const int MAX_ADC_VALUE = 1023;

void setup()
{
  pinMode(OUT_PIN, OUTPUT);
  pinMode(IN_PIN, OUTPUT);
  lcd.begin(16, 2);
  }

void loop()
{
    pinMode(IN_PIN, INPUT);
    digitalWrite(OUT_PIN, HIGH);
    int val = analogRead(IN_PIN);
    digitalWrite(OUT_PIN, LOW);

    if (val < 1000)
    {
      pinMode(IN_PIN, OUTPUT);

      float capacitance = (float)val * IN_CAP_TO_GND/(float)(MAX_ADC_VALUE - val);

      lcd.setCursor(0,0);
      lcd.print("Capacitance = ");
      lcd.setCursor(0,1);
      lcd.print("                ");
      lcd.setCursor(0,1);
      lcd.print(capacitance, 3);// for the best precision
      lcd.print("pF ");

    }

    else
    {
      pinMode(IN_PIN, OUTPUT);
      delay(1);
      pinMode(OUT_PIN, INPUT_PULLUP);
      unsigned long u1 = micros();
      unsigned long t;
      int digVal;

      do
      {
        digVal = digitalRead(OUT_PIN);
        unsigned long u2 = micros();
        t = u2 > u1 ? u2 - u1 : u1 - u2;
      } 

      while ((digVal < 1) && (t < 400000L));

      pinMode(OUT_PIN, INPUT);  
      val = analogRead(OUT_PIN);
      digitalWrite(IN_PIN, HIGH);
      int dischargeTime = (int)(t/1000L) * 5;
      delay(dischargeTime);   
      pinMode(OUT_PIN, OUTPUT);  
      digitalWrite(OUT_PIN, LOW);
      digitalWrite(IN_PIN, LOW);

      float capacitance = -(float)t/R_PULLUP
                             /log(1.0 - (float)val/(float)MAX_ADC_VALUE);

      lcd.setCursor(0,0);
      lcd.print("Capacitance = ");
      if (capacitance > 1000.0)
      {
        lcd.setCursor(0,1);
        lcd.print("                ");
        lcd.setCursor(0,1);
        lcd.print(capacitance/1000.0, 2);
        lcd.print("uF ");

      }

      else
      {
        lcd.setCursor(0,1);
        lcd.print("                ");
        lcd.setCursor(0,1);
        lcd.print(capacitance, 2);
        lcd.print("nF ");

      } 

    while (millis() % 1000 != 0);
}
    }

Наведений вище приклад коду виводить виміряні значення на РК-дисплей. Найкращим варіантом для вашого призначення є запис даних на зовнішню SD-карту.

Disclosure: I have not tested the code above myself.

1
додано

Кожен вимірювач ємності Arduino спирається на властивість конденсаторних контурів резистора (RC) - постійна часу. Постійна часу схеми RC визначається як час, необхідний для того, щоб напруга на конденсаторі досягала 63,2% від її напруги при повному заряді. Більш великі конденсатори заряджаються більше часу, а тому створюватимуть більші константи часу. Ємність в RC-ланцюзі пов'язана з постійною часу за рівнянням:

TC = R x C

where TC = time constant in seconds R = resistance in ohms C = capacitance in farads

Перестановка рівняння для вирішення для ємності дає:

C = TC/R

schematic

simulate this circuit – Schematic created using CircuitLab

Example: 1 megohm * 1 microfarad = 1 second enter image description here

Кожен вимірювач ємності має RC схему з відомими значеннями резисторів і невідомим значенням конденсатора. Arduino буде вимірювати напругу на конденсаторі і реєструвати час, необхідний для досягнення 63,2% його напруги, коли вона повністю заряджена (постійна часу). Оскільки значення опору вже відомо, ми можемо використовувати формулу вище в програмі, яка буде обчислювати невідомі ємності.

Оскільки ваш ємність занадто малий в діапазоні Піко Фарад, так що ви можете безпосередньо виміряти ємність через аналоговий PIN-код, як цей спосіб ... Schematic Ви сказали, що ваш конденсатор динамічний в природі, тому вам доведеться приймати принаймні 10 значень і середню, щоб отримати точне значення.

Код для вимірювання Низька ємність в діапазоні pF

const int OUT_PIN = A5;
const int IN_PIN = A0;
const float IN_STRAY_CAP_TO_GND = 24.48;
const float IN_CAP_TO_GND  = IN_STRAY_CAP_TO_GND;
const float R_PULLUP = 34.8;  
const int MAX_ADC_VALUE = 1023;

void setup()
{
  pinMode(OUT_PIN, OUTPUT);
  pinMode(IN_PIN, OUTPUT);
  Serial.begin(9600);
}

void loop()
{
    pinMode(IN_PIN, INPUT);
    digitalWrite(OUT_PIN, HIGH);
    int val = analogRead(IN_PIN);
    digitalWrite(OUT_PIN, LOW);

    if (val < 1000)
    {
      pinMode(IN_PIN, OUTPUT);

      float capacitance = (float)val * IN_CAP_TO_GND/(float)(MAX_ADC_VALUE - val);

      Serial.print(F("Capacitance Value = "));
      Serial.print(capacitance, 3);
      Serial.print(F(" pF ("));
      Serial.print(val);
      Serial.println(F(") "));
    }
    else
    {
      pinMode(IN_PIN, OUTPUT);
      delay(1);
      pinMode(OUT_PIN, INPUT_PULLUP);
      unsigned long u1 = micros();
      unsigned long t;
      int digVal;

      do
      {
        digVal = digitalRead(OUT_PIN);
        unsigned long u2 = micros();
        t = u2 > u1 ? u2 - u1 : u1 - u2;
      } while ((digVal < 1) && (t < 400000L));

      pinMode(OUT_PIN, INPUT);  
      val = analogRead(OUT_PIN);
      digitalWrite(IN_PIN, HIGH);
      int dischargeTime = (int)(t/1000L) * 5;
      delay(dischargeTime);   
      pinMode(OUT_PIN, OUTPUT);  
      digitalWrite(OUT_PIN, LOW);
      digitalWrite(IN_PIN, LOW);

      float capacitance = -(float)t/R_PULLUP
                             /log(1.0 - (float)val/(float)MAX_ADC_VALUE);

      Serial.print(F("Capacitance Value = "));
      if (capacitance > 1000.0)
      {
        Serial.print(capacitance/1000.0, 2);
        Serial.print(F(" uF"));
      }
      else
      {
        Serial.print(capacitance, 2);
        Serial.print(F(" nF"));
      }

      Serial.print(F(" ("));
      Serial.print(digVal == 1 ? F("Normal") : F("HighVal"));
      Serial.print(F(", t= "));
      Serial.print(t);
      Serial.print(F(" us, ADC= "));
      Serial.print(val);
      Serial.println(F(")"));
    }
    while (millis() % 1000 != 0)
      ;    
}
1
додано
-1: Цей метод не дуже підходить для таких малих ємностей: вам знадобиться величезне значення опору, інакше константа часу буде занадто короткою для хорошого вимірювання. Якщо ви хочете виконати вимірювання постійної постійної частоти, вам слід скористатися методом, описаним у відповіді Дмитра Григор'єва.
додано Автор Sprogz, джерело
Ти дав «ідею», а потім шматок коду, який робить щось зовсім інше, ніж ця ідея. Якщо ви написали цей код, чому б вам не пояснити, що він насправді робить? Якщо ні, то чому ви не віддаєте належне оригінальному автору?
додано Автор Sprogz, джерело
А як щодо ємностей навантаження штифтів arduino?
додано Автор Arperum, джерело
За даними ATmega328 це близько 14 пФ. Занадто близький до діапазону вимірювань для комфорту. Плюс будь-яка паразитна ємність за рахунок проводів і до дошки Uno і заголовків.
додано Автор Arperum, джерело
Так, ви праві. Але я спробував це і дав мені хороший результат не настільки точний і точний, але задовільний. Остудивши чувака, я дав йому узагальнену ідею не для вирішення його проблеми.
додано Автор Inky1980, джерело