How to build a simple and cheap thermometer with a PIC using a silicon diode as temperature sensor.

Overview

This project shows how to build a simple and cheap thermometer with a PIC using a silicon diode as temperature sensor. A silicon junction has approximately 2.3 mV/C temperature coefficient, making it suitable for basic temperature measurement.

Sensor Selection

Compared to other sensor types, diodes offer several advantages: analog output, good accuracy, easy integration with a microcontroller ADC, and very low cost.

2N2222 as sensor
2N2222 as sensor
MTS102 sensor
MTS102 sensor

Build the Circuit

Insert the diode in the TS1 socket. Cathode goes to the upper hole, anode to the middle. A 10k pull-up resistor provides approximately 0.5mA of bias current. The microcontroller is a PIC16F877A with an 8 MHz crystal. JP14 selects the RE2 input.

Source Code

The firmware uses Timer0 ISR for display multiplexing. The ADC reads RE2 for temperature measurement. Temperature coefficient conversion translates the ADC value to degrees. RD7 toggles between Fahrenheit and Celsius display. Calibration is performed with RD0/RD1 buttons. Resolution is approximately 2C steps.

pic-thermometer.c
/*
 * PIC DIGITAL THERMOMETER USING A SILICON JUNCTION SENSOR
 * target : PIC16F877A, 8 Mhz
 */

#define INCREF          PORTD.F0
#define DECREF          PORTD.F1
#define UNIT            PORTD.F7

#define SA      1
#define SB      2
#define SC      4
#define SD      8
#define SE      16
#define SF      32
#define SG      64
#define DP      128

const   unsigned char segment[10] =
        {
        SA+SB+SC+SD+SE+SF,
        SB+SC,
        SA+SB+SG+SE+SD,
        SA+SB+SG+SC+SD,
        SF+SG+SB+SC,
        SA+SF+SG+SC+SD,
        SA+SF+SG+SE+SC+SD,
        SA+SB+SC,
        SA+SB+SC+SD+SE+SF+SG,
        SA+SB+SC+SD+SF+SG
        } ;

#define segDEG  SA+SB+SF+SG
#define segMINUS        SG
#define segF    SA+SE+SF+SG
#define segC    SA+SD+SE+SF

long    cntr ;
unsigned char data[4] ;
unsigned char dcurr ;
unsigned char   fahrenheit = 0 ;
int     temp ;
int     ref = 116 ;

unsigned char   modulo10Seg(unsigned char v, unsigned char m)
        {
        return((m || v) ? segment[v % 10] : 0) ;
        }

void    interrupt(void)
        {
        if(INTCON.T0IF)
                {
                cntr++ ;
                dcurr++ ;
                PORTB = 0 ;
                if(dcurr == 4)
                        {
                        PORTA = 0b00000001 ;
                        dcurr = 0 ;
                        }
                else
                        {
                        PORTA <<= 1 ;
                        }
                PORTB = data[dcurr] ;
                INTCON.T0IF = 0 ;
                }
        }

main()
        {
        TRISB = 0 ;
        PORTB = 0 ;
        TRISD = 0xff ;
        OPTION_REG = 0x80 ;
        INTCON = 0xA0 ;
        for(;;)
                {
                if(cntr >= 4000)
                        {
                        ADCON1 = 0x00 ;
                        TRISA = 0xff ;
                        temp = ref - Adc_Read(7) ;
                        ADCON1 = 0x07 ;
                        TRISA = 0 ;
                        temp *= 221 ;
                        temp /= 102 ;
                        temp = 25 + temp ;
                        if(fahrenheit)
                                {
                                temp = ((90 * temp) / 50 ) + 32 ;
                                }
                        if(temp < 0)
                                {
                                data[0] = segMINUS ;
                                data[1] = modulo10seg(temp / 10, 0) ;
                                }
                        else
                                {
                                data[0] = modulo10seg(temp / 100, 0) ;
                                data[1] = modulo10seg(temp / 10, 1) ;
                                }
                        data[2] = modulo10seg(temp, 1) ;
                        data[3] = fahrenheit ? segF : segC ;
                        cntr = 0 ;
                        }
                if(PORTD)
                        {
                        if(INCREF)
                                {
                                ref++ ;
                                data[0] = modulo10seg(ref / 1000, 0) ;
                                data[1] = modulo10seg(ref / 100, 1) ;
                                data[2] = modulo10seg(ref / 10, 1) ;
                                data[3] = modulo10seg(ref, 1) ;
                                }
                        else if(DECREF)
                                {
                                ref-- ;
                                data[0] = modulo10seg(ref / 1000, 0) ;
                                data[1] = modulo10seg(ref / 100, 1) ;
                                data[2] = modulo10seg(ref / 10, 1) ;
                                data[3] = modulo10seg(ref, 1) ;
                                }
                        else if(UNIT)
                                {
                                fahrenheit = !fahrenheit ;
                                data[0] = 0 ;
                                data[1] = segDEG ;
                                data[2] = fahrenheit ? segF : segC ;
                                data[3] = 0 ;
                                }
                        while(PORTD) ;
                        cntr = 0 ;
                        }
                }
        }