]> git.the-white-hart.net Git - atmega/cap_meter.git/commitdiff
Initial commit
authorrs <>
Thu, 31 Dec 2020 02:34:22 +0000 (20:34 -0600)
committerrs <>
Thu, 31 Dec 2020 02:34:22 +0000 (20:34 -0600)
cap_meter.ino [new file with mode: 0644]

diff --git a/cap_meter.ino b/cap_meter.ino
new file mode 100644 (file)
index 0000000..c4eed10
--- /dev/null
@@ -0,0 +1,257 @@
+#include <Wire.h>
+#include <Adafruit_GFX.h>
+#include "Adafruit_LEDBackpack.h"
+
+
+//------------------------------------------------------------------------------
+// Measurement
+
+
+const int ADC_MAX = 1023;
+
+const int PIN_SENSE = A2;
+const int PIN_SOURCE = A0;
+
+const float Ccal = 1.75e-12;  // Measured cap when no test cap is present
+const float Cin = 24.48e-12;  // Input capacitance of the ADC
+const float Rpull = 34.8e3;   // Digital input pull-up resistance
+
+
+void measurement_init(void)
+{
+  pinMode(PIN_SOURCE, OUTPUT);
+  pinMode(PIN_SENSE, OUTPUT);
+  digitalWrite(PIN_SOURCE, LOW);
+  digitalWrite(PIN_SENSE, LOW);
+}
+
+
+float measurement_read(void)
+{
+  // Make extra sure the capacitor is discharged
+  pinMode(PIN_SENSE, OUTPUT);
+  pinMode(PIN_SOURCE, OUTPUT);
+  digitalWrite(PIN_SENSE, LOW);
+  digitalWrite(PIN_SOURCE, LOW);
+  delay(1);
+
+  pinMode(PIN_SENSE, INPUT);
+  digitalWrite(PIN_SOURCE, HIGH);
+  int val = analogRead(PIN_SENSE);
+  digitalWrite(PIN_SOURCE, LOW);
+
+  if (val < 1000)
+  {
+    // The capacitor to measure was small enough that it gave a low enough
+    // voltage to be resolvable when forming a voltage divider with the input
+    // capacitance of the sense pin.  Use the voltage divider formula to infer
+    // the capacitance.
+    //
+    //       Cin     (V)        (Vs)
+    // GND----||-------          -------------Vcc
+    //                |          |
+    // ...............|..........|...............
+    //       PIN_SENSE|          |PIN_SOURCE
+    //                |          |
+    //                -----||-----
+    //                     C
+    //                    (Vc)
+    //
+    // Vc * C = V * Cin  and  Vc = Vs - V
+    //
+    //     V * Cin
+    // C = -------
+    //     Vs - V
+
+    return (float)val * Cin / (float)(ADC_MAX - val) - Ccal;
+  }
+  else
+  {
+    // The capacitor to measure dominated the voltage divider too much to give a
+    // useful measurement, so measure its time constant against the internal
+    // input pullup resistor value.
+    //
+    //                               Rpull
+    // GND-------------          -----^^^-----Vcc
+    //                |          |
+    // ...............|..........|...............
+    //       PIN_SENSE|          |PIN_SOURCE
+    //                |          |
+    //                -----||-----
+    //                     C
+    //                    (Vc)
+    //
+
+    unsigned long t_start;
+    unsigned long t_end;
+    unsigned long t_charge;
+    int dig_val;
+
+    // Ground one pin and connect the pullup to Vcc on the other
+    pinMode(PIN_SENSE, OUTPUT);
+    delay(1);
+    pinMode(PIN_SOURCE, INPUT_PULLUP);
+
+    // Wait for the pulled-up input to read 1, when the capacitor is charged
+    t_start = micros();
+    while (!digitalRead(PIN_SOURCE));
+    t_end = micros();
+    t_charge = t_end > t_start ? t_end - t_start : t_start - t_end;
+
+    // Read the voltage the capacitor was charged up to
+    pinMode(PIN_SOURCE, INPUT);
+    val = analogRead(PIN_SOURCE);
+
+    // Discharge the capacitor
+    digitalWrite(PIN_SENSE, HIGH);
+    delay(t_charge / 1000 * 5);
+
+    // Reset the pin states
+    pinMode(PIN_SOURCE, OUTPUT);
+    digitalWrite(PIN_SOURCE, LOW);
+    digitalWrite(PIN_SENSE, LOW);
+
+    return -(float)t_charge * 1e-6 / Rpull / log(1.0 - (float)val / (float)ADC_MAX);
+  }
+}
+
+
+//------------------------------------------------------------------------------
+// Display
+
+
+Adafruit_7segment segs = Adafruit_7segment();
+
+// Pin assignments for unit indicator LEDs
+const int LED_L = 2;
+const int LED_P = 3;
+const int LED_N = 4;
+const int LED_U = 7;
+const int LED_H = 8;
+
+// Values for edges of each unit range
+const float L_P_BOUND = 1.0e-12;
+const float P_N_BOUND = 1.0e-9;
+const float N_U_BOUND = 1.0e-6;
+const float U_H_BOUND = 1.0e-3;
+
+const float INF = 1.0 / 0.0;
+
+
+void display_init(void)
+{
+  pinMode(LED_L, OUTPUT);
+  pinMode(LED_P, OUTPUT);
+  pinMode(LED_N, OUTPUT);
+  pinMode(LED_U, OUTPUT);
+  pinMode(LED_H, OUTPUT);
+  digitalWrite(LED_L, HIGH);
+  digitalWrite(LED_P, HIGH);
+  digitalWrite(LED_N, HIGH);
+  digitalWrite(LED_U, HIGH);
+  digitalWrite(LED_H, HIGH);
+  segs.begin(0x70);
+}
+
+
+void display_show(float value)
+{
+  if (value < L_P_BOUND)
+  {
+    digitalWrite(LED_L, LOW);
+    digitalWrite(LED_P, HIGH);
+    digitalWrite(LED_N, HIGH);
+    digitalWrite(LED_U, HIGH);
+    digitalWrite(LED_H, HIGH);
+    value = -INF;
+  }
+  else if (value < P_N_BOUND)
+  {
+    digitalWrite(LED_L, HIGH);
+    digitalWrite(LED_P, LOW);
+    digitalWrite(LED_N, HIGH);
+    digitalWrite(LED_U, HIGH);
+    digitalWrite(LED_H, HIGH);
+    value *= 1.0e12;
+  }
+  else if (value < N_U_BOUND)
+  {
+    digitalWrite(LED_L, HIGH);
+    digitalWrite(LED_P, HIGH);
+    digitalWrite(LED_N, LOW);
+    digitalWrite(LED_U, HIGH);
+    digitalWrite(LED_H, HIGH);
+    value *= 1.0e9;
+  }
+  else if (value < U_H_BOUND)
+  {
+    digitalWrite(LED_L, HIGH);
+    digitalWrite(LED_P, HIGH);
+    digitalWrite(LED_N, HIGH);
+    digitalWrite(LED_U, LOW);
+    digitalWrite(LED_H, HIGH);
+    value *= 1.0e6;
+  }
+  else
+  {
+    digitalWrite(LED_L, HIGH);
+    digitalWrite(LED_P, HIGH);
+    digitalWrite(LED_N, HIGH);
+    digitalWrite(LED_U, HIGH);
+    digitalWrite(LED_H, LOW);
+    value = INF;
+  }
+  segs.print(value);
+  segs.writeDisplay();
+}
+
+
+void display_show_serial(float value)
+{
+  if (value < 1.0e-12)
+  {
+    Serial.println("low");
+  }
+  else if (value < 1.0e-9 && value >= 1.0e-12)
+  {
+    Serial.print(value * 1.0e12);
+    Serial.println(" pF");
+  }
+  else if (value < 1.0e-6 && value >= 1.0e-9)
+  {
+    Serial.print(value * 1.0e9);
+    Serial.println(" nF");
+  }
+  else if (value < 1.0e-3 && value >= 1.0e-6)
+  {
+    Serial.print(value * 1.0e6);
+    Serial.println(" uF");
+  }
+  else
+  {
+    Serial.println("high");
+  }
+}
+
+
+//------------------------------------------------------------------------------
+// Top level
+
+
+void setup() {
+  Serial.begin(9600);
+  display_init();
+  measurement_init();
+}
+
+
+void loop() {
+  float capacitor_value;
+
+  capacitor_value = measurement_read();
+
+  display_show(capacitor_value);
+  display_show_serial(capacitor_value);
+
+  delay(100);
+}