High(er?) Resolution Voltage Divider

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.

/*
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);
}
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

  long voltage1 = vol1 * 330 / 102300;

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

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

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 [u]Serial.print()[/u] 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.)

New code:

/*
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.

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.

Is there such example for AC voltage ?

vvarrior:

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 ..... [u]Analog Read Voltage Example[/u] 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.

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?

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

Allan

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?

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.

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.

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.

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).

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:

wvmarle:
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?

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.

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.

/*
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.

float cF = 0.0048399345703125; // 5/1024; // ADC factor is 5V

Are you powering the Nano from USB?
Then this is not correct.
VCC of a Nano on USB power is more like ~4.6volt.
So cF is about 0.0045 (more decimal places is useless).

Doesn't make a difference though, because you're just getting a meaningless voltage value.
Maybe easier to just work with (equally meaningless) A/D values.
Leo..

Not expensive. Pretty cheap, really. Two resistors, three caps and a simple EC probe. That's all it takes. The magic happens mostly in software. It does need three pins. Expected price USD 5-10 including probe. Cheap enough I can probably forego the kickstarter route even. Also working on building a version with I2C interface version that includes temperature sensor, so it can be sold calibrated and with temperature correction all ready to go. Ideally also adding a pH sensor to it, but that's for a little later.

You need to get your resistor to be about the same as the resistance your probe sees. You can't calculate this, you have to measure this. Be aware that after 1 ms of applying current in one direction the resistance you measure starts to change, so your measurements are off.

The easiest is to calibrate using an NaCl solution (kitchen salt). A 1000 ppm solution gives an EC of 2 mS/cm. Just see what resistance you get.

I've been trying to get this to work on Raspberry Pi using ADC module but I've switched over to Arduino as price is about the same. Since I've gotten close with the RPi and have all of the calculations and calibrations in Python on RPi (including temp), I'll probably keep it all there and just use Arduino to return raw values and calculate on RPi side with Python - leaving the thermometer there as well. I'll need all 8 analog channels on Arduino for other sensors.

I am very interested in your probe and if you've got a kickstarter idea to launch it, please include it on the forum. I will contribute. Do the three channels the probe needed include the thermometer? I know for my project I need all 8 analog channels for the 4 four sensors but if I can get EC and pH probe in 4 channels it would work (or there might be other work arounds).

Wawa: Arduino Nano is powered through USB. What is the best way to get the most accurate voltage reading before the sensor for comparison?

Instead of using a resistor in series with the medium you are testing, to form a voltage divider, another technique is to use a constant current source [or sink]. Then, measure the voltage across the medium [or even, across the current regulator]–a voltage magnitude that will be directly proportional to the resistance in the medium. With a pure resistor voltage divider, there is a more math intensive inverse proportionality.

Also, with a constant current, you might be able to get away with a lower current, and still have a workable range.

Also, with a constant current circuit, it’s easier to adjust the voltage range, and thus take advantage of such things as the internal voltage reference, for an increase of resolution.

It’s still a voltage divider, but the current source/sink behaves like an infinite resistance. And, because the current remains constant, it can, perhaps [because I have no experience with sensors of this sort], be set to a level just below the electrolysis point, and it will stay there over the whole usable range.

If it’s a current source, then the current source is the upper “resistor” [in the voltage divider], and the medium is the lower resistor. A current sink will be the other way around.

BUT, this probably is too expensive a solution for the OP. I guess it comes down to gain of feature vs increased cost.

Check out my Blog where I talk about Current Sources:

http://www.sinistercircuits.com/Blog/LEDs_LightemWithoutSmokinem/index.php#sec__current_source

Three digital pins is what you need for the EC sensor. Temperature sensor is separate - can be analog (NTC, TMP35/36) or digital (DS18B20), doesn't matter really, as in the end all that's really important is the temperature value.

The I2C version is a very different animal. It's to be built around an ATtiny, so all you need is the connection to the I2C bus, with the ATtiny taking care of everything else (reading the probes, calculating EC based on the measurement and calibration data, temperature compensation). That would probably include an NTC temperature probe, and maybe even a pH circuit. I have the circuit designs and the parts, just not had the time to actually build and test it. It's a long term target.

ReverseEMF:
It's still a voltage divider, but the current source/sink behaves like an infinite resistance. And, because the current remains constant, it can, perhaps [because I have no experience with sensors of this sort], be set to a level just below the electrolysis point, and it will stay there over the whole usable range.

Electrolyses starts at about 1V, I forgot the exact number. It's just part of the problem. The other part is the migration of ions due to the current, the positive ions cluster around the negative pole, the negative ions around the positive pole.This causes changes in the resistance, and is the primary reason to use AC: the constant changes in direction prevents ions from moving. The minimum frequency is 1 kHz, better go for 3 kHz or more. On the other hand over about 300 kHz, and certainly over 1 MHz, it doesn't work well any more. I don't know what happens, but the conductivity goes down. The highest frequency I've reached in testing was some 950 kHz, and that was for a 3.1% salt solution (a little above seawater). The 555 I use can reach 2.7 MHz, and the ATtiny can measure up to 4 MHz (it's running at only 8 MHz), so there's plenty of room :slight_smile: