Parasite readings from analogRead

Hi everyone, I'm measuring a range of voltage values (0-5V) from a voltage divider with a capacitive load for a project, I take 100 samples in an interval of about 10 to 20ms, but I keep getting wrong values, my multimeter reads 3.8 and the value that the analogRead returns is 5V or 0 (1023 or 0) for most of the samples.

Can you guys please help me with this?

Not sure what you mean by "with a capacitive load". How is everything wired? Is the input voltage AC or DC?

Can you post your code?

Sounds like a rectangular waveform, so both are right - multimeters average over second or so with a dual-slope integrating ADC, the ADC on the Arduino is a successive approximation ADC clocked at 125kHz and sampling its input in a few microseconds (if low impedance). About 5 orders of magnitude difference in how quickly they respond to changing voltage.

Not sure what you mean by "with a capacitive load". How is everything wired? Is the input voltage AC or DC?

The capacitive load uses a capacitor connected to the voltage source, making it fluctuate from 0 to 5V "automatically", I'm using a voltage divider to get these 0 to 5V, because my original source (a PV) delivers 21V DC.

About 5 orders of magnitude difference in how quickly they respond to changing voltage.

Where can I get more information about this?

Here's my code, thank you for checking it out!

#include <Wire.h>
#include <avr/io.h>
#include <SD.h>
#include <avr/power.h>
#include <stdio.h>
#include <stdlib.h>
#include "RTClib.h"

 
RTC_DS1307 RTC;

#define porcentaje 0.7

#define FASTADC 1

// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

int rly1Pin = 2;
int rly2Pin = 3;
int rly3Pin = 4;
int voltPin = A2;
int corrPin = A3;
int valor = 0; 
const float incremento = (5.0/1024.0); 
float voltVec[100]={0}; 
float corrVec[100]={0}; 
//Para la tarjeta SD de memoria
int CS_pin = 10;
int pow_pin = 8;



void setup () {
    Serial.begin(9600);
    Wire.begin();
    RTC.begin();
 
  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");}
    
//RTC.adjust(DateTime(__DATE__, __TIME__));
  pinMode(CS_pin, OUTPUT);
  pinMode(pow_pin, OUTPUT);
  pinMode(rly1Pin, OUTPUT);
  pinMode(rly2Pin, OUTPUT);
  pinMode(rly3Pin, OUTPUT);
  Desactivar_Relay();
  SwitchOff_Carga();
  digitalWrite(rly3Pin, LOW);
  digitalWrite(pow_pin, HIGH);
  
  if (!SD.begin(CS_pin))
  {
    Serial.println("Card Failure");
    return;
  }
#if FASTADC
  // set prescale to 16
  sbi(ADCSRA,ADPS2) ;
  cbi(ADCSRA,ADPS1) ;
  cbi(ADCSRA,ADPS0) ;
#endif

}


void loop(){  
  
  DateTime now = RTC.now();
  int hora = now.hour();
  int minuto = now.minute(); 


  if (hora<7)
{
Dormir();
}

  if (hora>22)
{
Dormir();
}
  
    
  else 
{
   if (minuto==0) 
     {
     Despierta();
     Activar_Relay();
     int voc = 0;
     
     voc = analogRead(voltPin); 

     int maximo = voc*porcentaje; 
     int delta1 = maximo/5; 
     int delta2 = (voc-maximo)/95; 
     Serial.print("VOC = ");
     Serial.println(voc,DEC);
     SwitchOn_Carga();
     Medicion_Datos_IV(delta1,1,6);
     Medicion_Datos_IV(delta2,6,101); 
     Imprimir_Serial();
     Desactivar_Relay();
     SwitchOff_Carga();
     Switch_Descarga();
     Nada(); 
 }
  
   
  else 
  {
     Desactivar_Relay();
   }
}
  
}    



void Activar_Relay (){
     digitalWrite(rly1Pin, HIGH);
}

void Desactivar_Relay(){
    digitalWrite(rly1Pin, LOW);
}

void Medicion_Datos_IV (int delta, int lim_inf, int lim_sup){
  
  int compara = 0;
  int i = 0;
  
  while(i<lim_sup)
  {
  //compara = compara+delta;
  int volt = analogRead(voltPin);     
  int corr = analogRead(corrPin);
  //if (volt>=compara)
  //{
  voltVec[i] = (volt*incremento);
  corrVec[i] = (corr*incremento);
  i=i+1;
  //} 
  }
  
  
}

void Imprimir_Serial(){
  for(int i=1; i<=101;i++)
  {
  Serial.println(voltVec[i], DEC);
  }
  Serial.println("/");
  for(int i=1; i<=101;i++)
  {
  Serial.println(corrVec[i], DEC);
  }
}

void Nada (){
  Serial.println("Fin de toma de datos");
}

void Despierta(){
//power_spi_enable();
power_usart0_enable();
//power_usart1_enable();
power_timer0_enable();
power_timer1_enable();
power_timer2_enable();
//power_twi_enable();
}
void Dormir(){

Serial.println("No molestar, estoy durmiendo");
//power_spi_disable();
power_usart0_disable();
//power_usart1_disable();
power_timer0_disable();
power_timer1_disable();
power_timer2_disable();
//power_twi_disable();

}  

void SwitchOn_Carga(){
  digitalWrite(rly2Pin, HIGH);
  Serial.println("Conectando carga"); 
}

void SwitchOff_Carga(){
  digitalWrite(rly2Pin, LOW);
  Serial.println("Desconectando carga");
}

void Switch_Descarga(){     
  int medida = analogRead(voltPin);
  while (medida >= 1){
  digitalWrite(rly3Pin, HIGH);
  medida = analogRead(voltPin);
  delay(5);
  }
  digitalWrite(rly3Pin, LOW);
}

What are the values used in your voltage divider resistors? The source impedance of whatever voltage source wired to a analog input can effect the accuracy of the measurement if too high a value.

Lefty

I'm using 3.9k and 1.2k ohms for my voltage divider.. Is this to high? I changed them for 39 and 12 ohms but it was too low and the PV short-circuited!

You wrote:

I'm using 3.9k and 1.2k ohms for my voltage divider.. Is this to high? I changed them for 39 and 12
ohms but it was too low and the PV short-circuited!

3.9K and 1.2K are borderline OK resistor values for a 21 volt (assumed low impedance? PV == PhotoVoltaic array?), feeding an Arduino's A2D input pin. However, if the PV voltage goes any higher than 21 volts, then the voltage going into the A2D pin will go above 5 volts, and that's very bad for the A2D and bad for sane readings. I'd suggest increasing the 3.9K resistor to 4.3K or 4.7K, unless you are certain that the input voltage will never ever exceed 21 volts. (39 and 12 ohms are way off; just calculate the current draw and the power dissipation!) At DC, your voltage divider is drawing about 4 mA, which is huge compared to the disturbances the A2D makes to its inputs.

Am I correct that your capacitor is in parallel with the 1.2K resistor? (If not, please describe your circuit in more detail.) Without knowing the value of your capacitor, we cannot figure out the RC time constant for your ad-hoc filter, so we can't fully understand your circuit or its behavior. By the way, using an electrolytic cap in a signal-filtering role is just asking for trouble; they leak like sieves. Unless you're doing something fancy, a ceramic cap or a polyester film one should be fine. Note that the tolerance on non-precision caps is very wide, so either measure C or buy one with say +/- 20% tolerance.

If the C is parallel to the 1.2K resistor, and had a value of, say 1 uF (0.000001 Farads), then the RC combo will act like a first-order low pass filter with a knee in the response at:
F_hz = 1/(2PiR*C) = 132 Hz. So this RC combo would filter out signal components above 132 Hz, as a first-order (rather gradual) filter.

I suggest you first work on getting sane A2D readings with just a voltage divider,without the capacitor.

Hope this helps.

Thank you PiJoy! Yes, my source is a photovoltaic array, and I'll change my 3.9k resistor for a 4.3k because voltage can get to 21.9V in the most favorable conditions of sun.
I was able to get the readings, without the capacitor, my error was to have the negative feed from the PV floating around, without gnd.

My capacitor is 2200µF so the arduino will have enough time to read the voltage changes, I chose this value based on the Isc and Voc of the photovoltaic array, by:

C = Ts * Isc/Voc

Where Ts is the time the capacitor takes to get to Voc, which is the highest voltage value for the measures taken at a given time of the day (my Isc = 1.93 A)

I'll try with a ceramic cap instead, to se waht happens..

You wrote:

My capacitor is 2200µF so the arduino will have enough time to read the voltage changes, I chose this value based on the Isc and Voc of the photovoltaic array, by:

C = Ts * Isc/Voc

Where Ts is the time the capacitor takes to get to Voc, which is the highest voltage value for the measures taken at a given time of the day (my Isc = 1.93 A)

Your 2200 uF cap is almost certainly an electrolytic; suggest you leave those for power supply use only! To size your filter cap, your voltage divider decouples the PV array (and its current) from your RC filter. So, the resistor in parallel with the cap is what really matters for the filter's time constant, as in my previous post. I suspect you'll want a cap on the close order of 1 uF.