You are on page 1of 10

A Digital temperature meter using an LM35 temperature

sensor
Introduction
A digital thermometer is a good choice of project for beginners who just stepped
in to the world of microcontrollers because it provides an opportunity to learn
using sensors to measure the real world signals that are analog in nature. This
article describes a similar project based on a PIC16F688 microcontroller and an
LM35 temperature sensor. LM35 is an analog sensor that converts the
surrounding temperature to a proportional analog voltage. The output from the
sensor is connected to one of the ADC channel inputs of the PIC16F688
microcontroller to derive the equivalent temperature value in digital format. The
computed temperature is displayed in a 162 character LCD, in both C and F
scales.

Theory
The LM35 series of temperature sensors are produced by National
Semiconductor Corporation and are rated to operate over a -55 C to 150C
temperature range. These sensors do not require any external calibration and
the output voltage is proportional to the temperature. The scale factor for
temperature to voltage conversion is 10 mV per C. The LM35 series sensors
come in different packages. The one I used is in a hermatic TO-46 transistor
package where the metal case is connected to the negative pin (Gnd).

The measurement of negative temperatures (below 0C) requires a negative


voltage source. However, this project does not use any negative voltage source,
and therefore will demonstrate the use of sensor for measuring temperatures
above 0C (up to 100C).
The output voltage from the sensor is converted to a 10-bit digital number using
the internal ADC of the PIC16F688. Since the voltage to be measured by the ADC
ranges from 0 to 1.0V (that corresponds to maximum temperature range, 100

C), the ADC requires a lower reference voltage (instead of the supply voltage
Vdd = 5V) for A/D conversion in order to get better accuracy. The lower reference
voltage can be provided using a Zener diode, a resistor network, or sometime
just simple diodes. You can derive an approximate 1.2V reference voltage by
connecting two diodes and a resistor in series across the supply voltage, as
shown below. As a demonstration, I am going to use this circuit in this project. I
measured the output voltage across the two diodes as 1.196 V. The resistor R I
used is of 3.6K, but you can use 1K too. The important thing is to measure the
voltage across the two diodes as accurate as possible.

We need do some math for A/D conversion. Our Vref is 1.196 V, and the ADC is
10-bit. So, any input voltage from 0-1.196 will be mapped to a digital number
between 0-1023. The resolution of ADC is 1.196/1024 = 0.001168 V/Count.
Therefore, the digital output corresponding to any input voltage Vin =
Vin/0.001168. Now, lets see how to get the temperature back from this whole
process of converting sensors output to 10-bit digital number.
Assume, the surrounding temperature is 26.4 C. The sensor output will be 264
mV (0.264 V). The output of ADC will be 0.264/0.001168 = 226. If we reverse this
process, we have 226 from ADC and we can go back and find the temperature by
using the sensor scale factor (10 mV/C),
temperature = 226 * 0.001168 (V/Count) / 0.01 (V/C) = 26.4 C
If you want to avoid floating point math in your program, just use,
temperature = 226 * 1168 = 263968
While displaying this, you need to put a decimal at the fourth place from the left.
So the calculated temperature is 26.3968C, which is pretty close to the actual
one. The difference is caused by quantization and rounding errors. In this project,
we will display temperature accurate to one decimal place, i.e., we will divide the
above number by 1000 to get 263. So the temperature will be displayed as 26.3
C.

Once you have derived the temperature back in C, you can convert it to F
using a simple equation,
temperature in F = 9 x temperature in C /5 + 32
In this case, the number you got for C is scaled by 10 (263 for 26.3), you should
use
temperature in F = 9 x temperature in C /5 + 320
Since, the number for C may not be exactly divisible by 5 (such as 263 is not),
you can further eliminate the floating point by scaling it one more time by 10. So
the new equation will be,
temperature in F = 9 x temperature in C x 10 /5 + 3200
or, temperature in F = 18 x temperature in C + 3200 = 18 x 263+3200 =
7934
79.34 F is equivalent to 26.3 C. In this project, it will be displayed as 79.3 F.

Circuit Diagram
An external reference voltage to the internal ADC of PIC16F688 can be provided
through RA1 I/O pin. The output from the LM35 sensor is read through RA2/AN2
ADC channel. The temperature is displayed on a 162 character LCD that is
operating in the 4-bit mode. A 5K potentiometer is used to adjust the contrast
level on the display. The detail circuit diagram is given below. Note that the
PIC16F688 uses its internal clock at 4.0 MHz.

Circuit setup on the breadboard

A closer look at the LM35DH sensor and the reference voltage circuit.

Software
The firmware for this project is developed with MikroC Pro for PIC compiler. The
link to download the compiled HEX code is provided at the bottom of this section.
The configuration bits for PIC16F688 are
Oscillator -> Internal RC No Clock
Watchdog Timer -> Off
Power Up Timer -> On
Master Clear Enable -> Enabled
Code Protect -> Off
Data EE Read Protect -> Off
Brown Out Detect -> BOD Enabled, SBOREN Disabled
Internal External Switch Over Mode -> Enabled
Monitor Clock Fail-Safe -> Enabled
You can set these fuses in the Edit Project window (Project-> Edit Project)
/* Digital Thermometer using PIC16F688 and LM35
Internal Oscillator @ 4MHz, MCLR Enabled, PWRT Enabled, WDT OFF Copyright @
Rajendra Bhatt November 8, 2010 */

// LCD module connections


sbit LCD_RS at RC4_bit;

sbit LCD_EN at RC5_bit;


sbit LCD_D4 at RC0_bit;
sbit LCD_D5 at RC1_bit;
sbit LCD_D6 at RC2_bit;
sbit LCD_D7 at RC3_bit;
sbit LCD_RS_Direction at TRISC4_bit;
sbit LCD_EN_Direction at TRISC5_bit;
sbit LCD_D4_Direction at TRISC0_bit;
sbit LCD_D5_Direction at TRISC1_bit;
sbit LCD_D6_Direction at TRISC2_bit;
sbit LCD_D7_Direction at TRISC3_bit;
// End LCD module connections
// Define Messages
char message0[] = "LCD Initialized";
char message1[] = "Room Temperature";
// String array to store temperature value to display
char *tempC = "000.0";
char *tempF = "000.0";
// Variables to store temperature values
unsigned int tempinF, tempinC;
unsigned long temp_value;
void Display_Temperature() {
// convert Temp to characters
if (tempinC/10000)
// 48 is the decimal character code value for displaying 0 on LCD
tempC[0] = tempinC/10000 + 48;
else tempC[0] = ' ';
tempC[1] = (tempinC/1000)%10 + 48; // Extract tens digit

tempC[2] = (tempinC/100)%10 + 48; // Extract ones digit


// convert temp_fraction to characters
tempC[4] = (tempinC/10)%10 + 48; // Extract tens digit
// print temperature on LCD
Lcd_Out(2, 1, tempC);
if (tempinF/10000)
tempF[0] = tempinF/10000 + 48;
else tempF[0] = ' ';
tempF[1] = (tempinF/1000)%10 + 48; // Extract tens digit
tempF[2] = (tempinF/100)%10 + 48;
tempF[4] = (tempinF/10)%10 + 48;
// print temperature on LCD
Lcd_Out(2, 10, tempF);
}
void main() {
ANSEL = 0b00000100; // RA2/AN2 is analog input
ADCON0 = 0b01001000; // Connect AN2 to S/H, select Vref=1.19V
CMCON0 = 0x07 ; // Disbale comparators
TRISC = 0b00000000; // PORTC All Outputs
TRISA = 0b00001110; // PORTA All Outputs, Except RA3 and RA2
Lcd_Init(); // Initialize LCD
Lcd_Cmd(_LCD_CLEAR); // CLEAR display
Lcd_Cmd(_LCD_CURSOR_OFF); // Cursor off
Lcd_Out(1,1,message0);
Delay_ms(1000);
Lcd_Out(1,1,message1); // Write message1 in 1st row
// Print degree character
Lcd_Chr(2,6,223);

Lcd_Chr(2,15,223);
// Different LCD displays have different char code for degree symbol
// if you see greek alpha letter try typing 178 instead of 223
Lcd_Chr(2,7,'C');
Lcd_Chr(2,16,'F');
do {
temp_value = ADC_Read(2);
temp_value = temp_value*1168;
tempinC = temp_value/1000;
tempinC = tempinC*10;
tempinF = 9*tempinC/5 + 3200;
Display_Temperature();
Delay_ms(1000); // Temperature sampling at 1 sec interval
} while(1);
}
Download HEX file

Output
I took some pictures of the completed project displaying temperatures in both
the scales.

Temperature goes up if you touch the sensor with your fingers

Accuracy of the measurement

The accuracy of the temperature measurement highly depends upon the stability
of the reference voltage. If the reference voltage drifts from the value that we
considered in our calculation, the measured temperature value could be
significantly off from the actual value. Using a simple diode-resistor network for
deriving a reference voltage may not be a very good idea, but the purpose of this
project was to demonstrate the technique, not to come up with a commercial
digital thermometer product. You can also try a Zener diode or a potentiometer
to derive the reference voltage. Besides, the quantization error introduced by the
10-bit ADC, rounding numbers while doing the math, and the accuracy of the
sensor itself within the desired range of temperature also affect the
measurement output. Read the manufacturers datasheet for more details on the
performance of the LM35 series sensor.

Update
This design has a little flaw. It uses a voltage drop across two diodes (? 1.2 V) as
a reference voltage (Vref) for A/D conversion. However, the datasheet of
PIC16F688 suggests to use Vref greater than 2.2 V to ensure 1-LSB accuracy in
the A/D conversion. Therefore, I have re-written this project but this time using a
MCP1525 device for creating a precise 2.5 V reference voltage. The new design is
more precise and accurate in taking temperature measurements