LM335 Sensor is a 3-pin analog device which can measure temperature (converts temperature to analog voltage). This sensor requires an ADC to convert the analog data into digital data.
This post shows how to build a simple thermometer using PIC12F1822 microcontroller and LM335 analog temperature sensor. Temperature data is displayed on 16×2 LCD screen (I2C LCD). This project works also with DFRobot I2C LCD displays.
The compiler used in this project is Microchip MPLAB XC8 (MPLAB X IDE with MPLAB XC8 compiler).
The LM335 sensor has the following features (from LM335 datasheet):
- Directly Calibrated to the Kelvin Temperature Scale
- 1°C Initial Accuracy Available
- Operates from 400 μA to 5 mA
- Less than 1-Ω Dynamic Impedance
- Easily Calibrated
- Wide Operating Temperature Range
- 200°C Overrange
- Low Cost
The LM335 has a breakdown voltage directly proportional to absolute temperature at 10 mV/°K. For example if the LM335 output voltage is equal to 3.03 (3030 mV) that means the temperature is: 303 Kelvin = 30 °Celsius.
The PIC12F1822 is an 8-bit microcontroller which has 4 analog channels with 10-bit resolution. The good thing with this microcontroller is the fixed voltage reference. With the fixed voltage reference we get approximately an exact result. Normally negative and positive references of the ADC module are VSS and VDD, but VDD is not exactly equal to 5.00V and here we should use the fixed voltage reference as a positive reference of the ADC module.
The PIC12F1822 has 3 fixed voltage references: 1.024V, 2.048V and 4.096V. For example if we set the fixed voltage reference to 4.096V and the ADC module is configured so that the negative and the positive references are VSS and FVR (Fixed Voltage Reference) respectively, in this case the equivalent 10-bit digital value of 4.096V is 1023 and 3.00V is 3.00 * 1023/4.096 = 749 , and so on.
In this project I used 4.096 because the LM335 output is between 2.23V (temperature = -50°C) and 3.98V (temperature = +125°C).
Related Projects:
Interfacing I2C LCD with PIC microcontroller | MPLAB Projects
PIC12F1822 + 1602 LCD + LM335 Temperature Sensor | CCS C compiler
Hardware Required:
- PIC12F1822 microcontroller — datasheet
- LM335 temperature sensor — datasheet
- 16×2 LCD screen
- PCF8574 I/O expander (or PCF8574A) — PCF8574 datasheet
- 5 x 10k ohm resistor
- 2.2k ohm resistor
- 330 ohm resistor
- 10k ohm variable resistor or potentiometer
- 5V source
- Breadboard
- Jumper wires
Interfacing PIC microcontroller with LM335 sensor circuit:
Project circuit schematic diagram is shown below.
(All grounded terminals are connected together)
The LM335 sensor has 3 pins (from left to right):
Pin 1 for calibration, not used in this example
Pin 2: output
Pin 3: GND (ground).
The output pin of the LM335 sensor is connected to analog channel 0 (RA0). I chose the 2.2K ohm because as written in the datasheet for optimum accuracy the current flows through the LM335 should be 1mA. For example if the temperature = 27°C, the output will be 3.00V and assume the supply voltage is exactly 5.00V that means the current flows through the sensor is ( 5 – 3)/2.2 = 0.90mA which is good enough. Also the value 2.2K is a standard value and well used.
In this project the PIC12F1822 microcontroller runs with its internal oscillator @ 8 MHz, MCLR pin is configured as an input pin.
Interfacing PIC microcontroller with LM335 sensor C code:
The C code below is for MPLAB XC8 compiler, it was tested with version 2.00 installed on MPLAB X IDE version 5.05 with an optimization level = 1 (Project Properties —> XC8 Compiler —> Optimization —> Optimization level).
RAM used: 95 bytes (74%)
ROM used: 1725 words (84%)
To be able to compile the C code, a small I2C LCD library for MPLAB XC8 compiler is required which can be downloaded from the following link:
I2C LCD driver for MPLAB XC8 compiler
after the download, add the library file (I2C_LCD.c) to project folder.
The I2C LCD driver file is included with the line:
#include “I2C_LCD.c”
The hardware I2C module of the PIC12F1822 is initialized with a clock frequency of 100KHz (100000Hz):
I2C_Init(100000);
The I2C LCD is initialized with an I2C address of 0x4E:
LCD_Begin(0x4E);
To read from ADC module I wrote a small function with the name: uint16_t read_adc(). This function returns the digital value of the analog input.
The microcontroller used in this example is PIC12F1822, configuration words are:
1 2 | #pragma config CONFIG1 = 0x3F84 #pragma config CONFIG2 = 0x1613 |
Where:
- Fail-Safe Clock Monitor enabled
- Internal/External Switchover mode enabled
- CLKOUT function is disabled, I/O function on the CLKOUT pin
- Brown-out Reset (BOR) enabled
- Data memory code protection disabled
- Program memory code protection disabled
- RE3/MCLR pin function is digital input, MCLR internally tied to VDD
- Power-up Timer (PWRT) disabled
- Watchdog Timer (WDT) disabled
- INTOSCIO oscillator: I/O function on CLKIN pin
- Low voltage programming disabled
- In-Circuit Debugger disabled
- Brown-out Reset voltage (Vbor), low trip point selected
- Stack Overflow or Underflow will cause a Reset
- 4xPLL disabled
- Flash Program Memory Self Write disabled
MPLAB XC8 code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | /* * Interfacing PIC12F1822 microcontroller with LM335 analog temperature sensor. * Temperature results (Kelvin and degree Celsius) are displayed on * 1602 LCD screen (I2C LCD). * C Code for MPLAB XC8 compiler. * Internal oscillator used @ 8MHz. * This is a free software with NO WARRANTY. * http://simple-circuit.com/ */ // set configuration words #pragma config CONFIG1 = 0x3F84 #pragma config CONFIG2 = 0x1613 #include <xc.h> #define _XTAL_FREQ 8000000 #include <stdint.h> // include stdint header #include "I2C_LCD.c" // include I2C LCD driver source file char celsius_temp[] = "Temp = 00.0 C"; char kelvin_temp[] = "= 00.0 K"; int16_t Kelvin, Celsius; // function for reading analog data uint16_t read_adc() { GO_nDONE = 1; // start an A/D conversion cycle while (GO_nDONE == 1) ; // wait for conversion complete return (ADRESH << 8) | ADRESL ; // return converted data } // main function void main(void) { OSCCON = 0x70; // set internal oscillator to 8MHz FVRCON = 0x83; // Configure FVR to supply ADC positive reference with 4.096V ADCON0 = 0x01; // select channel 0 (AN0), enable ADC module ADCON1 = 0xF3; // right justified, ADC clock supplied from a dedicated RC oscillator, // VREF+ is connected to internal Fixed Voltage Reference (FVR) module I2C_Init(100000); // initialize I2C bus with clock frequency of 100kHz LCD_Begin(0x4E); // Initialize LCD module with I2C address = 0x4E while(1) { __delay_ms(1000); Kelvin = (read_adc() + 1) * 0.4; // read analog voltage and convert it to Kelvin (0.4 = 100*4.096/1024) Celsius = Kelvin - 273; // convert Kelvin to degree Celsius if(Celsius < 0) { Celsius = abs(Celsius); // absolute value celsius_temp[7] = '-'; // put minus '-' sign } else celsius_temp[7] = ' '; // put space ' ' if (Celsius > 99) celsius_temp[7] = '1'; // put 1 (of hundred) celsius_temp[8] = (Celsius / 10) % 10 + '0'; celsius_temp[9] = Celsius % 10 + '0'; celsius_temp[12] = 223; // put degree symbol kelvin_temp[2] = (Kelvin / 100) % 10 + '0'; kelvin_temp[3] = (Kelvin / 10) % 10 + '0'; kelvin_temp[4] = Kelvin % 10 + '0'; LCD_Goto(1, 1); // go to column 1 row 1 LCD_Print(celsius_temp); // print celsius_temp LCD_Goto(6, 2); // go to column 6 row 2 LCD_Print(kelvin_temp); // print kelvin_temp } } // end of code. |
Discover more from Simple Circuit
Subscribe to get the latest posts sent to your email.
Thank you very much 🙂
Kelvin = (read_adc() + 1) * 0.4;
read_adc() + 1 => Why you added 1?
A 0V is represented by 0 and 4.096V is represented by 1023, by adding 1 the 4.096V will by represented by 1024 (internal reference voltage is 4.096V) and hence we get the temperature in Kelvin.
You can remove it, there will be no big effect!