Change AREF from EXTERNAL to DEFAULT on the fly

I need to measure 2 voltages. One battery voltage of 42 Volts which would be reduced to 4.2V using potential divider(measurement range 42V to 30V = 4.2V to 3.0V)
Other is from current sensor ACS712-30A( measurement range 1V to 2.8V). For battery voltage I need to set the AREF to DEFAULT and for Current set AREF to EXTERNAL 3.3V available on the Arduino Nano board. Can I short the 3.3V pin to AREF pin or I would need to use a resistor, what value?
Can I use the following code

unsigned long startMillis;        //some global variables available anywhere in the program
unsigned long currentMillis;
const uint8_t period = 100;      //the value is a number of milliseconds

void power_calc(){

  unsigned long int wt = 0;
  float Vbatt = 00.00;
  float current = 00.000;
  uint8_t Samples = 64;
  uint16_t vADC = 0, aADC = 0, aADC_midpoint = 776;// midpoint 776@Aref=3.3V External, midpoint 512@Aref DEFAULT

 
  analogReference(DEFAULT);   // Change ADC reference voltage to DEFAULT = Vcc
  for (uint8_t i = 0; i < 3; i++){	// Stabilize the ADC
    // Battery Voltage
    vADC = analogRead(A0);                                                         // Read A0 for voltage
    delay(1);
  }
  delay(5);
  for (uint8_t i = 0; i < Samples; i++){
    // Battery Voltage
    vADC = analogRead(A0);                                                         // Read A0 for voltage
    Vbatt += (float)(vADC * (5.00/1024));
  }
  
  analogReference(EXTERNAL);    // Change ADC reference voltage to EXTERNAL = AREF = 3.3V
  for (uint8_t i = 0; i < 3; i++){ // Stabilize the ADC
    aADC = analogRead(A3);
    delay(1);
  }
  delay(5);
  // Battery Current. read output of ACS712
  for (uint8_t ii = 0; ii < Samples; ii++){
    aADC = analogRead(A3);                                                       	 // Read A3 for current
    // ACS712-30A = 66mV/A(0.066), 20A = 100mV/A(0.1)
    if (aADC > aADC_midpoint){                                                       // Battery Charging
      current = (float)(current + (((aADC - aADC_midpoint) * (3.300/1024)) / 0.066)); 
    }
    else if (aADC <= aADC_midpoint){                                                 // Battery Discharging
      current = (float)(current + (((aADC_midpoint - aADC) * (3.300/1024)) / 0.066));
    }
  }
  
  if (aADC > aADC_midpoint){
    sign = '+';                                                             // Battery charging
    charging_flag = 1;                                                      // show that battery is Charging
  }
  else if (aADC <= aADC_midpoint){
    sign = '-';                                                             // Battery Dischargingharging
    charging_flag = 0;                                                      // show that battery is Discharging
  }
  Vbatt = (float)(Vbatt / Samples);
  current = (float) (current / Samples);
}

void loop() {
  
  currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
  if ((currentMillis - startMillis) >= period){  //test whether the period (200mSec) has elapsed
    startMillis = currentMillis;                 //IMPORTANT to save the start time.
    power_calc();                                // Run Voltage, Current and Wattage Calculations
  }
}

if you change to int16_t then you can write

as

current = float(current + abs(aADC - aADC_midpoint) * 0.048828125); 
  if (aADC > aADC_midpoint){
    sign = '+';                                                             // Battery charging
    charging_flag = 1;                                                      // show that battery is Charging
  }
  else{
    sign = '-';                                                             // Battery Dischargingharging
    charging_flag = 0;                                                      // show that battery is Discharging
  }
current = float(current + abs(aADC - aADC_midpoint) * 0.048828125);

5V/1024=0.048828125 but I am using analogReference(EXTERNAL) which is 3.3V not 5V so it should be 3.3V/1024 = 0.00322265625

0.00322265625 / 0.066 = 0.048828125

Not how I would do it.

Assuming Arduino Uno R3...
Voltage is better measured not with default Aref, but with internal 1.1 (or external 3.3).
Current sensor is better measured with default Aref, to preserve ratiometric behaviour.

If you measure an ACS712 with a stable voltage (3.3volt), then the output of the A/D also gets dependent of the supply voltage of the ACS, which you don't want.
Leo..

Can I switch between Default and External reference in the code with External voltage applied on Aref pin always? Can I directly connect the 3.3v pin to Aref?

No, at least for some ADC designs, like the original AVR-based Arduinos. See this warning on the official Arduino reference page for analogRead():

If you’re using an external reference on the AREF pin, you must set the analog reference to EXTERNAL before calling analogRead(). Otherwise, you will short together the active reference voltage (internally generated) and the AREF pin, possibly damaging the microcontroller on your Arduino board.

i would use ADS1115.

1 Like

For the voltage measurement, but not for the ACS712.
The ACS is a ratiometric sensor, so it's output depends on current and supply voltage.
You should measure the ACS with a ratiometric A/D (default Aref on an Uno).
The ADS has an absolute A/D.
Leo..

ah, ok
1 year ago i made realy as you said

No, not directly. that will damage Aref.
You can however use a resistor between 3.3volt and Aref if you want to do that. The Uno R3 datasheet recommends a minimum value of 5k6 if I remember correctly. That will drop that 3.3volt Aref to about 2.8volt though (Ri of Aref is 32k, so 32/(32+5.6)*3.3= 2.8).
Still a bad idea to lower Aref for the ACS. You're trading resolution for accuracy/instability.
Something like an INA169 with shunt, and an ADS1115 could be a better solution.
Leo..

Why not divide 42V down to 3.2V and use 3.3V AREF?
R1 = 47k, R2 = 3.9k.

Why not divide ~5V supply voltage down to ~3.31V and use that for AREF?
R1=5.1K, R2 = 10k.

Ri of Aref is 32k, so that divider won't work.
A single 18k resistor between 5volt and Aref would work.
Leo..

1 Like

Noted, TNX

The ACS is ratiometric means it output is dependent on the VCC. If we assume the ACS output changes 1V/A(though it is 0.066mV/A) for simplicity purpose. If it is powered by 5V the no input current output voltage would be 2.5V and 3.5V or 1.5V for an input current of 1A depending on the direction. But if the ACS was powered by 4V the no current output would be 2V and 3V & 1V for 1A input current flow.
Similar for Arduino. If it works on 5V the ADC read value would be 512 for 2.5V and if it works on 4V the ADC value for 2.5V would be more than 512 for default analogReference.
If the Arduino analogReference is External sturdy 3.3V the VCC of the Arduino would not have any effect on the ADC read value. Similarly the ADS1115 has a fixed reference voltage so its output is not effected by its VCC.
Using an ratiometric ADC for ratiometric device like ACS and not an absolute ADC makes sense when the VCC is unstable.
My unit consisting of the Arduino Nano, ACS712-30A and LCD display is powered by 42V-18aH battery. The 42V is brought down to 12V through a series regulator which is fed to the input of 7805-1A regulator. The maximum current drain with LCD backlight is 50mA. So the VCC is very sturdy(4.99V as measured on digital multimeter).
First I thought I will connect the 3.3V pin to the Aref pin via a Germanium diode which would give me 3V on the Aref pin. When I switch to default analogReference the 5V on the Aref pin would be blocked by the diode from reaching 3.3V pin. Now I am considering the ADS1115.

Seems to be the best option for sturdy VCC. Even in default mode the 5v that would be available on the Aref pin would not affect the VCC as its the same voltage potential.

No.
The no current output would be 2volt, and 2.8volt/1.2volt for 1A.
Not only the offset is affected, but also the gain.
It changes from 1volt/A at 5volt to 4/5 * 1volt = 0.8volt with a 4volt supply.

A ratiometric 10-bit A/D would change from 5/1024 = ~5mV/step to 4/1024 = ~4mV per step, thus getting more sensitive and compensating for the drop in voltage of the sensor.

Not sure why you're going through all this trouble for a sensor with a possible error of 1.5%.
Leo..

Warning! The UNO will output the AVCC or 1.1V to AREF when one of these is selected. If you have connected a voltage source to that pin the current is undetermined, that means: it can blow up your processor.