Arduino voltmeter calculations

I'm trying to use arduino with LCD as car voltmeter. I've got R1=33kohm and R2=15kohm resistors as voltage divider. So if voltage stays below 15V from alternator it wont break arduino by going over 5V(it is the Vmax for inputs?)

But i cant figure out the how to make it show voltage correctly. I've got R1 and R2 in A0.

I tried to do it with this but i dont know the right formula for me.

I've got now

value = analogRead(A0);
vout = (value * 3.4)/1024.0;  //voltage coming out of the voltage divider
vin = vout / (R2/(R1+R2));  //voltage to display

But i think i need the right value to replace 3.4?

But i think i need the right value to replace 3.4?

Whatever value is connected to Vref.

You mean Ref-pin? Nothing? :stuck_out_tongue:

How about 5 then?

I've tried that. But when fluke shows 6.9V at resistors, arduino shows 6.6V. Is it possible to make it accurate or do i just need to finetune that value? Or are 1% resistors just not right for it?

I'd leave the 5V as it is (assuming the supply voltage really is 5V) , and check that the values of resistors plugged into the potential divider equation are correct.

Arduino adc is max rated for 5.5v, so 6.9v is good to kill it.

He's right - I assumed when you wrote "at the resistors", you meant across the potential divider.

15Volt over 33K and 15K gives max 4.7 volt over the 15K resistor.
As Vref is not connected it uses 5Volt from the Arduino Power supply - you need to measure this as between 4.9 and 5.1 reference voltage = 4% difference!

raw = analogRead(A0);

// raw = 0..1024 representing 0..Vref volt

vout = 5.00 * raw / 1024.0; // as Vref = 5.0 Volt (to be measured)

convert to car voltage;

voltageCar = (vout / 15.000) * (15.000 + 33.000); // or in short voltageCar = vout * 3.2:

Please fill in the resistors measured values .

The final code could become

// these defines have to be measured
#define VREF  5.10
#define R1 32767.0
#define R2 15140.0

float raw = analogRead(A0);
float vout = VREF  * raw / 1024.0; 
float carVoltage = vout / R2 * (R1 + R2);  

// or in a oneliner
// float carVoltage = analogRead(A0) * VREF / 1024.0 / R2 * (R1 + R2);
// as VREF / 1024.0 / R2 * (R1 + R2); are all constants one could compact this to

carVoltage = analogRead(A0) * 0.01576; // used sample constants above.

-- updated layout --

I tried to add measured values from resistors but its still off. Can this even be very accurate? I've changed a bit of R1 and R2 values and now im tenth off comparing to fluke. I think im satisfied with this :stuck_out_tongue:

Thanks guys!

The precision of tha ADC of the Arduino is 10 bit, in practice the last bit may be inaccurate. That means you have approx 500 steps for 0..15 volt ==> at best 1/30 volt precission = 0,2% . Assume the resistors have an accuracy of 1% . suppose VREF has an accuracy of 2%.

Then - float carVoltage = analogRead(A0) * VREF / 1024.0 / R2 * (R1 + R2); - would give an max accumalate error of
0.2% + 2% + 0% + 1% + 1% + 1% = 5.2%

=> 15V * 5.2% = 0.8 Volt max error => so one tenth of is indeed very good.

Disclaimer not official error math, just an first order approximation.

One can improve the measurement by doing the AnalogRead multiple times:

float readVoltage()
  #define SAMPLES 3.0
  float rv = 0;
  for (int i=0; i< SAMPLES ; i++) rv += analogRead(A0);
  rv /= SAMPLES; 
  return rv * 0.01576;   // average of 3 reads times the calculated constant.

If time is not an issue one can take more samples ...