Capacitor and Resistance Tester problem

Hello, here is my problem. I have this university project where I am building a measuring tool, but I am facing accuracy issues.

The problem lies in the different results I get from a serial monitor on an Arduino compared to the results displayed on my device.

1.Measuring Resistance.
I have a 1 kΩ resistor, but the measured value on the breadboard device fluctuates between 950-970 Ω. However, when I use another Arduino and check the value on the Serial Monitor, I get a much more accurate reading—between 997-999 Ω or even 1000 Ω. The tutorial I followed is the same code I used as well.

How to Make an Arduino Ohm Meter

  1. Measuring Capacitance.
    Measure Capacitance With Arduino : 6 Steps (with Pictures) - Instructables

This is the tutorial I followed, but I can't say much more because I am encountering the same issue.

If I use another Arduino, the values shown on the Serial Monitor are accurate. For instance, when measuring a 1 µF capacitor, the reading is correct. However, when I measure it on my device, I sometimes get 2 µF, and other times 3 µF or even 6 µF.




I know that all the cable management is bad, i already switched with another ardruino and i get the same value, i just want to know why i get so different values and what i can do, maybe change something in the code, idk.
And when measuring the capacitance the display freeze, the serial monitor is clear too.

I don't expect everything to go right, i know that at least around these values i need to have some accuracy.

// Programming a button to go back from a while menu thing
// https://forum.arduino.cc/t/programming-a-button-to-go-back-from-a-while-menu-thing/1325404


#include <Adafruit_GFX.h>
#include <Adafruit_ST7789.h>
#include <SPI.h>

#include <BH1750.h>
#include <Wire.h>

BH1750 lightMeter;

#define TFT_CS   10   // Chip select (CS)
#define TFT_RST   8   // Reset pin
#define TFT_DC    9   // Data/Command pin

#define  PRESSED  LOW // Using Pull-up, the button press connects to the GND
#define RELEASED HIGH

int analogPin = 1;
int chargePin = 12;
int dischargePin = 10; //speeds up discharging process, not necessary though
int resistorValue = 10000;

// Initialize Timer
unsigned long startTime;
unsigned long elapsedTime;

// Initialize Capacitance Variables
float microFarads;                
float nanoFarads;

int   backButtonPin = 5;    // Buton Back (BB)
int     upButtonPin = 4;    // Buton Up (BU)
int   downButtonPin = 3;    // Buton Down (BD)
int selectButtonPin = 2;    // Buton Select (BS)
enum button_t : uint8_t {NONE, UP, DOWN, SELECT, BACK} button;

uint16_t menuLineNumber[] = {0, 30, 80, 130, 180};

// Ohm metru //
const int sensorPin = A0;  // Analog input pin that senses Vout
int sensorValue = 0;       // sensorPin default value
float Vin = 5.0;             // Input voltage
float Vout = 0.0;            // Vout default value
float Rref = 999.0;          // Reference resistor's value in ohms
float R = 0.0;               // Tested resistor's default value
//Ohm metru //

void (*measurePtr)(void) = NULL;

int menuLine = 1;  // Meniul curent, începe de la 1

Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);

void afisaremeniu() {
  tft.fillScreen(ST77XX_BLACK);
  tft.setCursor(30, 30);
  tft.print("Rezistenta");
  tft.setCursor(30, 80);
  tft.print("Capacitate");
  tft.setCursor(30, 130);
  tft.print("Intensitatea Luminoasa");
  tft.setCursor(30, 180);
  tft.print("Informatii");
}

void afisareLine() {
  static uint16_t oldMenuLine = 0;
  
  tft.setTextColor(ST77XX_BLACK); 
  tft.setCursor(10, menuLineNumber[oldMenuLine]);
  tft.print('>');
  tft.setTextColor(ST77XX_WHITE); 
  oldMenuLine = menuLine;
  tft.setCursor(10, menuLineNumber[menuLine]);
  tft.print('>');
}

void setup() {
  pinMode(chargePin, OUTPUT);     
  digitalWrite(chargePin, LOW); 
  pinMode(    upButtonPin, INPUT_PULLUP);  // Setare buton Up ca INPUT_PULLUP
  pinMode(  downButtonPin, INPUT_PULLUP);  // Setare buton Down ca INPUT_PULLUP
  pinMode(selectButtonPin, INPUT_PULLUP);  // Setare buton Select ca INPUT_PULLUP
  pinMode(  backButtonPin, INPUT_PULLUP);
  Wire.begin();
  lightMeter.begin();
  tft.init(240, 320);  // Initializare ecran 240x320 pixeli
  tft.setRotation(1);  // Rotire ecran
 
  tft.setTextColor(ST77XX_WHITE);  // Text alb
  tft.setTextSize(2);  // Dimensiune text
  afisaremeniu();  // Afi?eaza meniul ini?ial
  afisareLine();
   Serial.begin(9600);
}

void loop() {
  static button_t oldButton = NONE;
  
   Serial.print("UP: ");
  Serial.println(digitalRead(upButtonPin));
   Serial.print(" | DOWN: ");
  Serial.println(digitalRead(downButtonPin));
    Serial.print(" | SELECT: "); 
  Serial.println(digitalRead(selectButtonPin));
    Serial.print(" | BACK: "); 
  Serial.println(digitalRead(backButtonPin));
  delay(100);

  if     (digitalRead(    upButtonPin) == RELEASED) { button = UP;}
  else if(digitalRead(  downButtonPin) == RELEASED) { button = DOWN;}
  else if(digitalRead(selectButtonPin) == RELEASED) { button = SELECT;}
  else if(digitalRead(  backButtonPin) == RELEASED) { button = BACK;}
  else { button = NONE;}

  if (oldButton != button) {
    oldButton = button;
    switch (button) {
      case UP:  // Navigare în meniu folosind butonul Up (BU)
        if (menuLine == 1) {
          menuLine = 4;  // Revin la ultimul meniu daca scade sub 1
          
        }
        else {
          menuLine--;  // Mergem la meniul anterior
        }
        afisareLine();  // Actualizeaza meniul pe ecran
        break;
        
      case DOWN:  // Navigare în meniu folosind butonul Down (BD)
        if (menuLine == 4) {
          menuLine = 1;   // Revin la primul meniu daca depa?e?te 3
        }
        else {
          menuLine++;     // Trecem la urmatorul meniu
        }
        afisareLine();    // Actualizeaza meniul pe ecran
        break;
      case SELECT:  // Executa ac?iunea selectata cu butonul Select (BS)
        actiune();  // Executa ac?iunea pentru meniul curent
        // bs_apasat = true;
        break;
      case BACK:  // Back
        measurePtr = NULL;
        afisaremeniu();
        afisareLine();  // Actualizeaza meniul pe ecran
        break;
        
    }
  }
  if (measurePtr) (*measurePtr)();
  delay(100);
}

void actiune() {
  switch (menuLine) {
    case 1:
      tft.fillScreen(ST77XX_BLACK);
      tft.setCursor(10, 10);
      tft.print("Masurare rezistenta:");
      measurePtr = masurareRezistenta;
      break;

    case 2:
      tft.fillScreen(ST77XX_BLACK);
      tft.setCursor(10, 30);
      tft.print("Masurare Capacitate:");
      measurePtr = masurareCapacitate;
      break;
    case 3:
      tft.fillScreen(ST77XX_BLACK);
      tft.setCursor(10, 30);
      tft.print("Masurare Iluminarii");
      measurePtr = masurareLumina;
      break;
    case 4:
      tft.fillScreen(ST77XX_BLACK);
      tft.setCursor(10, 30);
      tft.print("Testate Meniu 4!");
      break;
  }
}
void masurareRezistenta() {
  Serial.print('.');
  // Cite?te valoarea senzorului
  sensorValue = analogRead(sensorPin);  // Cite?te Vout pe pinul analogic A0
  Vout = (Vin * sensorValue) / 1023.0;  // Conversie la vol?i
  R = Rref * (1 / ((Vin / Vout) - 1));
  tft.fillRect(10, 50, 220, 30, ST77XX_BLACK);  // Cura?a zona de afi?are
  tft.setCursor(10, 50);

  if (R > 500000.0) {  // Rezisten?a infinita sau foarte mare
    tft.print("R: Inf");
  }
  else if (R > 999.0) {  // Conversie la kOhm
    tft.print("R: ");
    tft.print(R / 1000.0, 2);  // 2 zecimale pentru precizie
    // tft.print(" kΩ");
    tft.print(" kOhm");
  }
  else {  // Rezisten?a în Ohmi
    tft.print("R: ");
    tft.print(R, 2);  // 2 zecimale pentru precizie
    // tft.print(" Ω");
    tft.print(" Ohm");
  }
}

void masurareCapacitate() {
  delay(300);
 digitalWrite(chargePin, HIGH); // Begins charging the capacitor
  startTime = millis(); // Begins the timer
  
  while(analogRead(analogPin) < 648)
  {       
    // Does nothing until capacitor reaches 63.2% of total voltage
  }

 tft.fillRect(10, 50, 220, 30, ST77XX_BLACK);  // Cura?a zona de afi?are
  tft.setCursor(10, 50);

  elapsedTime= millis() - startTime; // Determines how much time it took to charge capacitor
  microFarads = ((float)elapsedTime / resistorValue) * 1000;
  Serial.print(elapsedTime);       
  Serial.print(" mS    ");         

  if (microFarads > 1) // Determines if units should be micro or nano and prints accordingly
  {
    tft.print((long)microFarads);       
    tft.print(" microFarads");    
    Serial.print((long)microFarads);       
    Serial.println(" microFarads");      
  }

  else
  {
    nanoFarads = microFarads * 1000.0;      
    tft.print((long)nanoFarads);         
    tft.print(" nanoFarads");         
    Serial.println(" nanoFarads");          
    delay(500); 
  }

  digitalWrite(chargePin, LOW); // Stops charging capacitor
  pinMode(dischargePin, OUTPUT); 
  digitalWrite(dischargePin, LOW); // Allows capacitor to discharge    
  while(analogRead(analogPin) > 0)
  {
    // Do nothing until capacitor is discharged      
  }
  pinMode(dischargePin, INPUT); // Prevents capacitor from discharging  
}

 void masurareLumina() {
  float lux = lightMeter.readLightLevel();
   tft.fillRect(10, 50, 220, 30, ST77XX_BLACK);  // Cura?a zona de afi?are
   tft.setCursor(10, 50);
   tft.print(lux);
   tft.print(" lx");
   delay(1000);
   
   }

I do not see any mention of you calibrating each device you build. Why not? Every instrument must be calibrated.

2 Likes

calibrate how ? do what ? i didn't said i have sensors to calibrate, please read again all and check the code and the pictures, and don't just give me a comment like that, come with a solutions, you gave me nothing honestly....

You need to adjust either the software or the hardware to give you the same results for each version of your device. What is so difficult to understand?

1 Like

It's not unusual to get noise/instability with breadboard wiring, especially with analog. Even on a circuit board analog can be sensitive. Multimeters also have smoothing/averaging/filtering so the numbers don't jump-around faster than you can read them.

I haven't looked at your code or your circuit but sometimes a small change/variation in the raw reading can make a bigger change in the calculated voltage/resistance/capacitance, etc.

And with ANY analog-to-digital conversion you can be on the hairy-edge between two counts so can't always be perfectly stable.

...Usually these kinds of measurements are better-done with a multimeter. Building your own meter is usually for fun or learning.

Except sometimes your project may need built-in voltage or current monitoring, etc.

I'm pretty sure multimeters use special-purpose chips.

It’s primarily a learning project, demonstrating that a student with some engineering knowledge can design and build such a device at home and actually use it. I can't figure it out unfortunetly.... :frowning:

I’ve skipped through the code and don’t see the use of a stable voltage reference- the power supply ( the default reference ) will vary between devices .

Variations in voltage references , A/D convertors etc etc between devices means you must calibrate your devices .
If you buy a multimeter , it’s comes with calibration information …

Your wiring layout is dreadful , you need to sort that out .

People here try to help and have vast experience - be courteous or you’ll get no where

2 Likes

The display update logic and sensor reading code are being executed together, without yielding time for stability.

Add a small delay after the display update to stabilize it.
Use millis() instead of delay() for non-blocking updates if freezing continues

made some changes, i can get out of the menu now, but it measure a bit worst, so i still can't figure it out why with just the ardruino i get a good value and with all the other components i get everything messed up

void masurareCapacitate() {
  delay(300);
 digitalWrite(chargePin, HIGH); // Begins charging the capacitor
  startTime = micros(); // Begins the timer
  
  while(analogRead(analogPin) < 648)
  {        if (digitalRead(backButtonPin) == RELEASED) {
    measurePtr = NULL;
    afisaremeniu();
    afisareLine();
    return;  // Iese imediat din funcție
  }
    // Does nothing until capacitor reaches 63.2% of total voltage
  }

 tft.fillRect(10, 50, 220, 30, ST77XX_BLACK);  // Cura?a zona de afi?are
  tft.setCursor(10, 50);

  elapsedTime= micros() - startTime; // Determines how much time it took to charge capacitor
  microFarads = ((float)elapsedTime / resistorValue) * 1000;
  Serial.print(elapsedTime);       
  Serial.print(" mS    ");         

  if (microFarads > 1) // Determines if units should be micro or nano and prints accordingly
  {
    tft.print((long)microFarads);       
    tft.print(" microFarads");    
    Serial.print((long)microFarads);       
    Serial.println(" microFarads");      
  }

  else
  {
    nanoFarads = microFarads * 1000.0;      
    tft.print((long)nanoFarads);         
    tft.print(" nanoFarads");         
    Serial.println(" nanoFarads");          
    delay(500); 
  }

  digitalWrite(chargePin, LOW); // Stops charging capacitor
  pinMode(dischargePin, OUTPUT); 
  digitalWrite(dischargePin, LOW); // Allows capacitor to discharge    
  while(analogRead(analogPin) > 0)
  {
    if (digitalRead(backButtonPin) == RELEASED) {
    measurePtr = NULL;
    afisaremeniu();
    afisareLine();
    return;
  }
    // Do nothing until capacitor is discharged      
  }
  pinMode(dischargePin, INPUT); // Prevents capacitor from discharging  
}

Hi, @frostygamerro

Can you please post a copy of your circuit, a picture of a hand drawn circuit in jpg, png?
Hand drawn and photographed is perfectly acceptable.
Please include ALL hardware, power supplies, component names and pin labels.

Have you got the measurement part of your circuit connected directly to gnd and 5V AT the UNO?

Good gnd connections will be essential for this sort of process.

Thanks.. Tom.... :smiley: :+1: :coffee: :australia:

Taking the measurement part from the 5v supply will not give accurate results .

Things such as using serial or the display cause voltage drops , as the supply current changes , and with it the reference voltage , especially with thin wires and bread boards .
For a University project you should be researching measurement techniques , single point grounding , voltage references as well as how the Arduino is built . Then investigating why you get differences .
That’s where the marks are , not in just wiring up some downloaded code .

1 Like


yes, all is connected to the 5V and GND at the uno.
I tried to power the ardruino throught the usb and i have 2 batteries18650 and it's the same bad result. Now i am thinking if i put the display at 3.3 would there be any diferences in measuring ? but i don't think so.
The Measuring resistance part is not the worst, even if i get 950 Ohm i know that the resistor is 1k, even the error is important for my license paper, but i don't understand how to make the Capacitance measure work, because i get the worst values, i look on the datasheets, even if the capacitor is +-10% i am not even there

would be better if i use a battery for the display only and another one for the ardruino and to take 5V from the ardruino ? I have 2 x 18650 batteries, the display from what i know works between 3-5.

As others have pointed out you need a stable reference if you want absolute values. Voltage regulators are specified for 2-5% accuracy, which is fine for a power supply but not as a reference. Use of the supply voltage is fine for ratio use such as potentiometer position.

If you still want to use the supply voltage you need to calibrate for the actual voltage - which may still not be stable depending on load. If you don't want to use an external reference you can use the internal reference and adjust the input accordingly. This still requires calibration because although the internal reference is stable the actual value varies.

Search ..Nic Gammon capacitance meter"

Get the Cap meter working then add the resistance.

and please

Dump anyting you see from INSTRUCTABLES.

Hi, @frostygamerro
Thanks for the diagram.

Hint, do it in black and white, colours, especially yellow and light colours are not very readable.

Pen(cil) and paper would be better.

int dischargePin = 10; //speeds up discharging process, not necessary though

Pin is already used for the display.

Tom.... :smiley: :+1: :coffee: :australia:

Nice catch.

thanks, i changed that, now i get worst results, i will try to make the tutorial you from Nic Gammon with the capacitance meter

In your shoes at this stage I would separate the resistance, capacitance and light level circuits and sketches to see if the inaccuracies occur in one or the other. And/or try without the OLED display. It means curbing impatience but...

I did that, i tested everything separated, without the display, i added them step by step, and at this point everything is messed up, i don't know what to do anymore. I will try the Nic Gammon tutorial but i am missing the 1.8k resistor and will wait some days for it to come