Hello,
I am trying to read the temperature from a Lilypad Temperature Sensor - connected to a Lilypad Arduino USB.
Unfortunately, the temperature values I get are far too high: I'm measuring approximately 60°C in a room with ~28°C !

This is how I did it.

• The Signal is connected to A3 on my board (using alligator clips)
• of the sensor to + on the arduino
• of the sensor to - on the arduino
• the arduino board is currently connected (and powered) via USB to my computer

As for the program, the temperature sensor says

This sensor will output 0.5V at 0 degrees C, 0.75V at 25 C, and 10mV per degree C

or more precisely from the datasheet:

The MCP9700/
9700A and MCP9701/9701A temperature coefficients
are scaled to provide a 1°C/bit resolution for an 8-bit
ADC with a reference voltage of 2.5V and 5V, respec-
tively.

it will map input voltages between 0 and 5 volts into integer values between 0 and 1023. This yields a resolution between readings of: 5 volts / 1024 units or, .0049 volts (4.9 mV) per unit

So, my understanding is that the conversion from the analog value to degrees Celsius should be:

``````degreesC = ((sensorValue * 0.00488) - 0.5) * 100;
``````

But that's not giving good values...

``````Sensor value is: 224
degrees C = 59.31
``````

What's wrong? How should I read the temperature from the sensor?

Thanks

For reference, here's the full sketch:

``````int sensorPin = A3;
int sensorValue;
float degreesC = 0;

void setup()
{
// Set sensorPin as an INPUT
pinMode(sensorPin, INPUT);

// on board LED
pinMode(13, OUTPUT);

// Initialize Serial, set the baud rate to 9600 bps.
Serial.begin(9600);
}

void loop()
{
// I just want the LED to blink to be sure something is happening
digitalWrite(13, HIGH);

// voltages between 0 and 5V are mapped to 0-1023
Serial.print("Sensor value is:");
Serial.println(sensorValue);

degreesC = ((sensorValue * 0.00488) - 0.5) * 100;
Serial.print("degrees C = ");
Serial.println(degreesC);

// I just want the LED to blink to be sure something is happening
delay(500);
digitalWrite(13, LOW);
}
``````

Use the MAP function. Scale up x10 to get 1 decimal.

knut_ny:
Use the MAP function.

Not wise. AFAIK map works with integers, loosing resolution.

axelleap:
So, my understanding is that the conversion from the analog value to degrees Celsius should be:

``````degreesC = ((sensorValue * 0.00488) - 0.5) * 100;
``````

That's for a 5volt Arduino. The "0.00488" comes from 5/1024

The Lilypad is a 3.3volt Arduino. 3.3/1024 = 0.00322265625
Try degreesC = ((sensorValue * 0.003223) - 0.5) * 100;

Change the last digit(s) to calibrate.
Because the 3.3volt supply might not be exactly 3.300volt
Leo..

Not wise. AFAIK map works with integers, loosing resolution.

not in this situation..

Wawa:
Not wise. AFAIK map works with integers, loosing resolution.
That's for a 5volt Arduino. The "0.00488" comes from 5/1024

The Lilypad is a 3.3volt Arduino. 3.3/1024 = 0.00322265625
Try degreesC = ((sensorValue * 0.003223) - 0.5) * 100;

Change the last digit(s) to calibrate.
Because the 3.3volt supply might not be exactly 3.300volt
Leo..

I wonder if it could be designed to be self calibrating? Have it read the 3.3v line on an analog pin then use that value for the calculations to get the multiplier.

knut_ny:
not in this situation…

Right.
Tried it with three values.
224, 225, 226

map gave 6.00, 6.20 and 6.50
Values have to be adjusted, because it’s too far off from tempC
My formula gave 22.20, 22.52 and 22.84

Printed with one decimal place would give equally course steps (bad).

If you want to read this sensor to 0.1C (one decimal place), you have to take more samples and average.
Reading with 1.1volt Aref enabled gives more A/D samples to work with AND makes it independent of supply variations.
Sample code to try.
Leo…

``````unsigned int total; // max 64 readings
float tempC; // final temp

void setup() {
analogReference(INTERNAL); // enable the internal ~1.1volt bandgap reference
Serial.begin(9600);
}

void loop() {
total = 0; // reset value
for (int x = 0; x < 10; x++) { // read 10x
total = total + analogRead(A3); // add each value to a total
}
tempC = ((total * 0.0001025) - 0.5) * 100;
Serial.println(tempC, 1); // one decimal place
delay(200); // some delay to slow readings
}
``````

@Wawa. Internal ref is 2.56V. Recalc.

Wawa:
That's for a 5volt Arduino. The "0.00488" comes from 5/1024

The Lilypad is a 3.3volt Arduino. 3.3/1024 = 0.00322265625
Try degreesC = ((sensorValue * 0.003223) - 0.5) * 100;

Ah yes, indeed! I changed, and now have far more reasonable values... A bit underestimated actually.
Is it possible my Lilypad is getting actually more than 3.3V? :o

I also meant to try the map function but accidentally broke the USB pin Now I have some soldering to do ...

knut_ny:

Thanks
Axelle.

Use internal reference, then the main voltage wont be of interest.
The MAP-function must be altered to use 3.3V (change from 600 to 465)

The first gives you 4 steps/deg. the other 3 steps

knut_ny:
Use internal reference, then the main voltage wont be of interest.

Sorry, I don't understand what you mean?
You mean I use 2.56V?
That will give me even a lower temperature that what I already have...

--Axelle

knut_ny:
@Wawa. Internal ref is 2.56V. Recalc.

So you’re saying this ATmega32u4 only has a 2.56volt Aref.
I see it mentioned in the datasheet, but not in the product page or Aref page of this site.
If there is only a 2.56volt Aref in this MCU, then the formula indeed has to be adjusted.
Leo…

``````unsigned int total; // max 64 readings
float tempC; // final temp

void setup() {
analogReference(INTERNAL); // enable the internal bandgap reference
Serial.begin(9600);
}

void loop() {
total = 0; // reset value
for (int x = 0; x < 10; x++) { // read 10x
total = total + analogRead(A3); // add each value to a total
}
//tempC = ((total * 0.0001025) - 0.5) * 100; // for an Uno/Nano
tempC = ((total * 0.0002500) - 0.5) * 100; // for a Lilypad | calibrate here
Serial.println(tempC, 1); // one decimal place
delay(200); // some delay to slow readings
}
``````