Capacimeter from Arduino to Pic... not working

35 views
Skip to first unread message

Gilles BARTHELEMY

unread,
Jan 30, 2020, 5:30:44 PM1/30/20
to jallib
Hello,

I found this code for Arduino. It needs no additional part to measure a capacitor value, just plug it between two pins of the microcontroller.

const int OUT_PIN = A2;
const int IN_PIN = A0;

//Capacitance between IN_PIN and Ground
//Stray capacitance is always present. Extra capacitance can be added to
//allow higher capacitance to be measured.
const float IN_STRAY_CAP_TO_GND = 24.48; //initially this was 30.00
const float IN_EXTRA_CAP_TO_GND = 0.0;
const float IN_CAP_TO_GND  = IN_STRAY_CAP_TO_GND + IN_EXTRA_CAP_TO_GND;
const int MAX_ADC_VALUE = 1023;

void setup()
{
  pinMode(OUT_PIN, OUTPUT);
  //digitalWrite(OUT_PIN, LOW);  //This is the default state for outputs
  pinMode(IN_PIN, OUTPUT);
  //digitalWrite(IN_PIN, LOW);

  Serial.begin(115200);
}

void loop()
{
  //Capacitor under test between OUT_PIN and IN_PIN
  //Rising high edge on OUT_PIN
  pinMode(IN_PIN, INPUT);
  digitalWrite(OUT_PIN, HIGH);
  int val = analogRead(IN_PIN);

  //Clear everything for next measurement
  digitalWrite(OUT_PIN, LOW);
  pinMode(IN_PIN, OUTPUT);

  //Calculate and print result

  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(") "));

  while (millis() % 500 != 0)
    ;    
}
I translated it to Jal, I just adapted the pins to use, and  converted floating values to integer, since I don't need them for my application
Include 16f877a

Pragma Target CLOCK 20_000_000
Pragma Target OSC hs
Pragma Target WDT disabled
Pragma Target BROWNOUT enabled
Pragma Target PWRTE disabled
Pragma Target LVP disabled
Pragma Target CPD disabled
Pragma Target WRT disabled
Pragma Target DEBUG disabled
Pragma Target CP disabled

-- include delay
include print
include format

-- Désactive les convertisseurs A/D
enable_digital_io()
--
-- Mesure en haute résolution
const bit ADC_HIGH_RESOLUTION = high
-- On va utiliser un seul canal analogique
const byte ADC_NCHANNEL = 1
-- Pas de tension de référence externe
const byte ADC_NVREF = ADC_NO_EXT_VREF

include adc
adc_init()

-- %~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%
-- % Traitement du port RS232
-- %~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%
-- -- Définition des valeurs du port série
const USART_HW_Serial     = TRUE   -- TRUE = RS232, FALSE = SPI
const Serial_HW_Baudrate  = 9600
include Serial_Hardware
Serial_HW_Init

-- some aliases so it is easy to change from serial hw to serial sw.
alias serial_write is serial_hw_write
alias serial_read is serial_hw_read
alias serial_data is serial_hw_data
alias serial_data_available is serial_hw_data_available
-- %~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%
-- % FIN Traitement du port RS232
-- %~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%~%

print_cls_ansi(serial_data)
print_string(serial_data,"Debut programme\r\n")
print_crlf(serial_data)

alias OUT_PIN is pin_B7
alias OUT_PIN_DIRECTION is pin_B7_direction
alias IN_PIN is pin_A0
alias IN_PIN_DIRECTION is pin_A0_direction

--Capacitance between IN_PIN and Ground
--Stray capacitance is always present. Extra capacitance can be added to
--allow higher capacitance to be measured.
const word IN_STRAY_CAP_TO_GND = 0 --initially this was 30.00
const word IN_EXTRA_CAP_TO_GND = 0
const word IN_CAP_TO_GND  = IN_STRAY_CAP_TO_GND + IN_EXTRA_CAP_TO_GND
const word MAX_ADC_VALUE = 1024

OUT_PIN_DIRECTION = OUTPUT
-- OUT_PIN = LOW  --This is the default state for outputs
IN_PIN_DIRECTION = OUTPUT
-- IN_PIN = LOW

var word val = 0
var dword capacitance = 0

forever loop
    -- Capacitor under test between OUT_PIN and IN_PIN
    -- Rising high edge on OUT_PIN
    IN_PIN_DIRECTION = INPUT

    OUT_PIN = HIGH
    val = adc_read_high_res(0)
    OUT_PIN = LOW

    -- Clear everything for next measurement
    IN_PIN_DIRECTION = OUTPUT

    -- Calculate and print result
    capacitance = (val * IN_CAP_TO_GND) / (MAX_ADC_VALUE - val)

    print_string(serial_data, "Capacitance Value = ")
    print_dword_dec(serial_data, capacitance)
    print_string(serial_data, " pF (")
    print_word_dec(serial_data, val)
    print_string(serial_data, ")\r\n")

    _usec_delay (1_000_000)

end loop
Unfortunately, it doesn't work at all, ADC doesn't see any change with several values of capacitors, I can't figure out why... I obviously miss something, but what?
Any idea will be welcomed!

Link to the original project:

Oliver Seitz

unread,
Jan 31, 2020, 1:13:05 AM1/31/20
to jal...@googlegroups.com
const word IN_STRAY_CAP_TO_GND = 0 --initially this was 30.00
const word IN_EXTRA_CAP_TO_GND = 0
const word IN_CAP_TO_GND  = IN_STRAY_CAP_TO_GND + IN_EXTRA_CAP_TO_GND
[...]
    -- Calculate and print result
    capacitance = (val * IN_CAP_TO_GND) / (MAX_ADC_VALUE - val)

IN_CAP_TO_GND is zero, therefore capacitance is always zero, no matter all the other values.

Using the not-so-well defined stray capacitance in a capacitive voltage divider is of course possible, but there are PICs which have far better peripherals built in for capatitance measurement. Take a look at 


For "CPU Type" select "8-bit PIC MCU", then further down try "CTMU" (Charge Time Measurement Unit) or "Capacitive Voltage Divider".

Greets,
Kiste


Am Donnerstag, 30. Januar 2020, 23:30:47 MEZ hat Gilles BARTHELEMY <bar...@gmail.com> Folgendes geschrieben:


--
You received this message because you are subscribed to the Google Groups "jallib" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jallib+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/jallib/ad650a5f-d052-4470-a3c5-120156c01f3a%40googlegroups.com.

Gilles BARTHELEMY

unread,
Jan 31, 2020, 6:17:03 AM1/31/20
to jallib
Thank you for your answer.
Yes, obviously anything multiplied by zero equal zero...

Anyway, I tried several values for IN_STRAY_CAP_TO_GND, with no result. Displaying the mesured value (VAL) always shows 838, no matter what capacitor I test (or even with no capacitor at all).
A0 tied to ground shows 0, and tied to VCC shows 1023, which seems correct. So appearently, measuring works. 
Maybe it's impossible to do with a 16F877A, but I doubt. Anyway, using the link you gave, I ordered some 18F45K22. Wait and see.
For my application, I must take the measure this way, because the goal is to get a wire length "on the fly" when a default is detected on an analog input.

A+
Gilles
To unsubscribe from this group and stop receiving emails from it, send an email to jal...@googlegroups.com.

Oliver Seitz

unread,
Jan 31, 2020, 7:34:23 AM1/31/20
to jal...@googlegroups.com
Ok, then there's another idea: You're setting A0 to digital input while reading the analog voltage. It's usually better to set analog inputs to "analog", as they then won't be loaded by the digital input circuitry. I doubt that this is the real problem, as a "measurement" which always reads 838, not +/-1, is very suspicious. What's the value when shorting the two pins?

Greets,
Kiste
 
Am Freitag, 31. Januar 2020, 12:43:51 MEZ hat Gilles BARTHELEMY <bar...@gmail.com> Folgendes geschrieben:


To unsubscribe from this group and stop receiving emails from it, send an email to jallib+un...@googlegroups.com.

To view this discussion on the web visit

Gilles BARTHELEMY

unread,
Feb 4, 2020, 2:53:08 AM2/4/20
to jallib

I received my brand new 18F45K22, and tested with it... with exactly same result. I invariably get:

A0 alone (tied to nothing) = 841
A0  tied to ground = 0
A0 tied to VCC = 1023
A0 tied to B7 (i.e OUT_PIN) = 1015

Also, I commented the line "enable_digital_io()" => same measurement.

I can't see any difference in the way it's done with Arduino, and my code... Obviously, I miss something, but where ? Hardware maybe ? Or am I simply blind ? ;-)

RobJ

unread,
Feb 4, 2020, 1:08:12 PM2/4/20
to jallib
Hi Gilles,

I am not sure but if you check the adc library you see this code:
   ADCON0_ADON = TRUE                              -- turn on ADC module
   delay_10us(adc_conversion_delay)                -- wait acquisition time
   ADCON0_GO = TRUE                                -- start conversion
   while ADCON0_GO == TRUE loop                    -- wait until conversion completed

So when you start reading the ADC there is first a delay of 10us of acquisition time and I wonder if this delay influences your measurement.

Kind regards,

Rob

Oliver Seitz

unread,
Feb 4, 2020, 3:03:39 PM2/4/20
to jal...@googlegroups.com
Hi Rob,

a *very* good point. 

The physical magic behind that "measurement" is indeed the fact, that you take a sample right *within* the acquisition time.

And, as the line 

 -- adc_conversion_delay = adc_conversion_delay / 10

in adc.jal is commented out, I presume the delay is not 10us and not the recommended  approx. 20us, but like 210us. No chance with a 30pf CVD to measure anything after such a long wait.

You have to address the ADC module yourself then, for in fact it is an error you're measuring. The library is meant to not measure errors.

But, when you can't use the library in the first place, I'd highly recommend reading chaper 19 of the 18f45k22 datasheet. It explains the periperal which is meant to measure capacitors.

Sorry for not checking the library... I only had the hardware in mind ;-)

Greets
Kiste


Am Dienstag, 4. Februar 2020, 19:08:13 MEZ hat RobJ <rob...@hotmail.com> Folgendes geschrieben:


--
You received this message because you are subscribed to the Google Groups "jallib" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jallib+un...@googlegroups.com.
To view this discussion on the web visit

Oliver Seitz

unread,
Feb 5, 2020, 11:33:48 AM2/5/20
to 'Oliver Seitz' via jallib
Hi all!

Sorry, I was partly on a wrong way. In fact it is a capacitive voltage divider, and in theory there is no need to read the value at a certain time. 

Input leakage current at room temperature is typical 0.1, maximum 50nA. (Values from 18f45k22 datasheet)

(0.1nA*210us)/30pF=0,7mV

(50nA*210us)/30pF=350mV

Loading the CVD by a capacitor to measure increases the overall capacitance. 

However, when looking at te attached diagram...

Inline-Bild

The pin capacitance is only marked as 5pF, while the ADC-hold-capacitance is nominal 13.5pF. The hold capacitor is disconnected while the main program is running. 

So, after the CVD settles to a voltage between (cap to measure) and 5pF, another 13.5pF capacitor is connected, which can alter the voltage quite a bit. 

What capacitances did you test? I think values like 1pF, 10pF, 27pF should show different readings. With values over 100pF there's a chance they do not differ much. As 100pF can be reached by 2 meters of cable, your board layout could also be of interest.

Greets
Kiste


Am Dienstag, 4. Februar 2020, 21:03:39 MEZ hat 'Oliver Seitz' via jallib <jal...@googlegroups.com> Folgendes geschrieben:


Reply all
Reply to author
Forward
0 new messages