Sorry, here's the code. In essence, arduino is reading the voltage divider correctly up to a certain voltage, and then seems to lose 1V, regardless of the resistor configuration of the voltage divider.
I've originally had this running on a Pro Mini 3.3V, but have since tried on a Nano and the result it the same. It does make me also think the maths is off somewhere, but can't see where!
Don't know how much use the photo will be in terms of wiring, I can draw up a diagram if that will help?
main.cpp:
#include <Arduino.h>
#include "InternalVoltage.h"
#define VOLTAGE_SENSOR A0
#define R1Value 21850
#define R2Value 4670
float voltages[4];
uint8_t switches[4];
uint8_t counter = 0;
InternalVoltage internalVoltage;
void setup() {
internalVoltage.getInternalVoltage();
Serial.begin(9600);
Serial.println("START");
Serial.print("Internal Voltage: ");
Serial.println(internalVoltage.internalVoltage);
for (uint8_t i = 0; i < 4; i++){
switches[i] = i + 2;
pinMode(i + 2, OUTPUT);
}
pinMode(A0, INPUT);
}
void loop() {
digitalWrite(switches[counter], HIGH);
// delay(50);
float previous_cells = 0;
for (uint8_t i = 0; i < counter; i++)
previous_cells += voltages[i];
float reading = internalVoltage.readVoltageDivider(VOLTAGE_SENSOR, R1Value, R2Value);
voltages[counter] = reading - previous_cells;
Serial.print(counter);
Serial.print(" : ");
Serial.print(internalVoltage.voltageDividerReading);
Serial.print(" : ");
Serial.print(reading);
Serial.print(" = ");
Serial.print(voltages[counter]);
Serial.println();
digitalWrite(switches[counter], LOW);
counter++;
if (counter > 3)
counter = 0;
delay(600);
}
internalVoltage.h:
#ifndef _InternalVoltage_h
#define _InternalVoltage_h
#include <Arduino.h>
class InternalVoltage{
public:
void getInternalVoltage();
float readVoltageDivider(uint8_t pin, float R1, float R2);
void setOffset();
float internalVoltage = 5.0;
int voltageDividerReading = 0;
private:
uint32_t readVcc();
float decimalVoltage(float x, float in_min, float in_max, float out_min, float out_max);
float offset = 0.0;
};
#endif
internalVoltage.cpp:
#include <Arduino.h>
#include "InternalVoltage.h"
/**
* Public
*/
void InternalVoltage::getInternalVoltage(){
internalVoltage = decimalVoltage(readVcc(), 0, 6000, 0, 6);
}
float InternalVoltage::readVoltageDivider(uint8_t pin, float R1, float R2){
analogRead(pin); // 1st read switches pin to ADC but reading is unstable, esp. with high impedance voltage sources
delay(50); // wait for the voltage to settle and then do the actual reading
//float voltageReading = (getInternalVoltage() / 1023) * analogRead(pin);
voltageDividerReading = analogRead(pin);
float voltageReading = (internalVoltage / 1023) * voltageDividerReading;
delay(10);
return voltageReading / (R2 / (R1 + R2));
}
void InternalVoltage::setOffset(){
}
/**
* Private
*/
uint32_t InternalVoltage::readVcc() {
// Read 1.1V reference against AVcc
// set the reference to Vcc and the measurement to the internal 1.1V reference
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
ADMUX = _BV(MUX5) | _BV(MUX0);
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
ADMUX = _BV(MUX3) | _BV(MUX2);
#else
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#endif
delay(10); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Start conversion
while (bit_is_set(ADCSRA,ADSC)); // measuring
uint8_t low = ADCL; // must read ADCL first - it then locks ADCH
uint8_t high = ADCH; // unlocks both
uint32_t result = (high<<8) | low;
result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
return result; // Vcc in millivolts
}
float InternalVoltage::decimalVoltage(float x, float in_min, float in_max, float out_min, float out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}