View Full Version : Programming a Temperature Sensor using a PIC18F4550

03-30-2010, 02:23 AM
I'd like to program a Temperature Sensor using the PIC18F4550, but I'm not sure how to start. For the moment, I am using a 10k Ohm pot to try to calibrate it. The Temperature Sensor that I am using is the LM335Z:

As I move the potentiometer from one end to the other, in ADRESH/ADRESL
I get values that range from 0x000 to 0x3FF. I understand that this is the voltage.

My first approach was to go into the datasheet and program every value. For example, values < 0x156 = -40*C, values > 0x1C6 = 100*C (since these are the max values), then program brackets. 0x157 = -39*C, 0x156 = -37*C, etc.

If I approached it this way, I would be killing myself going through all those values, especially if I found out the part is a little off or I need to change sensors or something.

I read somewhere on this forum:
This simple device output 10mV/C. Feed this signal to one input of the comparator. The other input can be derived from a resistor network to provide the voltage for comparison.

This looks like something that applies to me, but I don't fully understand it, let alone try to program this in assembly.

03-30-2010, 04:15 AM
You can use an analog input on your pic and it will read the output from the temperature sensor.

If the temp in your room is 25*C, the input on the analog pin will be 250mv.

Simply divide the input by 10 to display the temperature.

03-30-2010, 12:01 PM
Not quite, it is an absolute Kelvin (K) scale.
0V output = 0K = -273.15C
10mV per degree C (or K) - means output at 0C (273.15K) = 273.15*10= 2731.5mv =2.7315V

Output at 25 degrees C (273.15+25=298.15K) = 298.15*10 = 2981.5mV = 2.9815V

To get the answer in degrees C, subtract the ADC result you should get at 0C from the ADC result, then:

The ADC range = 0-1023 (3FFh) for 5V
Each volt = 100 degrees C
Temp(K)= ADCresult /1023*5*100
= ADCresult * 0.4888

Temp(C) = (ADCresult - (2.73/5*1023)) *0.4888
= (ADCresult - 559) * 0.4888

03-30-2010, 12:05 PM
use this to generate code to multiply by 0.4888
I'm not sure if the generated code will work for negative temperatures - you could use the temp(K) result and then subtract 273 afterwards.


03-30-2010, 12:29 PM
Thanks very much guys, I'll work on it later tonight and let you know how it works =)

03-30-2010, 12:35 PM
Not quite, it is an absolute Kelvin (K) scale.
0V output = 0K = -273.15C
10mV per degree C (or K) - means output at 0C (273.15K) = 273.15*10= 2731.5mv =2.7315V

Output at 25 degrees C (273.15+25=298.15K) = 298.15*10 = 2981.5mV = 2.9815V

You are correct. I never did like that kelvin kid... ;)

03-30-2010, 02:40 PM
A further point is that this is only as accurate as your 5V power supply to the PIC.
If your power supply is 4.9V then the result would be 6 degrees lower at room temperature.

03-30-2010, 06:33 PM
Hi corsair,
I have a similar project made with 18F452 with LM35. This may come to help you.
Here's the code in mikroBASIC:
program thermometer452

dim LCD_RS as sbit at RB4_bit
LCD_EN as sbit at RB5_bit
LCD_D4 as sbit at RB0_bit
LCD_D5 as sbit at RB1_bit
LCD_D6 as sbit at RB2_bit
LCD_D7 as sbit at RB3_bit

LCD_RS_Direction as sbit at TRISB4_bit
LCD_EN_Direction as sbit at TRISB5_bit
LCD_D4_Direction as sbit at TRISB0_bit
LCD_D5_Direction as sbit at TRISB1_bit
LCD_D6_Direction as sbit at TRISB2_bit
LCD_D7_Direction as sbit at TRISB3_bit

dim ADCResult as longword
dim value as word[3]
dim vstring as string[3]

sub procedure GlobInit
ADCON1 = $4E
LCD_Out(1, 1, "Temp:")
LCD_Out(1, 15, "'C")
end sub

while true
ADCResult = (ADC_Read(0) * 500) >> 10
value[0] = ADCResult div 100
value[1] = (ADCResult div 10) mod 10
value[2] = ADCResult mod 10
vstring[0] = value[0] + 48
vstring[1] = value[1] + 48
vstring[2] = value[2] + 48
LCD_Out(1, 10, vstring)
unsigned long ADCResult;
unsigned int value[3];
char vstring[3];

void GlobInit(void){
TRISB = 0;
PORTB = 0;
TRISA = 1;
ADCON1 = 0x4E;
LCD_Config(&PORTB, 4, 5, 6, 3, 2, 1, 0);
LCD_Out(1, 1, "Temp:");
LCD_Out(1, 15, "'C");

void main(){
while (1){
ADCResult = (ADC_Read(0) * 500) >> 10;
value[0] = ADCResult / 100;
value[1] = (ADCResult / 10) % 10;
value[2] = ADCResult % 10;
vstring[0] = value[0] + 48;
vstring[1] = value[1] + 48;
vstring[2] = value[2] + 48;
LCD_Out(1, 10, vstring);
}Hope this helps.

03-30-2010, 11:20 PM
I am using a 3.3 voltage regulator, and i measured it and it looks pretty consistent at 3.3.

Tahmid, I have a question about your ADC result. Why are you adding 48?

The value[0],value[1],value[2] are the digits that are to be displayed, correct?

03-30-2010, 11:35 PM
At 3.3V a recalcualtion is required:

Temp(K)= ADCresult /1023*3.3*100
= ADCresult * 0.3226

Temp(C) = (ADCresult - (2.73/3.3*1023)) *0.3226
= (ADCresult - 846) * 0.3226

Maximum temperature measurable will be 57 degrees C (330K) because 330K gives 3.3V

03-30-2010, 11:48 PM
Hmm, yea this is mainly just for a room temperature sort of deal. Thank you very much Mark!

Just one quick question... I have a 7-segment display and I want to display just the voltage decimal. When I used your equation, it's combining both Hex and Decimal systems. After I figure this out, I should be able to use your equation and be able to convert the temperature into decimal as well.

For example, ADRES = 0x3FF (where ADRESH = 0x3, ADRESL = 0xFF)
I can easily extract each of the 3-digits by dividing by 10, where I would have:
value1 = F
value2 = F
value3 = 3

Now, I know each value is a power of 16, where it would be 3*(16^2) + F*(16) + F = 1023. To get the voltage, since 1023 = 3.3v, it would just simply be (ADRES/1023)*3.3. But ADRES is in hex (headache!).

03-31-2010, 09:24 AM
You can use a hex to bcd converter and a 7 seg driver. It will display the decimal on a 7 seg either way. Or you can try to multiplex it and do it from the uC.

03-31-2010, 12:43 PM
The reason that Tahmid is adding 48 is that 48 is the ASCII for "0". You don't have to worry about that for 7seg LEDs.
For the voltage if you use:
(ADRES /1023) *33
= ADRES/31
what you get is 10x the voltage, ie 1.5V gives 15
This is easier to display and saves using non-integers which can be a pain in ASM

Have a look in AN526 (from the Microchip site) for a Hex to BCD routine and investigate how BCD works.

Everything has to be converted to hex anyway because that's the way the PIC works, we are only using decimal here because we understand it better, but PICs don't really like it.

04-01-2010, 05:13 PM
I am using a 3.3 voltage regulator, and i measured it and it looks pretty consistent at 3.3.

Tahmid, I have a question about your ADC result. Why are you adding 48?

The value[0],value[1],value[2] are the digits that are to be displayed, correct?

Say we have 20'C = 0.2v. ADC reads that as (0.2/5)*1024 = 41. That corresponds to (41 * 500) >> 10 = 20. So value[0]=0, value[1]=2, value[2]=0. So LCD should display 020. But value[0...2] are in numeric form. To send these to LCD, they should be sent as ascii values. The ascii value of numbers 0 to 9 are (48+number).
0 -> 48, 3 -> 51, 7 -> 55, 9 -> 57, etc...
So, that's why.

Check this out: http://www.asciitable.com/

Hope you understood.

04-02-2010, 04:26 PM
So, after a few days, I finally got this to work. The Temperature Sensor that I will be using is a LM335Z. Anyone know where I can download a look-up table for this? :D Or do I have to program that myself.

04-07-2010, 12:58 AM
so I finally got the temperature sensor, my beloved LM335Z! my professor suggested that i get an op amp for it, so my dumbass went out to radioshack and got an lm741 op-amp. now, after looking around, it looks like im going to need more components (resistors, capacitors, diodes, etc). so, i'm willing to do this, but i was wondering if someone can help me design a circuit for this (if it's even needed because i would like to avoid this). the good thing is, we won't have to start from complete scratch. i already have somewhat of an idea that i need to do- i just need some guidance.

i want to design this temperature sensor so that it uses the full 0-3.3v range instead of just a small portion (like 1.8-2.1 or whatever). so, i found a few things on the internet that might be of use.

1) the circuits of this LM3911 (which is similar to the LM335 from what i read) are here: http://pdf1.alldatasheet.com/datasheet-pdf/view/8897/NSC/LM3911.html
2) the circuit that i want to copy but it doesn't have any circuit pictures! it uses the LM3911 and it says it uses an op-amp along with ait's all in a .doc i found, which is attached.

the thing is, none of these circuits have op-amps, so i dont get how he said "The circuit was taken directly from the National LM3911 datasheet." nonetheless, my guess is that he is using the circuit labeled "Operating With External Zener for Lower Power Dissipation." this circuit uses 1 zener, 1 resistor, 1 sensor, and the output is in kelvin.

can someone help me alter that circuit (what parts and where to connect) so that i can use my lm741 op-amp and lm335z temperature sensor to operate in the range of 0-3.3v?

04-07-2010, 10:29 AM
The LM3911 has a built in op amp so I wouldn't use those circuits as examples.
Unfortunately the 741 is rubbish and you won't be able to use it unless you have at least +9V and -9V power sources in your application. A rail to rail op amp would be best but if you have 5V available somewhere (maybe before your voltage regulator) you might be able to use a LM358 which works from the negative rail to 1.5V below the positive rail, which would give you a 0-3.5V range. Best get a dual op amp because you might need 2.
On the positive side, you won't need the zener diode circuit you posted because it is just to reduce the voltage into the sensor from 15V to 6.2V.

04-07-2010, 10:44 AM
Which temperature range do you (or more likely your professor) want to measure

04-07-2010, 01:23 PM
markd, that's very helpful information. i do have a 5v power supply, and i can't seem to spot a -vdd source anywhere.. so hooking an LM358 from Vdd(5v) to ground would work great. besides an LM358, what else would i need to get? btw, i'm not using an lm3911, i have a lm355z. i just used lm3911 as an example because it's pretty close to the lm355z.

from the lm358 datasheet, i can make an non-inverting op-amp, correct? what resistors should i use? (not sure what voltage i should be aiming for).

t06afre, the temperature range is just going to be room temperature and around that area. nonetheless, i need to find an equation somewhere on the web that estimates the curve of the lm335z, happen to know of where i could get it? =)

anyways, thanks for your replies guys

04-07-2010, 03:03 PM
Something like this might work. It has a gain of 5 and the bottom op amp supplies a reference voltage. By playing with the gain and the reference voltage you should be able to get what you are after.
The 2.5V label is your sensor input (2.5V would be 250Kelvin = -23 degrees C which is a bit chilly).
If you go to this page, click file, import and then paste the below into it you should be able to simulate it.


$ 1 5.0E-6 10.20027730826997 57 5.0 50
w 336 144 336 192 0
a 336 128 480 128 1 3.5 0.0 1000000.0
w 480 128 480 192 0
r 336 192 480 192 0 4000.0
r 240 192 336 192 0 1000.0
w 240 48 336 48 0
w 336 48 336 112 0
O 480 128 544 128 0
a 336 320 480 320 1 3.5 0.0 1000000.0
172 240 48 176 48 0 6 2.5 3.0 2.5 0.0 0.5 Voltage
w 336 336 336 384 0
w 336 384 480 384 0
w 480 384 480 320 0
R 128 224 128 176 0 0 40.0 5.0 0.0 0.0 0.5
g 128 352 128 400 0
174 128 224 128 352 0 10000.0 0.41090000000000004 Resistance
w 144 288 176 288 0
w 176 288 176 304 0
w 176 304 336 304 0
w 480 320 480 256 0
w 480 256 240 256 0
w 240 256 240 192 0
o 7 64 0 34 5.0 9.765625E-5 0 -1
o 20 64 0 35 5.0 7.8125E-4 1 -1

04-07-2010, 04:26 PM
wow, that thing's amazing. cool find =)

ill play around with it on saturday, have 2 exams coming up.. looking forward t it, should be fun to build.