Extremely unstable analogReads

Hello,

i'm having a problem while datalogging temperature, voltage and current in my small 12V-battery project.
I'm using the widely know small sensors for voltage and current, as well as LM4040 voltage reference.

image
image

I've set up an SD Card and logged all Data for about 4 days. The fan wasn't running at all, since i've set the threshold at 30°C.
Unfortunately, i'm getting very fluctuating readings, from 12.40V one day to suddenly 13.10V the next day. There is no charger connected.
Since this affects the voltage sensor as well as the current sensor at the same time, i suspect it's a problem with the analogRead.

Do you have any idea what the problem might be?

Code:

//Voltage Sensor
int ANALOG_IN_PIN=A0;
float adc_voltage=0.00;
float in_voltage=0.0;
float ref_voltage=4.85;
int adc_value=0;
float R1=30000.0;
float R2=7500.0;

//Temperatursensor
#include <math.h>
const int B = 4275;               // B value of the thermistor
const int R0 = 100000;            // R0 = 100k
const int pinTempSensor = A1;     // Grove - Temperature Sensor connect to A0
int tempRead=0;
float temperature=0.00;

//Luefter
int fanPin=3;

//Stromsensor
int currentPin=A7;
float currentValue;
float readCurrent;

//LEDs
int led1Pin=6;
int led2Pin=5;
int led3Pin=4;
int led4Pin=9;
int led5Pin=8;

//SD-Card
#include <SD.h>
#include <SPI.h>
File myFile;
int pinCS=10;

//RTC (Real-Time-Clock)
#include <Wire.h>
#include <RTClib.h>
RTC_DS1307 rtc;
DateTime now;

void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
pinMode(ANALOG_IN_PIN,INPUT);
pinMode(pinTempSensor,INPUT);
pinMode(fanPin,OUTPUT);
pinMode(led1Pin,OUTPUT);
pinMode(led2Pin,OUTPUT);
pinMode(led3Pin,OUTPUT);
pinMode(led4Pin,OUTPUT);
pinMode(led5Pin,OUTPUT);
pinMode(currentPin,INPUT);
pinMode(pinCS,OUTPUT);

analogReference(EXTERNAL);

//SD Card Initialization
  if (SD.begin()){
    Serial.println("SD card is ready to use.");
    } else {
      Serial.println("SD card initialization failed");
      }
//SD.remove("datalog.txt");     //Deleting Textfile

//RTC (Real-Time-Clock)
if(!rtc.begin()){
   Serial.println("Couldn't find RTC");
  }
if(!rtc.isrunning()){
   Serial.println("RTC is NOT running");
  }
//rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));         //Zeit/Datum neu justieren
}

void loop() {
  now=rtc.now();
  measVoltage();          //Spannungssensor
  measTemp();             //Temperatursensor
  controlFan();           //Lueftersteuerung
  measCurrent();          //Stromsensor
  showTime();             //RTC(Real-Time-Clock)
  writeSD();              //SD_Card
  controlLED();           //LEDs steuern
  serialPrint();
  delay(5000);
}


void measVoltage(){
  adc_value=analogRead(ANALOG_IN_PIN);
  adc_voltage=(adc_value*ref_voltage)/1024;
  in_voltage=adc_voltage/(R2/(R1+R2));
  }
  
void measTemp(){
  tempRead = analogRead(pinTempSensor);
  float R = 1023.0/(0.97*tempRead)-1.0;
  R = R0*R;
  temperature = 1.0/(log(R/R0)/B+1/298.15)-273.15; // convert to temperature via datasheet
  }
  
void controlFan(){
if(temperature>30.0){
  analogWrite(fanPin,150);}
  else {analogWrite(fanPin,0);
    }
  }

void measCurrent(){
  readCurrent=analogRead(currentPin);
  currentValue=10*((4.50/951.00)*readCurrent)-25.1;       //Strom=10xSpannungswert-25,1 (c=25.1, m=0.1)
  }

void showTime(){
    Serial.print(now.day(), DEC);
    Serial.print("/");
    Serial.print(now.month(), DEC);
    Serial.print("/");
    Serial.print(now.year(), DEC);
    Serial.print("  ");
    Serial.print(now.hour(),DEC);
    Serial.print(":");
    Serial.print(now.minute(),DEC);
    Serial.print(":");
    Serial.print(now.second(),DEC);
    Serial.println();
  }

void writeSD(){
  myFile = SD.open("datalog.txt",FILE_WRITE);         //Create/Open file
  if (myFile){                                        //if the file opened okay, write to it
    myFile.print(now.day(),DEC);
    myFile.print("  ");
    myFile.print(now.month(),DEC);
    myFile.print("  ");
    myFile.print(now.year(),DEC);
    myFile.print("  ");
    myFile.print(now.hour(),DEC);
    myFile.print("  ");
    myFile.print(now.minute(),DEC);
    myFile.print("  ");
    myFile.print(now.second(),DEC);
    myFile.print("  ");
    myFile.print(in_voltage);
    myFile.print("  ");
    myFile.print(temperature);
    myFile.print("  ");
    myFile.print(currentValue);
    myFile.println();
    
    myFile.close();
    }
    else{                                            //if the file didn't open, print an error
      Serial.println("Error opening file");
    }
  //Reading the file:
//      myFile=SD.open("datalog.txt");
//      if(myFile){
//        Serial.println("Read: ");
//        //Reading the whole file
//        while (myFile.available()){
//          Serial.write(myFile.read());
//          }
//        myFile.close();
//        }
//        else{
//          Serial.println("Error opening file");
//}
  }

void controlLED(){  
  if(in_voltage>12.8){
    digitalWrite(led1Pin,HIGH);
    digitalWrite(led2Pin,HIGH);
    digitalWrite(led3Pin,HIGH);
    digitalWrite(led4Pin,HIGH);
    digitalWrite(led5Pin,HIGH);}
    else if(in_voltage<=12.8&&in_voltage>12.5){
      digitalWrite(led1Pin,HIGH);
      digitalWrite(led2Pin,HIGH);
      digitalWrite(led3Pin,HIGH);
      digitalWrite(led4Pin,HIGH);
      digitalWrite(led5Pin,LOW);}
        else if(in_voltage<=12.5&&in_voltage>12.2){
        digitalWrite(led1Pin,HIGH);
        digitalWrite(led2Pin,HIGH);
        digitalWrite(led3Pin,HIGH);
        digitalWrite(led4Pin,LOW);
        digitalWrite(led5Pin,LOW);}
          else if(in_voltage<=12.2&&in_voltage>12.0){
          digitalWrite(led1Pin,HIGH);
          digitalWrite(led2Pin,HIGH);
          digitalWrite(led3Pin,LOW);
          digitalWrite(led4Pin,LOW);
          digitalWrite(led5Pin,LOW);}
            else if(in_voltage<12.0){
            digitalWrite(led1Pin,HIGH);
            digitalWrite(led2Pin,LOW);
            digitalWrite(led3Pin,LOW);
            digitalWrite(led4Pin,LOW);
            digitalWrite(led5Pin,LOW);}
  } 

void serialPrint(){
Serial.print("Spannung: ");
Serial.println(in_voltage,2);
Serial.print("Temperatur: ");
Serial.println(temperature);
Serial.print("Strom: ");
Serial.println(currentValue);
Serial.println();
  }

The way that your code is posted it is difficult to copy to a text editor or the IDE for closer examination. Read the forum guidelines to see how to properly post code. Please edit your original post to include code tags on the code.
Use the IDE autoformat tool (ctrl-t or Tools, Auto format) before posting code in code tags.

The photo is not very helpful. A schematic would be.

analogReference(EXTERNAL);

Have you monitored your reference to make sure that it is steady at all times?

It looks like you are using an external reference , as noted above , with the Arduino rather than the internal reference - what is it , how is it wired , why are you using it ?.
Using and passing current through a bread board is liable to cause voltage drops ( eg in the 0v lines ) which are reflected in your measurements .

You also need to check that doing a lot of maths on a analog signal does not loose the resolution of that signal , using floats, taking logs etc on a integer ( 1 part inn1024) derived signal creates warning signals.
Start simple and print out the raw analog values to see what’s happening

Thanks for the note, i edited the post.

I haven't monitored the reference voltage over a longer period of time, but everytime i checked it has been the same.
I don't get why i would change, i don't have any active load connected at all so there is literally nothing going on.
The reason i'm using the external reference voltage is to have a stable and reliable reference since i was told the internal reference can change quite a lot when loads are active (right now that really didn't work out, haha).

The connection is the standard LM4040 connection as should below. It's basically a 5V reference, but it drops to 4,84V since i'm powering it with only the 5V arduino output.

Either you misunderstood or whomever told you that is mistaken. The default analog reference can change with load on the power supply because the default reference is Vcc. The 1V1 internal analog reference is stable, but its initial value can be ±0.1V. So, for instance the 1.1V internal reference can be 1.0V to 1.2V. To be accurate, measure the analog reference and use the measured value in computations. The reference voltage will be stable at the measured value even if Vcc varies. There are other values of internal Vref for other procesors. See the analog reference page.

That said, an external reference can be more accurate.

Unfortunately, i'm getting very fluctuating readings, from 12.40V one day to suddenly 13.10V the next day. There is no charger connected.

Those data look like normal noise and battery chemistry to me.

The LM4040 is a very stable device. I see no reason you shouldn't use it.
Can you tell us exactly how it is connected?

  • which Arduino pins? Is the wire from the LM4040 common connected directly to the Arduino pin or does it go through the plug in breadboard?
  • Wire lengths.

It appears the voltage change is driving the current change.

Should we assume the current comes from the 12V battery? How is the current generated?
What else is connected to your circuit?
What is the function of the USB cable in your test?

I’d check the operation of that reference I’m not sure you can operate with such a low supply voltage and get a stable output - it has virtually no voltage overhead to control and with low supply conditions may not have enough current to operate ( don’t forget the input load to the Arduino )

The LM4040 is based on the TL431 which is a shunt regulator. It is supposed to work down to 45µA.
Yet it is still a possibility.

You need at least 5.5 to 6V on the LM4040 cathode, if the supply V fell below 5V the LM4040 cannot amplify it back up to 5. I would use a 4.096V LM4040. You have a 5:1 divider so 12V will be reduced to 2.4V.

I guess the OP needs to verify if the 4.096 was used (LM4040-4.1 was in the original post) or a 5V device.

@ma_wu
Please verify the reference voltage on your sketch is 4.04 not 4.84 :slight_smile:
If it is 4.84 and the LM4040 is a 4.1 then there is an issue that needs to be remedied.

Hello again,

first of all thank you so much for the answers, it helps me narrow down the problem!

I've monitored the system for the past 4 days again, this time with the default reference Vcc.
It looked fine the first 3 days but on the 4th there have been massive fluctuation again. Again, nobody touched the system in any way.

I might have an idea where the problem is coming from:
I was there this morning when the system was still inacurate and measured Vcc, it was 5,08V at that time. Some hours later it dropped to 5.02V. So it makes sense that the AnalogRead differs.
That's why i wanted to use the LM4040, but unfortunately i purchased the 5V-Version.
Because there is hardly an overhead driving a 5V-reference from Vcc, the voltage dropped as mentioned before to 4,84.
When Vcc went up above 5V to 5,08V, i think the LM4040's reference voltage has also risen, since it is supposed to provide 5V.

I can't confirm this yet but could this be the case?
I could try getting a 4,096V reference, but that means that i can only measure voltages up to 4,096V? Or is there another way to get a stable reference while being able to use the "full range" of the arduinos 5V?

Thanks in advance.

I don't remember which Arduino that you are using.

You still have the internal reference. Have you tried it? Resistor voltage divider(s) to bring the signal(s) to less than 1V for the 1.1V reference. Enable the internal 1V1 reference, measure the Vref, use the measured value in your calculations.

There are other built in internal reference voltages depending on the chip.

Try 1k resistor series with signal on Ao and A1, and 100nf to ground on A0, A1

It seems OP wants to measure voltage and current of a 12volt SLA battery.
Voltage can be done with 1.1volt Aref,
but the ACS current sensor that OP has must be used with default Aref.
Better to ditch all those sensors, and switch to an I2C sensor made for the job,
like an INA 226 (16-bit) or INA219 (12-bit) breakout board.
Leo..

You can:

  1. Try to power the Arduino with 5.5V and use your current reference.
  2. Use the current reference and divided it down to 4.1 volts or so. Add a 0.1 µF cap on the external input pin.
  3. Use the 1.1V internal reference and divide down the inputs to be below 1.1V.
  1. Try to power the Arduino with 5.5V and use your current reference.
  2. Use the current reference and divided it down to 4.1 volts or so. Add a 0.1 µF cap on the external input pin.
  3. Use the 1.1V internal reference and divide down the inputs to be below 1.1V.

I've now used a 9V DC power supply to power the arduino as well as my 5V voltage reference. It seems to be now at 5V, as supposed to.

Unfortunately, i still get messy inputs:

I've monitored the actual battery voltage with a solar charger, it did definitely not break down like this.

I will try adding a 10µF (only one i have available atm) capacitor to the external input next...

This is so frustrating :pensive:

I think I have a simple test that might help.

Can you monitor a 1.5V battery with another Ax input? Print/plot out the raw A/D readings.

I will assume a 1.5V alkaline battery will not change much over a day or 2 test, and it will not jump up and down.

Good idea, I will try this the next couple of days

Looking at your picture - you have long wires which can pickup the noise, use twisted pairs or shielded cable for signal wires.