Go Down

Topic: Troubles with analog temp sensors (Read 1 time) previous topic - next topic

jpadie

Dec 03, 2017, 05:03 pm Last Edit: Dec 03, 2017, 06:48 pm by jpadie
Hi

I'm scratching my head on this.  I'm observing similar results over different analog sensors (i.e. different model numbers AND different devices) and different boards.  Which makes me think that there is something wrong either with my board design or my code. 

Basically the readings I am getting are always in the low mV.  translating to a high temperature (100+C) - which considering i'm sitting in my kitchen with two jumpers and shivering slightly is an unlikely result.

the code is as follows

Code: [Select]

#include <Arduino.h>
#include <util/crc16.h>
#include <avr/pgmspace.h>
#include <util/parity.h>

void calcTemp();
int nearest(float x);



const byte tempPowerPin = A2;
const byte tempSensorPin = A3;


int curTemperature;
bool hasChanged;
const int mvs[201] = {1299, 1294, 1289, 1284, 1278, 1273, 1268, 1263, 1257, 1252, 1247, 1242, 1236, 1231, 1226, 1221, 1215, 1210, 1205, 1200, 1194, 1189, 1184, 1178, 1173, 1168, 1162, 1157, 1152, 1146, 1141, 1136, 1130, 1125, 1120, 1114, 1109, 1104, 1098, 1093, 1088, 1082, 1077, 1072, 1066, 1061, 1055, 1050, 1044, 1039, 1034, 1028, 1023, 1017, 1012, 1007, 1001, 996, 990, 985, 980, 974, 969, 963, 958, 952, 947, 941, 936, 931, 925, 920, 914, 909, 903, 898, 892, 887, 882, 876, 871, 865, 860, 854, 849, 843, 838, 832, 827, 821, 816, 810, 804, 799, 793, 788, 782, 777, 771, 766, 760, 754, 749, 743, 738, 732, 726, 721, 715, 710, 704, 698, 693, 687, 681, 676, 670, 664, 659, 653, 647, 642, 636, 630, 625, 619, 613, 608, 602, 596, 591, 585, 579, 574, 568, 562, 557, 551, 545, 539, 534, 528, 522, 517, 511, 505, 499, 494, 488, 482, 476, 471, 465, 459, 453, 448, 442, 436, 430, 425, 419, 413, 407, 401, 396, 390, 384, 378, 372, 367, 361, 355, 349, 343, 337, 332, 326, 320, 314, 308, 302, 296, 291, 285, 279, 273, 267, 261, 255, 249, 243, 237, 231, 225, 219, 213, 207, 201, 195, 189, 183};

void calcTemp() {
  long reading=0;
  int _reading = 0;
  float mv;
  float finalReading;
  for (byte i = 0; i <= 15; i++) {
    _reading = analogRead(tempSensorPin);
    if (i > 0) {
      reading = _reading + reading;
    }
  }
  finalReading = (reading/15.0);
  mv = (finalReading/1023.0) * 1100.0;
  int index = nearest(mv);
  int _curTemperature = index - 50;
  if (_curTemperature != curTemperature) {
    curTemperature = _curTemperature;
    hasChanged = true;
  }
}

int nearest(float x) {
  int idx = 0; // by default near first element
  int distance = abs(mvs[idx] - x);
  for (int i = 1; i < (sizeof(mvs) / sizeof(mvs[0])); i++) {
    int d = abs(mvs[i] - x);
    if (d < distance)
    {
      idx = i;
      distance = d;
    }
  }
  return idx;
}


void setup() {
  // put your setup code here, to run once:
  pinMode(tempPowerPin, OUTPUT);
  digitalWrite(tempPowerPin, HIGH);
  pinMode(tempSensorPin, INPUT);
  analogReference(INTERNAL);
}

void loop(){
calcTemp();
//delay(10000);
}



the hardware design is very simple - an atmega328p with 10nF decoupling caps and 10kpullup on reset.
A2 connected as a power pin and A3 to the output of the analog temp sensor.  When this bits gets sorted out I will add a radio to the board and pop it in a box.  There will be 20 of them.

the eagle files are here: https://1drv.ms/f/s!Aob6wYJSSDO0i_ppDmovt2RL5fSs-g

images of them for easy reference are here:



and a photo of the board I am actually working on is here:


 (i have tested five in this state, some with LMT84 and some with LM94022 (both in the 5 pin SC-70 package). 

can anyone shed any light on the consistently erroneous readings please?  Just for the avoidance of doubt, the readings got on the uC are broadly consistent with direct voltmeter readings on the output pin of the temp sensors (albeit they are still connected to the uC at that time). 

I'm feeding the board five volts at the moment.  Although this is within tolerance, in production they will be running off two AAA cells.  The board will be in sleep mode most of the time and i will need to hardwire the power to the temp sensor ultimately as the latency is too slow (10 secs).

thanks in advance,
Justin

tkbyd

Ummm... not what you asked.. but why are you using an analog sensor? The simple DS18B20s are very popular because they are cheap, easy to use, and dependable!

outsider

#2
Dec 04, 2017, 02:19 am Last Edit: Dec 04, 2017, 02:47 am by outsider
What kind of ADC results are you getting from A3 at room temperature? Looks like 25C should be around 835, 20C around 860.

wvmarle

Why using a lookup table? It's easier (and probably more accurate) to simply calculate the value in code. Saves a lot of memory, too: that table is 402 bytes out of your 2048 available. It's also highly linear, making it even stranger to use a lookup table rather than a formula.

You use INTERNAL for ADC reference, are you sure about that part?

Code: [Select]

void calcTemp() {
  long reading=0;
  int _reading = 0;
  float mv;
  float finalReading;
  for (byte i = 0; i <= 15; i++) {
    _reading = analogRead(tempSensorPin);
    if (i > 0) {
      reading = _reading + reading;
    }
  }
  finalReading = (reading/15.0);
  mv = (finalReading/1023.0) * 1100.0;
  int index = nearest(mv);


There's a lot wrong here.
Take 16 samples instead of 15, and you can replace your floating point calculation by a simple bitwise operator.
And why that i>0 test? You don't want the first one?

So let's fix that part:
Code: [Select]

  for (byte i = 0; i <= 16; i++) {
    _reading = analogRead(tempSensorPin);
    if (i > 0) { // Dump the first reading; record the other 16.
      reading = _reading + reading;
    }
  }
  finalReading = reading >> 4; // right-shift four bits is the same as dividing by 16, just a lot faster and much smaller code.


Then the temperature calculation.

Code: [Select]

  mv = (finalReading/1023.0) * 1100.0;

Having to do this means you didn't calculate your lookup table properly. Based on the numbers in your sketch you should get the reading by this simple calculation:

Code: [Select]

float temp = reading * -0.19364 + 183.92;



Putting this all together you can reduce your sketch to this:

Code: [Select]

#include <Arduino.h>
#include <util/crc16.h>
#include <avr/pgmspace.h>
#include <util/parity.h>

const byte tempPowerPin = A2;
const byte tempSensorPin = A3;

int curTemperature;
bool hasChanged;

void calcTemp() {
  long totalReading = 0;
  hasChanged = false;
  for (byte i = 0; i <= 16; i++) {
    int reading = analogRead(tempSensorPin);
    if (i > 0) {
      totalReading += reading;
    }
  }
  int temp = (totalReading >> 4) * -0.19364 + 183.92;
  if (temp != curTemperature) {
    curTemperature = temp;
    hasChanged = true;
  }
}

void setup() {
  pinMode(tempPowerPin, OUTPUT);
  digitalWrite(tempPowerPin, HIGH);
  pinMode(tempSensorPin, INPUT);
  analogReference(INTERNAL);
}

void loop(){
  calcTemp();
  //delay(10000);
}



You can see significant savings in size as well. Your sketch:
Code: [Select]

Sketch uses 2668 bytes (8%) of program storage space. Maximum is 30720 bytes.
Global variables use 416 bytes (20%) of dynamic memory, leaving 1632 bytes for local variables. Maximum is 2048 bytes.


My version:
Code: [Select]

Sketch uses 1798 bytes (5%) of program storage space. Maximum is 30720 bytes.
Global variables use 14 bytes (0%) of dynamic memory, leaving 2034 bytes for local variables. Maximum is 2048 bytes.


33% smaller size, 97% less memory for global variables.
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.

jpadie

Thanks for the replies.

@tkbyd I'm using an analog sensor because they can work at very low voltage, have very low quiescent current and are very cheap.  i could move to a digital variant but would need one that sat flush to the board as there is no head height in the enclosure.  Obviously i'd need to redesign the board too! 

@outsider the ADC is reporting around 290-300 per measurement.  consistently across boards and sensors. 

@wvmarle lots of things to reply to.  here goes:

why use a transfer table?  Why not?  i've got lots of memory headroom and for debugging it eliminates all maths errors (as well as avoiding too much floating math)

using the 1.1v reference - yes.  I'm sure.  i know the limits that the sensor will work in and the better resolution of the internal reference is desirable.

number of samples:  i am taking 16 samples and discarding the first.  it's a hangover from the initial code where the analog reference gets changed and you need to wait for stability. 

good point on the bitmath.  thanks.


it is possible that your math on the lookup table gives the right answer.  But remember that the lookup table may appear as if the sensor response is linear, but it is not.  It is parabolic.  The lookup table is accurate (according to the datasheet). 

In any event, your code versus mine produces much the same result - and this is just debug code to test the sensors, not remotely production code.


So, chaps, the questions still beg as to what would cause this board and code to read consistently incorrectly across power supplies, boards, sensors and sensor types?  Apparently its 130C in my kitchen. 

thanks
Justin

wvmarle

why use a transfer table?  Why not?  i've got lots of memory headroom and for debugging it eliminates all maths errors (as well as avoiding too much floating math)
My solution probably has less floating point maths. You still have to do a
Code: [Select]
  mv = (finalReading/1023.0) * 1100.0; calculation. I basically replaced that one with the complete conversion.

Quote
it is possible that your math on the lookup table gives the right answer.  But remember that the lookup table may appear as if the sensor response is linear, but it is not.  It is parabolic.  The lookup table is accurate (according to the datasheet).
I noticed at one end of the table the steps are 5-6, at the other end the steps are 6. So it may be a parabolic reading, over this part of the readings it's very close to linear. Plotting the readings also gives a near-perfectly straight line. Errors from a linear approximation are almost certainly far less than the errors of the sensor itself.
Actually the spec sheet itself mentions it's a "selectable linear negative temperature coefficient".

Quote
In any event, your code versus mine produces much the same result - and this is just debug code to test the sensors, not remotely production code.
Well, that proves my code is functional the same as yours :) It should produce the same output.

Hold the sensor in your hands, see what temperature you get (should be around 33°C if you have normally warm hands).
Put it in the fridge, see what temperature you get (should be around 4°C).
You should see the calculated temperature value drop.
Also good for debugging is to have the actual ADC value you have measured printed on the Serial console. You should get values in the 800-range according to the spec sheet.
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.

jpadie

Yup.  I'm not seeing sensible values as I mentioned.  But they are consistent.  2-300mV.

Just hooked one up directly to two aaa cells and took some voltage readings.  180mv after 60 seconds. 

I'm wondering whether I'm killing them all with the soldering process (hot air for a couple of seconds but I've also tried a crude reflow oven too). 




wvmarle

Killing a part would normally result in no output, but at least you should see a clear difference in different temperature regions.
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.

wvmarle

It makes me wonder: is your board correct?
Did you not by chance mix up top view/bottom view when designing the footprints, something like that?
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.

jpadie

It's a good thought, but no. The wiring to the sensors is correct according to the data sheets. 

I will try some readings in different t temperature zones and see what comes up. 

wvmarle

Did you try the same circuit built up using breakout boards and so of the sensors?

I don't see anything strange in your posted schematic, but that doesn't necessarily mean it's correct.
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.

jpadie

nope.  damn difficult to solder those tiny packages on perfboard. 

i will try to make up a couple more sensor only boards tomorrow night and see whether there is any difference.

thanks for the advice so far
justin


MarkT

#12
Dec 04, 2017, 11:09 pm Last Edit: Dec 04, 2017, 11:18 pm by MarkT
You can't expect the ADC to work at all without decoupling on AREF.  100nF to ground on the AREF pin is
a requirement for accurate readings.

I'm a bit sceptical about running the sensor itself without decoupling, an Arduino pin set to
HIGH is not a very stiff supply, its about 40 ohms or so, but given its a micropower sensor
that doesn't seem too bad.  But there's always the risk of parasitics when you power things
from something that isn't stable.  If the sensor really only does take a few uA supply, no point
making it switchable really, just power it direct.

Check the sensors outputs with a multimeter when powered from a genuine supply voltage,
compare to that in-circuit.  Should narrow down the field.

You say several sensors (several types?) were tested - but same problem?  Odd.  Genuine parts?

If using the internal reference, be aware there's a big spread between chips and individual
calibration is needed.
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

wvmarle

If using the internal reference, be aware there's a big spread between chips and individual
calibration is needed.
OP is getting a reading of about 300 on what should be an 800 mV signal with 1.1V reference.

So either the signal is indeed at 330 mV, or the reference voltage is at about 3V. That's way too far off either way to be explained by normal variation.
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.

outsider

#14
Dec 05, 2017, 08:30 am Last Edit: Dec 05, 2017, 09:04 am by outsider
What kind of ADC reading are you getting with 100C in your kitchen? Are you sure you have programmed for a 1.1V AREF?
Which Arduino? 1.1V / 5V = 0.22 * 100C = 22C
Did you miss the TMP36, only 0.5 microAmps in shutdown mode and its linear, -40 to 125C
TMP36

Go Up