Go Down

Topic: High(er?) Resolution Voltage Divider (Read 373 times) previous topic - next topic

vvarrior

I am using a Raspberry Pi to turn on a 3.3 output pin, then using Arduino Nano to read a voltage divider. How do I read the voltage in higher resolution (2.131235) than 2.1?

The raw analog output is 717-720. The output for my conversionFactor is 0, whether I use int or long.

Code: [Select]
/*
Print output for voltage divider
*/
int v1 = A0;
int v2 = A1;
int conversionFactor = 3.3/1023;
void setup() { // Function to setup serial
  Serial.begin(9600);
}
// the loop routine runs over and over again forever:
void loop() {
  // read the input on analog pin 0:
  int vol1 = analogRead(v1);
  int vol2 = analogRead(v2);
  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 3.3V):
  long voltage1 = vol1 * conversionFactor;
  long voltage2 = vol2 * conversionFactor;
  // print out the value you read:
  Serial.print("v1:");
  Serial.print(conversionFactor);
  Serial.print("|v2:");
  Serial.print(voltage2);
  Serial.println();
  delay(1000);
}

olf2012

Code: [Select]
int conversionFactor = 3.3/1023;

You are storing the result of a floating point operation into an int. This will truncate the value to 0. Use this calculation instead
Code: [Select]
  long voltage1 = vol1 * 330 / 102300;


DVDdoug

The resolution of the 10-bIt ADC is 1023 steps.   That's about 5mV with the 5V reference.

And, use type float like the Analog Read Voltage Example if you don't want to loose resolution.  

Code: [Select]
int conversionFactor = 3.3/1023;
That's not correct with the default 5V reference  (and you shouldn't be using in integer).

You can change a parameter in Serial.print() to determine the precision of the printed result.   (But, don't be fooled into thinking you can get more than 10-bit resolution from the ADC.)

vvarrior

New code:
Code: [Select]
/*
Print output for voltage divider
*/
int v1 = A0;
int v2 = A1;
float conversionFactor = 3.3/1023;
void setup() { // Function to setup serial
  Serial.begin(9600);
}
// the loop routine runs over and over again forever:
void loop() {
  // read the input on analog pin 0:
  float av1 = analogRead(v1);
  float av2 = analogRead(v2);
  // Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 3.3V):
  float avc1 = av1 * conversionFactor;
  float avc2 = av2 * conversionFactor;
  // print out the value you read:
  Serial.print("v1:");
  Serial.print(avc1,8);
  Serial.print("|v2:");
  Serial.print(avc2,8);
  Serial.println();
  delay(1000);
}


Changed everything to float and added 8 to the print function. The print portion was my error.

jremington

#4
May 20, 2018, 08:12 pm Last Edit: May 20, 2018, 08:13 pm by jremington
Quote
added 8 to the print function
Float or double variables on Arduino are sometimes  accurate to 7 decimal digits, but you can usually count on 6.

ted

Is there such example for AC voltage ?

Southpark

#6
May 20, 2018, 10:43 pm Last Edit: May 23, 2018, 02:44 am by Southpark
Code: [Select]

int conversionFactor = 3.3/1023;

The "long" format for conversionFactor (instead of "int") was discussed already, which is nice. And the "5V" value was discussed as well, which means that it'll be a good idea to indicate why you used a '3.3' value in the first place.

Also, if you want to follow the same way that the internal D-to-A hardware (of the successive approximation A-to-D) does its digital to analog voltage conversions........which is what the hardware actually does (internally) .... then go for:

5/1024

Whoever put in '1023' at this site here accidentally got it wrong ..... Analog Read Voltage Example  and it should be amended so that it becomes '1024'.

(google resistive ladder, R-2R digital to analog conversion etc.)

It's not going to make much difference which one you use, but good to know that the hardware involves 5/1024 (for the voltage resolution). So if the hardware operates in that way, then might as well use the formula associated with it. And - when doing A-to-D, we don't usually make the input signal (or voltage) go all the up to roof (ceiling) anyway.

vvarrior

I am using 3.3v instead of 5v because I need to shut off the sensor. I am testing the electrical conductivity of water, as well as pH. Testing conductivity throws off the pH reading.

And just to clarify, I want to use 3.3/1024 instead of 1023?

allanhurst

I hope you're not trying to measure pH and conductivity with the same electrodes....


Allan

Southpark

#9
May 21, 2018, 12:49 am Last Edit: May 21, 2018, 04:19 am by Southpark
I am using 3.3v instead of 5v because I need to shut off the sensor. I am testing the electrical conductivity of water, as well as pH. Testing conductivity throws off the pH reading.

And just to clarify, I want to use 3.3/1024 instead of 1023?
The 3.3 and 5 V values are specific to the analog to digital converter module inside your microprocessor system (--- and ... the A-to-D converter does contain a D-to-A as well). Eg....  the arduino nano A-to-D converter is based on a 5V voltage range, right?

This just means, you need to know in advance whether the hardware's voltage range is 5V or 3.3V. This is generally not a user-setting. It's determined by the hardware you have.

So if you're using an uno or mega, or nano, then the voltage range is 5V. So the voltage resolution will be 5/1024 (in the hardware).

Correct ....... use 5/1024 .... not 5/1023.

wvmarle

I am using 3.3v instead of 5v because I need to shut off the sensor. I am testing the electrical conductivity of water, as well as pH. Testing conductivity throws off the pH reading.
That's normal. Ground loops. Putting caps in your EC probe connection can help a lot (what probe/sensor are you using for this?) as it stops DC currents. With my EC probe in the water hose and the pH probe in the reservoir I don't have any such issues; haven't yet tried to put the EC probe in the reservoir.

Quote
And just to clarify, I want to use 3.3/1024 instead of 1023?
No - 5/1024. But you're probably losing a lot of precision here.

First of all: find the ACTUAL voltage range of your pH probe output. There's probably an offset applied, but the output of a pH probe is only about 60 mV/pH point. That's 12 ADC points for 1 pH point shift. You want this offset to be as low as possible, so the highest pH value you measure gives an output close to 0V, and the lowest pH gives an output of <1V.

This way you can use the internal 1.1V reference. Two advantages: much more stable reference voltage (independent from fluctuations in Vcc; your pH probe produces an absolute voltage anyway), and a much better range (1 pH point is now 60 ADC points).
Quality of answers is related to the quality of questions. Good questions will get good answers. Useless answers are a sign of a poor question.

ReverseEMF

I don't have time to go into detail, but, you might be able to fineggle more resolution by using the Internal reference and a voltage divider.  This is talked about, here:

https://arduino.stackexchange.com/questions/36865/does-adc-conversion-to-a-voltage-rely-on-the-actual-value-of-the-5-v-pin/36899
1.21 GIGAWATTS?!?

| Please DON'T Private Message to me, what should be part of the Public Conversation -- especially if it's to correct a mistake, or contradict a statement!  Let it ALL hang out!! |

vvarrior

That's normal. Ground loops. Putting caps in your EC probe connection can help a lot (what probe/sensor are you using for this?) as it stops DC currents. With my EC probe in the water hose and the pH probe in the reservoir I don't have any such issues; haven't yet tried to put the EC probe in the reservoir.

No - 5/1024. But you're probably losing a lot of precision here.

First of all: find the ACTUAL voltage range of your pH probe output. There's probably an offset applied, but the output of a pH probe is only about 60 mV/pH point. That's 12 ADC points for 1 pH point shift. You want this offset to be as low as possible, so the highest pH value you measure gives an output close to 0V, and the lowest pH gives an output of <1V.

This way you can use the internal 1.1V reference. Two advantages: much more stable reference voltage (independent from fluctuations in Vcc; your pH probe produces an absolute voltage anyway), and a much better range (1 pH point is now 60 ADC points).
I haven't gotten to messing around with the pH probe yet but I will soon. I am still working on the EC probe. For the EC probe, I am using a regular plug documented here: Plug EC
I am using this probe for pH: pH Probe

I will note your suggestions when beginning pH testing, Thank you.

From what I understand, EC is a lot more sensitive than pH. Given that, it sounds like it's a good idea to use the 1.1V internal reference for EC as well. Have you had luck with this?

wvmarle

Ah, that one. I know it, looked at it. Very scary as you use a regular power plug (so someone may plug it in for whatever reason).

Range and accuracy are low for this technique as it's a voltage divider. Best accuracy is when your liquid's resistance is about the same as the other resistor's value. Also it uses DC which is bad for EC measurements. You have to use AC (1-1000 kHz). If using DC you will find that over the first few seconds the EC you measure changes considerably, and you will see bubbles forming at your probe (a sign of electrolysis).

My main focus has been on building an EC probe by timing the discharge of a small capacitor, and using the same cap to produce an AC current through the liquid. Getting excellent results, now got a bunch of test probes running here, and hope to turn this in a product really soon. Getting quite ready for that. Accuracy is about 2% over two orders of magnitude (0.05-5 mS/cm - typical hydroponic range - can measure higher with lower accuracy as well).

A second technique I'm now employing is by using a 555 timer, I'm getting a range of 0.001-100 mS/cm with little effort, and first results also indicate 1-2% accuracy. Needs more thorough testing, especially on long term stability.

Very important is temperature compensation, as the EC increases by about 2% for each 1 degree C increase in temperature for most ionic solutions. pH is also temperature dependent but less strongly.
Quality of answers is related to the quality of questions. Good questions will get good answers. Useless answers are a sign of a poor question.

vvarrior

#14
May 23, 2018, 08:45 am Last Edit: May 23, 2018, 08:48 am by vvarrior
Impressive. I'd like to take a look at your product when it becomes available or you're looking for someone to test it. I'm not worried about my probe being plugged in because I am the only one working with it.

The main reason I'm using DC  is because once everything is tested and working properly, I am going to deploy a large number of these and can't afford the significant price of an AC probe for each one.

I will know the target resistance value of the water solution. You're saying it is most accurate when the resistor is close to what the EC of the water should be correct?

Target EC should be between 700 (max) and 800 ohms and will alert around 1500 (min) ohms - if all of my calcs are correct. Would you mind looking at this code and telling me where I'm going wrong? It seems like I'm missing a resistor value (146~?). cF is actually 4.956093/1024 because that's the value I'm getting when I ground the voltage divider. - correct me if I'm wrong. And I have a 2200 ohm resistor at the end of the probe.

Code: [Select]
/*
Print output for voltage divider
*/
int v1 = A1;
int v2 = A0;
float cF = 0.0048399345703125; // 5/1024; // ADC factor is 5V
int vdPin = 7; // Pin to voltage divider
int sD = 5000; // delay in milliseconds to loop sensor
void setup() { // Function to setup serial
  Serial.begin(9600);
  pinMode(vdPin, OUTPUT); // output digital pin
}
// the loop routine runs over and over again forever:
void loop() {
  digitalWrite(vdPin, HIGH); // turn sensor on
  delay(1000); // Let sensor voltage settle
  // read the input on analog pin 0:
  float av1 = analogRead(v1);
  float av2 = analogRead(v2);
  // Convert the analog reading (which goes from 0 - 1024) to a voltage (0 - 5V):
  float avc1 = av1 * cF;
  float avc2 = av2 * cF;
  Serial.print(cF,6);
  Serial.print(" - v1: raw(");
  Serial.print(av1);
  Serial.print(") ");
  Serial.print(avc1,6);
  Serial.print("|v2: raw(");
  Serial.print(av2);
  Serial.print(") ");
  Serial.print(avc2,6);
  Serial.println();
  digitalWrite(vdPin, LOW); // turn sensor off
  delay(sD);
}


Attached is a diagram of my circuit.

Go Up