I'm trying to measure capacitance with my STM32L053-Disco.

I'm using the ADC and one output pin to charge the capacitor. I tried measuring the time it takes for the capacitor to charge to 62.3%.

The problem that I'm facing is that the values that I'm getting from ADC never show that it gets any charge.

Also it seems that the capacitor that I plugged in doesn't do anything, the readings are the same with capacitor plugged in and when I disconnect it.

I used a 1 nF capacitor and 1MOhm resistor.

This is my circuit:

enter image description here


while (1)
    // Get ADC value
    HAL_ADC_PollForConversion(&hadc, 1000);

    raw = HAL_ADC_GetValue(&hadc);
    real = (raw*3.3)/4096;

    //status == HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);

    if (real >= 3.3*0.632)
        time2 = HAL_GetTick();

    if (real <= 0.12)
        time1 = HAL_GetTick();

    time3 = (time2 - time1)/1000;
    c = time3/res;

    // Convert to string and print
    sprintf(TxBuffer,"%7.3f V\n", real);
    HAL_UART_Transmit(&huart1, (uint8_t*)TxBuffer, strlen(TxBuffer), HAL_MAX_DELAY);

    // Pretend we have to do something else for a while

I never get to measuring capacitance because these are the ADC values that I get:

enter image description here

Can anybody help me?

  • \$\begingroup\$ So your ADC consistently reads about 146 counts. What if you plug 3.3V directly into your ADC input? \$\endgroup\$
    – vicatcu
    May 10 at 0:52
  • \$\begingroup\$ It reads like that when I put in 1Mohm resistor, when I plug it directly I get 4096 counts \$\endgroup\$
    – Rexepo LT
    May 10 at 1:15
  • \$\begingroup\$ A more accurate way is to use an AC (alternating) current source to control the frequency then counter the frequency over a fixed time interval interrupt. What range, resolution and accuracy do you expect? A Schmitt trigger Osc works well for this. \$\endgroup\$ May 10 at 3:40
  • \$\begingroup\$ I want to measure 1 nF – 10 µF and don't really care about accuracy if it's atleast close to real value. \$\endgroup\$
    – Rexepo LT
    May 10 at 8:58
  • \$\begingroup\$ "it seems that the capacitor that I plugged in doesn't do anything" Do you have an oscilloscope available to help checking the circuit? \$\endgroup\$
    – devnull
    May 10 at 11:25

3 Answers 3


You have the GPIO going to the capacitor through a 1 Meg resistor, and then you've connected the ADC input to it.

What is the impedance of the ADC input? If I read the datasheet correctly it is 50 k.

You've formed a voltage divider with 1 Meg and 50 k resistors. Your capacitor isn't going to charge the way you were expecting it to.

One thing you could do is to add a high input impedance buffer between the capacitor and the ADC input, and maybe lower the charging resistance as well.

There is a section of the data sheet that tells you how to calculate the maximum external impedance used to drive the analog input. You could start with that and see if you can use a lower value resistor. You'd have to take the ADC input impedance into account when doing the calculations.

  • \$\begingroup\$ Is there anyway I could fix that so I would see my capacitor charge? \$\endgroup\$
    – Rexepo LT
    May 10 at 1:14
  • \$\begingroup\$ @RexepoLT I added to my answer. There might be a better way to do it, I haven't really looked into making a cap meter using a micro, you might do a bit of research to see how other people have done it. \$\endgroup\$
    – GodJihyo
    May 10 at 1:34
  • \$\begingroup\$ Use the analog comparator hooked into a timer so you measure the time it takes to charge to a given voltage. Then reconfigure to discharge the capacitor and measure the time it takes to go below a given voltage.for a wide range you can use different value resistors to charge/discharge the capacitor. \$\endgroup\$
    – Kartman
    May 10 at 5:11
  • 1
    \$\begingroup\$ Yes you are reading the datasheet incorrectly. 50k is not the ADC input impedance. \$\endgroup\$
    – Justme
    May 10 at 9:42
  • 1
    \$\begingroup\$ @GodJihyo Check Figure 27 of the datasheet to see the roles of the \$R_{AIN}\$ and \$R_{ADC}\$ resistances in the transient response of the sample-and-hold mechanism. The figure you are looking for (for almost DC operation with a single channel) is the 50nA current. The point is: since the DC input resistance is very high people often disregard that the transient behavior is much worse and exaggerate on the value of the external drive resistance \$R_{AIN}\$. \$\endgroup\$
    – devnull
    May 10 at 10:20

In order to use measure capacitance and inductance we use AC sources.

Emulate a AC sine source using the microcontroller , make a Sauty bridge then feed the differential input of the Sauty bridge to a BJT common collector differential to single converter and feed that output to a pin.

  • \$\begingroup\$ Sounds complicated. The OP's method should work fine with a buffer to raise the input impedance. \$\endgroup\$ May 10 at 19:01
  • \$\begingroup\$ yes but it is very reliable because it takes into account the steady state response of a capacitor. \$\endgroup\$
    – Jun Seo-He
    May 12 at 12:56

The proper way to measure capacitance is with a constant current or by impedance ratios at some frequency. Consider the timer method.

Use two threshold voltages, (one could be 0V) with a difference dV to measure the time interval. You chose 62.3% of 3.3V but I don't know how you reset,start,measured that. But using 63.2% has an exponential decay towards 3.3V since the current reduces as the voltage charges up with current being the voltage drop on the resistor , I=V/R.

In theory that will work fine if you can ensure your reset, start, stop thresholds are accurately measured in time. So a much slower ramp than the code latency to start/stop the timer is needed. However, this method is also affected by the ADC input impedance and noise due to (R//C) and switch noise and you do not have a low impedance.

Consider the frequency method.

A better way is to use an external oscillator whos frequency = k/C or cycle interval is C/k where k depends on the difference in threshold voltages, dV for start/stop, then C=Ic dt/dV. THe current Ic depends on the voltage drop across the resistor = V/R. You can use the ADC to measure this if it is fast enough but it is easier to use a comparator with precise hysteresis.

Using a CMOS Schmitt trigger with nominal thresholds of 1/3, 2/3 is not precise but gets a decent linear triangle wave with C to ground and R feedback and RC=T swings only about 1/3 rather than the exponential decay that occurs after 1/3T where T=62.3% of target V, or 0.623 * 3.3V .

Then all you have to do is measure frequency and compute C=k/f for some constant k that can be computed from the actual dV.

Thus C becomes a frequency controlled timer with f inversely proportional to C.

There are much better ways with other hardware but those were not mentioned.

  • \$\begingroup\$ _"Then all you have to do is measure frequency and compute C=k/f for some constant k that can be computed from the actual dV." - or you measure the period, and then you only have to scale the result. \$\endgroup\$ May 13 at 5:08
  • \$\begingroup\$ @BruceAbbott It would have to be averaged period with a clock much faster than intended use Osc. signal. I was thinking 100 Khz like good LRC meters but it could be slow for that type of application. Counting cycles is like averaging pulse time intervals assuming it's 50% d.f. always. in order to attenuate noise. \$\endgroup\$ May 13 at 5:59
  • \$\begingroup\$ In 1978 I designed a digital capacitance meter using a 555 timer in one-shot mode and 4 digit decade counter with LED display. 1MHz clock, 1 second gate, 6 ranges covering 9.999nF (1pF resolution) to 999.9uF with better than 1% linearity and +-1 digit noise. No fancy high speed MCU required! (or possible back then). 44 years later it still works perfectly. \$\endgroup\$ May 13 at 11:25
  • \$\begingroup\$ Nice job @BruceAbbott \$\endgroup\$ May 13 at 13:13
  • \$\begingroup\$ . I did something different in the same year measuring XY impedance to 10 ppm resolution at 100k & 200 kHz for an Eddy current sensor with a SCADA system using PLL's. The interesting part was 0 and 90 deg phase shift was a 1mm thru hole in a steel tube and a 50% reduction in wall thickness ring was used for calibration. I digitized using rotary encoders every 0.1 mm using BurrBrown 12 MHz ADC's and an MC6800 used for SCADA & console I/O 1000:1 Swiss motors with Sin-cos pots were used to rotate phase and auto null for calibration. \$\endgroup\$ May 13 at 13:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.