I need to build a capacitor meter using a Wemos D1 mini board (I need wifi and small board). I have used this guide (https://www.gammon.com.au/forum/?id=12075) as a starting point. Unfortunately, it did not work. I need to measure 100pf and up.
I built the capacitance meter from Nick's page and it worked well. Very close to the values shown by my DMM.
it did not work
That statement conveys no useful information. The program does something, just no what you expect. So what does the program actually do? What is the program output? How is that different from what you expect?
Post the code that you used. Post a schematic of your setup.
As promised I tested it, it works really well over a range 20pF - >100uF. I've commented the code so you can see how it works.
For caps below 1000pF it uses "capacitors in series" principle, comparing Cext with Cs
Over 1000pF it uses cap charging through resitor between voltage thresholds. Vc = Vcc (1-exp(-t/RC)
Values of Cstray and Rpullup would need to be measured for accurate results, but work fine on my UNO;
you would need to change them for a different board.
You can measure Rpullup by measuring the voltage on open circuit, then with say a 10k load resisitor.
Cstray by calibrating against a good cap of say 50pF
/* Arduino Uno Capacitance meter
https://www.circuitbasics.com/how-to-make-an-arduino-capacitance-meter/
470uF - 18pF cap connected between A0 and A2
for electrolytics + goes to A2
*/
const int OUT_PIN = A2;
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); // output defaults to LOW
pinMode(IN_PIN, OUTPUT); // output defaults to LOW
Serial.begin(9600);
}
void loop() {
pinMode(IN_PIN, INPUT);
digitalWrite(OUT_PIN, HIGH);
int val = analogRead(IN_PIN);
digitalWrite(OUT_PIN, LOW); //discharge Cext ready for next method
if (val < 1000) {
/*
measuring Cext using the capacitive divider principle
as the caps are in series the charge is the same on both Q = It; but also charge = CV
Hence Cs*val = Cext(1023-val)
whence Cext = val *Cs / 1023 - val
below val=800 we have an error margin of 1pF
At val = 992 we have an error margin of 25pF and at val=999 40pF when C = 1000pF
*/
pinMode(IN_PIN, OUTPUT); //discharge Cs ready for next method
float capacitance = (float)val * IN_CAP_TO_GND / (float)(MAX_ADC_VALUE - val);
Serial.print(F("Capacitance Value = ")); //Serial.print(F just puts the string in flash memory
Serial.print(capacitance, 3); // 3 places after decimal point? - ridiculous, measurement of pF is not that precise
Serial.print(F(" pF ("));
Serial.print(val);
Serial.println(F(") "));
}
else {
//use RC charging time to measure C
//t is microseconds, R kohm so C will be in nF
pinMode(IN_PIN, OUTPUT); //one side of cap "grounded"
delay(1);
pinMode(OUT_PIN, INPUT_PULLUP); //now charging Cext via RPullup
unsigned long u1 = micros(); //time charging started
unsigned long t;
int digVal;
do {
digVal = digitalRead(OUT_PIN); //charging from zero up to Vih which is ABOUT 2.6V
unsigned long u2 = micros();
t = u2 > u1 ? u2 - u1 : u1 - u2;
} while ((digVal < 1) && (t < 400000L));
//if it times out - at 400msec - digval will not be 1. Hence "highVal"; Threshold is about 100uF
pinMode(OUT_PIN, INPUT);
val = analogRead(OUT_PIN); //measure the voltage it has charged to
//then from val = Vcc(1-exp(t/RC) -> t =-CRln(1-val/Vcc) -> C = - ( t / R) / ln (1 - val / Vcc)
//discharge it
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 = "));
//next bit is just choosing appropriate units
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); //repeat loop every second
}
A WeMos D1 mini (ESP8266) has a completely different A/D (absolute vs. ratiometric),
so don't expect you can just change to that processor without problems.
An ESP32 could be a better starting point.
Leo..
the sketch I tested times the charging time for the cap from 0 to ViH - then measures with the ADC.
ViH for the ESP8266 and ESP32 is 0.75 * Vcc = 2.5V which is outside the range of the ADC.
I've looked at the Nick Gammon meter and I beilieve that too is aimed at the earlier arduinos.
While the ESP8266 and ESP32 are great devices the ADC's leave a lot to be desired (such as linearity) and the ESP32 (as I found out) can be a challenge for "beginners".
I'd suggest the OP gets a nano and a breadboard, a lot of learning and fun for coppers. However as he "needs" wifi then the WeMOS CAN do the job - but he will need to rewrite a LOT of the sketch- and to make it easier, define the limits of the capacitance he needs to measure.
I didn't get an e-mail notification so I was under the impression that nobody replied :). I got everything working with an Arduino Nano. But I would like to use an ESP like Wemos D1 Mini or Node MCU but I don't get this working for some reason. I also tried the CapacitiveSensor library. Works on the Nano but not on the Wemos
At the top of the page is a box to select whether you get emails.
See my earlier comments you will understand how it works and how to mod the code to work on a different processor.
Thanks for the reply. I have switched on the notifications. But I am not sure I completely follow you. You have tested on a UNO. This works indeed. But did you test this on a Wemos D1 for example as well? Could you tell me how to make the connections?
I fully documented my code as posted above so you should be able to see how it works. Depending on the range of capacitance you need to measure you may be able to delete part of the code.
For caps below 1000pF it uses "capacitors in series" principle, comparing Cext with Cs
Over 1000pF it uses cap charging through resitor between voltage thresholds. Vc = Vcc (1-exp(-t/RC)
Values of Cstray and Rpullup would need to be measured for accurate results, but work fine on my UNO;
you would need to change them for a different board.
You can measure Rpullup by measuring the voltage on open circuit, then with say a 10k load resisitor.
Cstray by calibrating against a good cap of say 50pF
The WEMOS D1 / NodeMCU / ESP8266 only has 1 analog input which would be a problem; the ESP32 WROOM Devkit has several but a bit tricky to use.
Thanks for your suggestions. I would like to use ESPHome and integrate the board with Home Assistant. So I am thinking to see if it is working with an ATtiny board and send the data to Wemos.
Where did you get a "74htc14"?
Some kind of typo there.
Correct family is 74HCT.
Mouser seems to carry 74HCT14, but not Digikey. Odd.
"Schmitt Trigger"