[SOLVED] Arduino killing all my temp sensors?

Hi all,

I'm fairly new to electronics but I successfully built a few things with my breadboard, some resistors, LEDs and temperature sensors.

This afternoon I received a collection of thermistors and some temperature sensors (LM35, LM335). I wanted to benchmark them all against each other so I made a little assembly, they were all working fine, everything was perfect.

Then I want to work again on another project involving the MPC9700 and so I make this:

Resistor is 220 ohms, capacitor 1uF.

And I am getting strange readings. I realised I inverted polarity on the MPC9700 so I turn it around. But it was not returning coherent readings using a code I knew was working before with this sensor.

so I replaced it with an LM35 thinking that I might have destroyed it by inverting + and -

But the LM35 was returning strange values too (it was working not even an hour ago) and became very very very very very hot. I tried again with the MPC9700, the capacitor and the resistor with the same result. I unplugged everything and I have been wondering ever since... What is going on??
Did I damage my Arduino? It's still blinking, the digital outputs are fine (tested with LEDs) but now I'm scared to hook anything up to the analog pins... Anyone got a clue as to what happened?

I am still a newb so sorry if this is simple but I found if you are using serial monitor you need to make sure the speeds are the same.
If you set in code then change the serial monitor to match.

Also in 2nd picture, your capacitor is behind the feeds, wouldn't it need to be in front? Again I am just guessing as I don't really know :slight_smile:

Hope this helps.
I have RHT03, DS1307, BMP085, 16x2 LCD connecting to a UNO. But not fully working yet.
Sensors are nice though :wink: are yours good?

Try replacing the 1 uF cap with a 10k or more resistor.

Have a look at Temperature sensor tutorial - Using the TMP36 / LM35

Looks like you wiring is OK - could you post your code?

Maramor:
I am still a newb so sorry if this is simple but I found if you are using serial monitor you need to make sure the speeds are the same.
If you set in code then change the serial monitor to match.

Also in 2nd picture, your capacitor is behind the feeds, wouldn't it need to be in front? Again I am just guessing as I don't really know :slight_smile:

Hope this helps.
I have RHT03, DS1307, BMP085, 16x2 LCD connecting to a UNO. But not fully working yet.
Sensors are nice though :wink: are yours good?

When I say incoherent readings I meant -30C then jumping to +450C, not ASCII gibberish like when the speeds are not the same.
AFAIK, resistors can be put anywhere as long as they are there. I was confused too because on schematics and tutorials you can find, they can be placed after or before a component but I googled it up and it seems it makes no difference.

My sensors are good and I can see a lot of applications for them, when they don't heat up like crazy!

Here is the code for the “sensors bench”:

// A1 : thermistor 10k SR PASSIVES (Ref tme.eu NTCC-10K)
// A2 : thermistor 10k noname (Ref tme.eu 640-10K)
// A3 : LM35DZ
// A4 : LM335Z
// A5 : MCP9700
// resultat LM35 = NTCC-10K > 640-10K > MCP9700 (impedance) > LM335 (nocal)

#include <math.h>;

int therm1Pin = A1;
int therm2Pin = A2;
int lm35Pin = A3;
int lm335Pin = A4;
int mcp9700Pin = A5;

void setup() {
  Serial.begin(9600);
  Serial.println("Ready.");
}

//this function copy pasted from an example I found
double Thermistor(int RawADC) {
  double Temp;
  // See http://en.wikipedia.org/wiki/Thermistor for explanation of formula
  Temp = log(((10240000/RawADC) - 10000));
  Temp = 1 / (0.001129148 + (0.000234125 * Temp) + (0.0000000876741 * Temp * Temp * Temp));
  Temp = Temp - 273.15;           // Convert Kelvin to Celcius
  return Temp;
}

void loop() {
  // display labels
  Serial.println("\t\tTherm1\t\tTherm2\t\tLM35\t\tLM335\t\tMCP9700");
  
  // read every sensor senseurs
  int therm1 = analogRead(therm1Pin);
  int therm2 = analogRead(therm2Pin);
  int lm35   = analogRead(lm35Pin);      //
  delay(5);                              // multiplexage?
      lm35  = analogRead(lm35Pin);      //
  int lm335  = analogRead(lm335Pin);
  delay(5);
      lm335 = analogRead(lm335Pin);
  int mcp9700= analogRead(mcp9700Pin);
  delay(5);
      mcp9700 = analogRead(mcp9700Pin);
      
  // display raw analog
  Serial.print("Analog:\t\t");
  Serial.print(therm1); Serial.print("\t\t");
  Serial.print(therm2); Serial.print("\t\t");
  Serial.print(lm35); Serial.print("\t\t");
  Serial.print(lm335); Serial.print("\t\t");
  Serial.println(mcp9700);
  
  // convert to volts
  float voltTherm1 = therm1 / 1023.0 * 5.0;
  float voltTherm2 = therm2 / 1023.0 * 5.0;
  float voltLm35   = lm35 * (5.0 / 1023);
  float voltLm335  = lm335 / 1023.0 * 5.0;
  float voltMcp9700= mcp9700 / 1023.0 * 5.0;
  
  // display voltages
  Serial.print("Voltages:\t");
  Serial.print(voltTherm1, 4); Serial.print("\t\t");
  Serial.print(voltTherm2, 4); Serial.print("\t\t");
  Serial.print(voltLm35, 4); Serial.print("\t\t");
  Serial.print(voltLm335, 4); Serial.print("\t\t");
  Serial.println(voltMcp9700, 4);
  
  // convert to celsius
  float celsTherm1 = Thermistor(therm1);
  float celsTherm2 = Thermistor(therm2);
  float celsLm35 = (voltLm35*100);
  float celsLm335 = (voltLm335*100)-273.15;
  float celsMcp9700 = ((voltMcp9700-.5)*100);
  
  // display celsius
  Serial.print("Temps:\t\t");
  Serial.print(celsTherm1); Serial.print("\t\t");
  Serial.print(celsTherm2); Serial.print("\t\t");
  Serial.print(celsLm35); Serial.print("\t\t");
  Serial.print(celsLm335); Serial.print("\t\t");
  Serial.println(celsMcp9700);
  
  // new line
  Serial.println("*******************************************************************************************************************************");
  delay(1000);
}

And for the second schematics. This is going to be a fridge temperature monitoring alarm. Note there are provisions for lights and a piezzo. It used to work the way it was in Fritzing and with the same code the first time I wired it around. When I saw the sensor's mess, I disconnected everything but the sensor to try and narrow down the problem:

// prend la temperature sur A0 (MCP9700), la converti en Volts puis en Celsius puis
// imprime sur port serie

int tempPin = 0;

int loLedPin = 8;
int okLedPin = 9;
int hiLedPin = 10;
int piezoPin = 11;

int analogTempRead;
float celsiusTempRead;
int aref_voltage;

void setup() {
  Serial.begin(9600);
  aref_voltage = 50;           // *10 to avoid setting a float if using 3.3V
  pinMode(loLedPin, OUTPUT);
  pinMode(okLedPin, OUTPUT);
  pinMode(hiLedPin, OUTPUT);
  pinMode(piezoPin, OUTPUT);
  Serial.println("Ready.");
}

void loop() {
  analogTempRead = 0;
  for (int i =0; i<16; i++) analogTempRead += analogRead(tempPin);
  float volt = analogTempRead * (aref_voltage/10.0)/16368;
  Serial.print(volt); Serial.println(" V");

  int celsiusTempRead = ((volt-.5)*100)+0.5;   // +0.5 to round up
  //celsiusTempRead = 150;
  Serial.print("Temperature = "); Serial.print(celsiusTempRead); 
  Serial.println(" C");
  
  if (celsiusTempRead >= -30 && celsiusTempRead <= 0) {
    digitalWrite(loLedPin, HIGH);
    digitalWrite(okLedPin, LOW);
    digitalWrite(hiLedPin, LOW);
    delay(300);
  }
  if (celsiusTempRead > 0 && celsiusTempRead <= 8) {
    digitalWrite(loLedPin, LOW);
    digitalWrite(okLedPin, HIGH);
    digitalWrite(hiLedPin, LOW);
    delay(300);
  }
  if (celsiusTempRead > 8 && celsiusTempRead <= 100) {
    digitalWrite(loLedPin, LOW);
    digitalWrite(okLedPin, LOW);
    digitalWrite(hiLedPin, HIGH);
    delay(300);
  }
  if (celsiusTempRead < -30 || celsiusTempRead > 100) {
    digitalWrite(loLedPin, HIGH);
    digitalWrite(okLedPin, LOW);
    digitalWrite(hiLedPin, HIGH);
    analogWrite(piezoPin, 1);
    delay(150);
    digitalWrite(loLedPin, LOW);
    digitalWrite(okLedPin, HIGH);
    digitalWrite(hiLedPin, LOW);
    delay(150);
  }
}

GoForSmoke:

Try replacing the 1 uF cap with a 10k or more resistor.

Will do when I get back home

That's because the analog pins don't flow more than a very tiny bit of current. Some kind of slow drain is needed and depending on how much current is sourced to the sensor pin a different resistor to ground may suit best. Really perhaps as low as 1k or as high as I dunno might do, I used 22k to ground with input from 0-5V through 2.2k with good results. Without the drain, the wire going to the sensor tends to fill up as it were and measure high or get 'floaty'.

It's possible that some of those sensors put out so little that you'd want 100's of k resistance. I've stuck led leads between ground (the led ground leg) and analog 0 and gotten measures without the resistor to ground, the led made such low current that if I read it often enough per second the reads stayed well below 3V even with one led shining brightly into the led used as sensor. That's probably micro-amps from the led.....

The EE's here can probably explain it all very well, at least to someone ready to handle the explanation.

Ok, here is the code, as I would modify what you put:

// prend la temperature sur A0 (MCP9700), la converti en Volts puis en Celsius puis
// imprime sur port serie

int tempPin = 0;

int loLedPin = 8;
int okLedPin = 9;
int hiLedPin = 10;
int piezoPin = 11;

int analogTempRead;
float celsiusTempRead;
int aref_voltage;
// PJ - Change 1: Pre declare volt here
float volt;

void setup() {
  Serial.begin(9600);
  aref_voltage = 50;           // *10 to avoid setting a float if using 3.3V
  pinMode(loLedPin, OUTPUT);
  pinMode(okLedPin, OUTPUT);
  pinMode(hiLedPin, OUTPUT);
  pinMode(piezoPin, OUTPUT);
  Serial.println("Ready.");
}

void loop() 
{
  //  analogTempRead = 0;     // PJ - Change 2: This is not needed with the next line change!                  
  //for (int i =0; i<16; i++) // PJ - Change 3: No need to take and average 10 readings
  analogTempRead = analogRead(tempPin);
  
  //  float volt = analogTempRead * (aref_voltage/10.0)/16368; // 16368 = 1024 * 16
  volt = analogTempRead * (aref_voltage/1024.0); // change 4: 1024.0, otherwise will calc integer value!!
  Serial.print(volt); Serial.println(" V");
  

  int celsiusTempRead = ((volt-.5)*100)+0.5;   // +0.5 to round up
  //celsiusTempRead = 150;
  Serial.print("Temperature = "); Serial.print(celsiusTempRead); 
  Serial.println(" C");
  
  if (celsiusTempRead >= -30 && celsiusTempRead <= 0) {
    digitalWrite(loLedPin, HIGH);
    digitalWrite(okLedPin, LOW);
    digitalWrite(hiLedPin, LOW);
    delay(300);
  }
  if (celsiusTempRead > 0 && celsiusTempRead <= 8) {
    digitalWrite(loLedPin, LOW);
    digitalWrite(okLedPin, HIGH);
    digitalWrite(hiLedPin, LOW);
    delay(300);
  }
  if (celsiusTempRead > 8 && celsiusTempRead <= 100) {
    digitalWrite(loLedPin, LOW);
    digitalWrite(okLedPin, LOW);
    digitalWrite(hiLedPin, HIGH);
    delay(300);
  }
  if (celsiusTempRead < -30 || celsiusTempRead > 100) {
    digitalWrite(loLedPin, HIGH);
    digitalWrite(okLedPin, LOW);
    digitalWrite(hiLedPin, HIGH);
    analogWrite(piezoPin, 1);
    delay(150);
    digitalWrite(loLedPin, LOW);
    digitalWrite(okLedPin, HIGH);
    digitalWrite(hiLedPin, LOW);
    delay(150);
  }

  // Change 5: Not much point taking readings more than once per second
  delay(1000);
}

So five changes in all:

  • Change 1: Pre declare volt in preamble as a global variable. No need to declare each cycle of loop
  • Changes 2 and 3: No need to read and average 16 values (at least not at the moment). Once you have it working for one reading, do some tests to see how stable the readings are and decide if smoothing is necessary.
  • Change 4: This is probably the key change. The value and type of aref_voltage is integer. If you divide 50 by 1024 as an integer calculation the result will be 0. To promote the calculation to a floating point calculation, you need to make one of the values a float, hence 1024.0. I suspect this change alone may make the values more sane.
  • Change 5: I would slow things down a bit - no need to take readings more frequently than once per second. I don't have anything from the data sheet to suggest frequent reading is a problem, but anyway it will consume unnecessary power.

Don't change the capacitor for a resistor. Understand the wiring diagram to see why. Have a look at the datasheet, page 7. A capacitor would only be required to help decouple capacitive loads (ie cables) running from the sensor. In your test case - not required. Do not put a resistor from Vin to out - it will just give you a full reading on the analog input pin!

Let us know how you get one! I should ppint out that I haven't compiled the modifications above, so I apologise if I have accidentally misplaced a semi-colon, or bracket.

I'm not sure what happened, maybe I was tired and did a short, no idea.

But with a 10k resistor (instead of the original 220) between the Vdd and +5V, and with a 1uF capacitor between Vout and GND, I'm getting accurate readings on the MCP9700.

For further reference, is it possible to damage a capacitor in any way? Maybe that's what happened? I couldn't find it anymore today so I took a fresh one and it's fine.

Also, if I put a 220 ohms resistor as suggested in the datasheet instead of a 10k along with the 1uF capacitor, I'm getting wrong readings (ie too much voltage coming out on the analog of the MPC9700). Same if I only put a 1uF capacitor without any resistor. Is there a way to calculate what's the best resistor value to go with a capacitor in that specific case?

The datasheet has this to say, am I misreading or missing something?

4.3 Layout Considerations
The MCP9700/9700A and MCP9701/9701A family does not require any additional components to operate. However, it is recommended that a decoupling capacitor of 0.1 ?F to 1 ?F be used between the VDD and GND pins. In high-noise applications, connect the power supply voltage to the VDD pin using a 200? resistor with a 1?F decoupling capacitor. A high frequency ceramic capacitor is recommended. It is necessary for the capacitor to be located as close as possible to the VDD and GND pins in order to provide effective noise protection. In addition, avoid tracing digital lines in close proximity to the sensor.

Thanks for the suggestions. I implemented them with the following results.
I had to chage the aref_voltage from 50 to 5 due to the code modifications. As for change 4, I understand where you are coming from and I was stuck there for a while. I tried putting 10.0 or 1024.0 and it seemed it didn't change anything for the calculation, as long as there was a decimal number on the line.

Now, I tried without a resistor nor a capacitor, and I am getting readings from 23 to 27 (when actual temp is 24.6C). If I put a 10k resistor and a 1uF capacitor, then the readings are all smooth and 24C, all the time.

Regarding page 7 of the datasheet, I had a look but I couldn't understand why a resistor wouldn't work. Could you clarify please? Again, I have very very limited electronics knowledge and my maths skills are basic, I never studied physics or electronics.

It seems the de-coupling is necessary, based on your findings. I would wire it according to the data sheet method though. If you look at fig 3 on the datasheet, it shows the OUT line being decoupled with a 2k resistor, but the Vdd being fed directly. What happens if you try this? It would also be worth trying with the layout in fig 4, with the capacitor and resistor in series between the OUT and "-" (GND). The suggestion to replace the capacitor between Vdd and OUT with a resistor, would mean the voltage reading on the analog input pin of the Arduino would be 5v, less some small drop depending on the current drawn by the analog pin input. The temperature output of the device would not be "seen" by the arduino.

One other point reference accuracy - put a voltmeter on the 5v pin used to feed the LM-35. You may find it is not exactly 5v, and this will distort your result. Once you know the actual level, amend aref_voltage. I suggest you make this a float as well, so you can deal with a non-integer value.

Good to see progress though!

Wiring the datasheet way 220 ohms on Vdd + 1uF between Vdd and GND: results between 22 and 25C
2k ohms on Vout: results between 20 and 27C
1uF between Vdd and GND only: results between 21 and 26C
Wiring like in my previous post: a steady 24C

I'm confused...

This seems to be the best, giving the most constant readings between samples. Which version of the datasheet are you using though? I see no Fig4 suggesting such a circuit in the one I have?

Data sheet: National Semiconductor Literature Number: SNIS159B, dated November 2000. As explained, in figure 4 there is a 75 Ohm resistor in series with a 1uF capacitor between Vout and Gnd. It also shows a 0.1uF capacitor as optional between Vdd and Gnd.

Do have a look at that LadyAda link I posted earlier. It shows how to use the LM35 with the arduino, and discusses how to make the result more accurate.

I did read it, thanks.

There's something else I don't understand now.
Whether I use the +5V feed of the Arduino board or the +3.3V feed, I am getting the same voltage for a given temperature and I don't need to adjust my calculations in the program.
How is it possible? If I use 5V and keep aref_voltage = 5 I get the correct temperature, if I use 3.3V and keep aref_voltage = 5 then I get accurate temperature too. But if I use 3.3V and set aref_voltage = 3.3 then the readings are off. I understand that if I put aref_voltage = 3.3 then I am 1.7 off in the calculation but what I don't understand is how using 3.3 or 5V doesn't make a difference at the sensor output. As such, I don't understand the analog conversion either: volt = analogTempRead * (aref_voltage/1024.0); why use 5 even when the supplied voltage is 3.3?

That's interesting, and it disproves something I said earlier! Going back to the datasheet, it can be seen that the input voltage to the device does not change the output characteristics - it still gives 10mV / C, so that is why you don't need to change aref_voltage, and also why my earlier comment about reading the output voltage being used to feed the device and changing aref_voltage was wrong. That type of logic only applies to voltage divider types of layout.

Based on http://arduino.cc/en/Reference/AnalogRead, 5 is the correct number because that is what the input ADC handles. Because 0 - 1023 is provided for 0 - 5V, to convert the number given by AnalogRead() to voltage means TempRead * 5 / 1024.0 (as there are 1024 steps).

It's clear now, thanks a lot