Precision of resistor measurements...

Hi,

I'm trying to read some resistance values (resistive sensors) with an Arduino Due (3.3V). I'm using a voltage divider to avoid independence of voltage applied, using of course a reference resistor (1% tolerance) carefully measured but values obtained are far of real ones.

Example: temperature sensor (Irrometer 200TS, in range of interest -5ºC to 40ºC corresponds 40Kohm to 5 Kohm as per datasheet) Ref. resistor value is also provided by manufacturer. Connection to Arduino is as follows:

PWM2 pin - sensor - 7.87Kohm ref. resistor - GND

I'm using two analog inputs to measure voltage values:

  • between PWM2 pin and sensor (tSensorPWMValue)
  • between sensor and ref. resistor (tSensorRefValue)

In this way, sensor resistance can be calculated with following code:

// Power the temp. sensor divider
 digitalWrite(tSensorPower, HIGH);
 delay(10)
 
 // read the value from the temp. sensor:
 tSensorPWMValue = analogRead(tSensorPWMPin); // A0
 tSensorRefValue = analogRead(tSensorRefPin); // A1

tSensorResistor = (float) SensorRefResistor*(((float) tSensorPWMValue/ (float) tSensorRefValue)-1.0);

Measuring two points means we don't need to manage assumptions about effective voltage in PWM output. But real thing is that values obtained are very imprecise with errors between 5% to 10%.

Any idea about how to improve precision readings ? Is it possible at all ?

Regards,
joanba

I would start with 0.1% or better for the resistance involved in measuring.

I would also buy a few additional ones of that tolerance to calibrate the system. Or just pick one out of the 5% box and call it good. All future measurement will habe the same 5% error after calibration on that "good" one.

7k is quite high value, try with a cap 100 nF for decoupling at two resistors junction and ground.
Estimate self-heating of the resistors, give plenty of time after you touch a resistor with hands

Sounds like you need some smoothing / averaging, try summing 10 consecutive analog reads then divide that by 10.
What is the value of variable "SensorRefResistor"? Can you post a wiring diagram?

Your equation:

tSensorResistor = (float) SensorRefResistor*(((float) tSensorPWMValue/ (float) tSensorRefValue)-1.0);

is incorrect.

The code below will properly calculate the unknown resistance.

#define tSensorPWMPin A0
#define tSensorRefPin A1

const float SensorRefResistor = 7870;
const int tSensorPower = 5;

float tSensorPWMValue;
float tSensorRefValue;
float unknownR;

void setup() {
  Serial.begin(115200);
  // Power the temp. sensor divider
  digitalWrite(tSensorPower, HIGH);
  delay(10);
  // read the value from the temp. sensor:
  tSensorPWMValue = (float)analogRead(tSensorPWMPin); // A0
  tSensorRefValue = (float)analogRead(tSensorRefPin); // A1
  unknownR = SensorRefResistor * (tSensorRefValue / (tSensorPWMValue - tSensorRefValue));
  Serial.println(unknownR);
}

void loop() {}

The use of a digital output pin and two measurement channels is unnecessary (and undesirable) to achieve a ratiometric result. All that one needs to do is to use the 3V3 regulator output pin as the supply since this is connected to the Aref terminal of the Due resulting in direct, single measurement that is always relative to the supply equalling full scale.

Unfortunately, unlike the AVR based Arduino boards, the Due does not have a user selectable Aref level so you can only measure analog values relative to 3V3. The Due does has a Aref pin for an external reference but it has never been implemented in the Arduino core firmware.

In the future, please note that posting a full sketch that compiles is the proper thing to do. Snippets really just confuse the issue - although you posted enough to see that your error was due to your incorrect equation.

A Due output pin will have significant source resistance (hundreds of ohms perhaps). Use the 3.3V rail
as your power source and see if things are better.

I'm not sure if you approach to power the sensor and reference divider by a digital output pin is for energy saving or not.

Assuming your goal is not to save power I would:

Divider_A 3.3v supply ----- R1----A0----R2-----gnd
Divider_B 3.3V supply ------R3----A1----Sensor ----gnd. (perhaps R3 & Sensor should be reversed, see below)

Now the real fun starts...... picking the resistors.

I would start by make R1 = R2 with a 0.1µF cap across R2. Maybe 10 k each.

I would create a excel sheet with a calculation of A1 counts as a function of R sensor for different values of R3.
I would also create a calculation for Rsensor connected to 3.3 and R3 to ground.
With the calculations you can see the optimum R3

Its been a long time since I worked with NTC resistors (which your Irrometer 200TS is) and I recall because NTCs are non linear and voltage dividers are non linear there is a benefit of having the NTC on one of the locations, however I don't recall which.

BTW NTC stands for Negative Temperature Coefficient resistor. And you have a typical "10K NTC" you can google this and find all sorts of information, especially how to convert the sensor resistance to °C

Calibration: I would use an ice bath for 0°C. Not knowing your exact needs I don't know if this will be adequate but I suspect it will.

John

Hi,

Thanks for all these answers, I've been testing most of your comments but root cause is completely different. I think I found it. First few points to mention:

  • I've replaced sensors for well known resistors, to ensure reads are consistent.

  • Maths are correct, equation I'm using is valid. Easy to demonstrate.

  • I've tested readings with a decoupling capacitor of 100nF but it doesn't help. In fact Atmel datasheet for SAM3X micros do not show any recommendation about it. It recommends impedances lower than 10K for good measures but this depends on the sensor itself which I cannot control, obviously I can reduce the ref. resistor to be less than 7.87K but will increase power consumption and also doesn't help to improve measures (tested). I'm using this value as recommended in sensor manufacturer examples.

  • Aref in a Due is 3.3Volts. The advantage of using 2 analog inputs is that measures do not depend on ref. voltage itself.

Ok, so the interesting part:

  • When I'm powering the circuit connecting the Due to the USB programming port and a USB socket I get correct readings in resistors, obviously with an acceptable error.

  • When I'm powering the Due with the power supply I'm building (adafruit breakouts: solar lipoly charger + powerboost + TPL5110 as a timer ) I get resistor measurements with an important error.

So I should understand what's missing in my power supply as all circuit is working fine and XBee packets are sent normally in both cases...

Regards,
Joan

Can you post a diagram of how its wired up, and ideally a photo of the setup too?

Hi,
How do you know what the resistance of your thermistor is?
Do you measure it with a DMM before putting it in your DUE circuit?

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Thanks.. Tom.... :slight_smile:

Hi Tom,

To test and measure error in sensor values I've replaced sensors by resistors, and I've tested several values in different ranges (see below). I measure first the resistors with a DMM with 4 digits (so I can see a resistor of 7880 ohms for example, understanding it can be +- 1). Anyway, reading with Arduino I've found that I normally get readings with errors between 3 to 4 %. Now I need to compare errors when using different power supplies to see if there is any significant difference as I suspect. Are these errors of an expected magnitude ?

In my case this error can be even acceptable as I translate this value to water tension in cBar using experimental formulas (provided by sensor manufacturer: 200SS) depending on the range of the resistor. I'm currently using 2 sensors for soil moisture measurement at different deeps and a temperature sensor to compensate readings.

Resistance < 550 Ohms: CB=0
Resistance < 1000 Ohms: CB=-20.00*((WM1_Resistance/1000.00)(1.00+0.018(TempC-24.00))-0.55)
Resistance > 1000 Ohms, but < 8000 Ohms: CB=(-3.213*(WM1_Resistance/1000.00)-4.093)/(1-0.009733*(WM1_Resistance/1000.00)-0.01205*(TempC))
Resistance > 8000 Ohms: CB=-2.246-5.239*(WM1_Resistance/1000.00)(1+.018(TempC-24.00))-.06756*(WM1_Resistance/1000.00)(WM1_Resistance/1000.00)((1.00+0.018*(TempC-24.00))(1.00+0.018(TempC-24.00)))

Idea is to automate the watering decision based on sensor readings... so precision shouldn't be perfect at all.

I'll upload a picture of the circuit prototype as soon I arrive at home. On thing I'm not comfortable is because the high number of wires required for a protoboard that has sometimes weak contacts...

Regards,
Joan

joanba:
The advantage of using 2 analog inputs is that measures do not depend on ref. voltage itself.

From the few lines I read from these posts I conclude that you don't understand the ratiometric behaviour of an Arduino A/D.
Returned A/D value of a voltage divider circuit is independent of the voltage on Aref if the divider is powered from the same Aref.
Leo..

Hi,
When you have your resistors in circuit, have you measured the circuit voltage values with your DMM and calculated the resistor value by hand to compare with the controller output?

Tom... :slight_smile:

Previous statement is clear and I was trying to say the same, it doesn't matter what's the Aref voltage, because we only need the ratio between the two measurements, so I think we're saying the same.

Today I've added some code to my sketch to calculate error between measurements from Arduino and a DMM. Basically when powering the Arduino via programming port and using an USB socket from my monitor I get very low errors < 0.2%. When I switch the USB wire to my power supply made of adafruit breakouts error increases to 1% which is not bad. See picture uploaded for an idea of this power supply. Probably bigger errors I mention earlier are because the wires in the protoboard, I've a lot of problems with them. Anyway the error differences is still not solved...

The power supply is built as follows:

Adafruit lipoly solar charger --> TPL5110 (timer) --> L4940V5 -> Adafruit PowerBoost

Adafruit lipoly solar charger:
3.7V when battery is powering everything --> requires the PowerBoost to always feed the Arduino with 5V
5V when connected to an USB socket (like in picture)
6V when solar panel is powering the circuit --> requires L4940V5 to limit voltage to PowerBoost
TPL5110 --> much more efficient than Arduino sleep mode
L4940V --> as said to protect PowerBoost but also to ensure it works when using battery voltage
PowerBoost --> accepts voltages from 1.8 to 5.5V and always provides 5.2V