Problem measuring voltage with ADC and resistor network

Hi all,

I am trying to sample the voltage of an 50kHz AC source that can go from -25V to +25V. Trying to keep things simple I have built that little resistor network:

tic.JPG

I am expecting to find

Vin = R1CVadc - R1/R3 * Vcc
where C = 1/R1 + 1/R2 + 1/R3 and Vcc = +5V

I am reading from A0 with the ADC clock prescaler set to 32, keepingjust the 8 first bytes of the reading.

With Vin = +5V and Vin = 0V I get the exact expected reading. But negative voltages don't work so well, if I apply -5V for example I read Vadc = 2.3V which corresponds to Vin = -0.47V.

I must be missing something obvious?

Thanks!
Franck

tic.JPG

Yes you are, you are missing that 8 bit resolution for a 50V range gives a resolution of 0.2V,
And that your divider divides much too much. Try R1 = 4.7k

You mean “high order 8 bits”, not “first 8 bytes”.

My bad, I am indeed using 4.7k which I measured to 4.67k with my multimeter. Good point about the resolution, but the measurement is still way off?
I checked Vcc while measuring and it is at 5V as expected.. not sur what I am doing wrong.

Franck

Perhaps your error is due to a 50KHz signal being measured with a device that can only manage about 9K conversions a second?

Thinking the 50K Hz was a typo and you really mean 50 Hz…

As WattsThat suggested, the sample rate here is critical. Or at least you must understand the effects of sampling a fixed frequency signal with a different frequency sample rate.

Look at this link undersampling Ignore the math and look at the graphics. You can see what you will measure if you measure a changing signal either too slow or slightly too fast.

However, if you indeed mean 50KHz you will have to better define your measurement goal.

franck102:
My bad, I am indeed using 4.7k which I measured to 4.67k with my multimeter. Good point about the resolution, but the measurement is still way off?
I checked Vcc while measuring and it is at 5V as expected.. not sur what I am doing wrong.

Franck

First thing to check is that with the Arduino pin disconnected the centre of the divider shows the correct
voltages - if necessary check all the resistor values and their connections.

Then check again with the Arduino pin connected using multimeter that the voltages haven't changed.

And post your code of course...

I will do all that, thanks.

I should have clarified that while the eventual goal is to measure 50kHz AC (no typo, it’s a meter information bus), I am testing the circuit with DC right now.

Franck

MarkT:
First thing to check is that with the Arduino pin disconnected the centre of the divider shows the correct
voltages - if necessary check all the resistor values and their connections.

Then check again with the Arduino pin connected using multimeter that the voltages haven’t changed.

And post your code of course…

So with no input voltage connected, I measure Vadc=2.29V with my DMM, and that doesn’t change when I reconnect the A0 pin. The calculated value was 2.34V, so close enough.

Here is the code. I started with the ADC prescaler to 16, and I changed to 8 to see if that helped.
I am trying to implement the circuit described here (in French, sorry):

Having no oscilloscope (one is in the mail…) my goal was to get a histogram of the signal, to at least see if the peak voltages had chance of triggering the optocoupler.

#include <SPI.h>
#include <SdFat.h>

// #define DEBUG

#define SS_SD SS
#define PIN_LED 13

SdFat sd;
SdFile sdFile;
unsigned long started;
bool done = false;

Print *printer;
uint32_t values[128];
int sdBegin();
void blink(int count);

void setup()
{
    Serial.begin(9600);
    pinMode(PIN_LED, OUTPUT);

    ADCSRA = 0;             // clear ADCSRA register
    ADCSRB = 0;             // clear ADCSRB register
    ADMUX |= (0 & 0x07);    // set A0 analog input pin
    ADMUX |= (1 << REFS0);  // set reference voltage
    ADMUX |= (1 << ADLAR);  // left align ADC value to 8 bits from ADCH register

    // sampling rate is [ADC clock] / [prescaler] / [conversion clock cycles]
    // for Arduino Uno ADC clock is 16 MHz and a conversion takes 13 clock cycles
    ADCSRA |= (1 << ADPS2) | (1 << ADPS0);    // 32 prescaler for 38.5 KHz
    //ADCSRA |= (1 << ADPS2);                     // 16 prescaler for 76.9 KHz
    //ADCSRA |= (1 << ADPS1) | (1 << ADPS0);    // 8 prescaler for 153.8 KHz

#ifndef DEBUG
    if (!sd.begin()) {
        //Serial.println("SD card init failed");
        //sd.errorPrint();
    } else {
        // Serial.println("Initialized!");
    }

    if (!sdFile.open(sd.vwd(), "tic", FILE_WRITE)) {
        // Serial.println("Could not open file");
    } else {
        // Serial.println("File opened!\!");
    }
    printer = &sdFile;
#else
    printer = &Serial;
#endif
    started = millis();
    printer->print("Started at ");
    printer->println(started);
//
    ADCSRA |= (1 << ADATE); // enable auto trigger
    ADCSRA |= (1 << ADIE);  // enable interrupts when measurement complete
    ADCSRA |= (1 << ADEN);  // enable ADC
    ADCSRA |= (1 << ADSC);  // start ADC measurements
}

ISR(ADC_vect)
{
    if (!done) {
        values[ADCH >> 1]++;
    }
}

void loop()
{
    if (!done && millis() - started > 20000) {
        done = true;
        for (int i = 0; i < 128; ++i) {
            printer->print(5.0 * i / 128.0, 2);
            printer->print(": ");
            printer->println(values[i]);
        }
        printer->print("Closed at ");
        printer->println(millis());
#ifndef DEBUG
        sdFile.close();
#endif
        done = true;
        blink(3);
    }
}

void blink(int count)
{
    for (int i = 0; i < count; i++) {
        digitalWrite(PIN_LED, HIGH);
        delay(500);
        digitalWrite(PIN_LED, LOW);
        delay(500);
    }
}

Here are some sample outputs, everything looks right for positive voltages, but not for negative ones:

Vin = 0V DC:

2.23: 0
2.27: 815
2.30: 741916
2.34: 26180
2.38: 0

Computed: 2.34

Vin = +5V DC:

2.73: 0
2.77: 0
2.81: 769292
2.85: 0
2.89: 0

DMM: 2.77
Computed: 2.81

Vin = -5V DC:

2.23: 0
2.27: 721
2.30: 321853
2.34: 446718
2.38: 0

DMM: 2.26V
Computed: 1.88

If Vin comes from a LiPo (4.0V on the DMM both with no load and while sampling) the readings are correct:

Vin = -4V -> Vadc=1.92 which yields -4.53V
Vin = 4V -> Vadc=2.71 which yields 3.90V

... which made me realize that earlier I had an interaction between the Vin supply (9V AC/DC adapter to breadboard rail) and the circuit (through the second breaboard rail, even though its jumper was on "off").

I now get correct readings With Vin coming from the 9V adapter, and the Uno powered by the computer's USB.
When reading the meter's signal however I again get the positive bias - almost negative readings. I will try powering the Uno from the LiPo while doing the readings, see if that helps.
The meter's bus is supposed to have galvanic isolation from the rest of the meter, but who knows...

Franck

Reading the AC signal with the Uno powered from a battery powered laptop USB again yields readings between -0.8V and 5.4V...

Vcc looked stable at 5V, but of course it may be fluctuating with the AC signal an I can't see that with the DMM.

I am giving up, I'll wait for the small DSO I ordered. So much for my ADC-based poor-man's sampling machine :slight_smile:

Thanks!
Franck

franck102:
Here are some sample outputs, everything looks right for positive voltages, but not for negative ones:

Vin = 0V DC:

2.23: 0

2.27: 815
2.30: 741916
2.34: 26180
2.38: 0



Computed: 2.34

**Vin = +5V DC:**


2.73: 0
2.77: 0
2.81: 769292
2.85: 0
2.89: 0



DMM: 2.77
Computed: 2.81

**Vin = -5V DC:**


2.23: 0
2.27: 721
2.30: 321853
2.34: 446718
2.38: 0



DMM: 2.26V
Computed: 1.88

Definitely not getting -5V onto that first resistor then, or you've miswired your circuit.

I suspect you are using a +5V supply to try to generate -5V, but its not an isolated supply,
so you are simply shorting it out.

Correct, at the time I posted those numbers the supply wasn’t properly isolated. Since then I got everything working as expected with DC, but not with the signal, even though

  • the bus has galvanic isolation from the mains
  • the Uno was powered by the USB of a laptop running on battery

Franck

What's the ac source output impedance?

You need r2 and r3 to be equal to bias the signal to 2.5v. Try 900 ohms each and should keep it between 0-5v for full 25v.

wolframore:
You need r2 and r3 to be equal to bias the signal to 2.5v. Try 900 ohms each and should keep it between 0-5v for full 25v.

You forget R1 which is effectively in parallel with R2, and the fact that 900 ohms isn't a known resistor value.

I just ran it in simulation. Am I missing something?

You must have, the circuit is clearly not symmetrical (that's obvious by inspection, no need to turn
to simulation.) Did you drive the input at 0V, +25 and -25V?

To get 2.5V out with 0V in means R1 || R2 = R3, so R2 != R3

Just playing with a new sim software :D. Yes ran it with +/- 25v sine wave. Is there a dc offset I’m not aware of?

You have three resistors, one connected to 0V, one to +5V, one to 0V(+/-25V). This is obviously not symmetrical about 2.5V

Do you understand what I meant by "To get 2.5V out with 0V in means R1 || R2 = R3, so R2 != R3"