PIC16F877A Thermometer with MCP9700A

Using a Microchip MCP9700A analog temperature sensor

MCP9700A with PIC16F877A on EasyPIC4

Using a Microchip MCP9700A analog temperature sensor: cheap, easy to use, factory calibrated, plug and play.

Overview

Low power linear active thermistor. 3 pins (ground, power, output), -40 to +125 C with +/- 2C accuracy, 2.3V to 5.5V supply, 6 uA operating current, +10mV/C temperature coefficient. 500mV output = 0C.

MCP9700A output voltage curve

Plug and Play

On the EasyPIC board, put the MCP9700A in the DS1820 socket. Connect JP14 to RE2.

Circuit Schematic

MCP9700A circuit LCD thermometer display

C Source Code

mcp9700a_thermometer.c
/*
 *******************************************************************************
 * PIC DIGITAL THERMOMETER USING A MICROCHIP MCP9700A ANALOG SENSOR
 *******************************************************************************
 *
 * source code example for mikroC users
 * feel free to use this code at your own risks
 *
 * target : PIC16F877A, 8 Mhz crystal
 * HS clock, no watchdog.
 *
 * easyPIC4 settings :
 *      MCP9700A on DS1820 socket, see web page for more details.
 *
 *******************************************************************************
 */

/*
 * LCD_printfix constants
 */
#define INT_RANGE   1000    // integer part : 3 digits
#define DEC_RANGE   10      // decimal part : 1 digit

/*
 * this counter is incremented on each TIMER0 overflow
 */
unsigned int cntr ;

long    temp ;          // Temperature in Celcius * 10
int     fahr ;          // Temperature in Fahrenheit * 10

/*
 * offset reference of the sensor : 0C is 500 mV => 102.4
 * since the sensor is factory calibrated, there is no need for adjustment
 */
int     ref = 1024 ;            // offset multiplied by 10 for tenth of degrees

/*
 * LCD character definitions (generated by mikroC LCD Custom Character tool)
 */
const char characterC[] = {8,20,8,0,3,4,4,3};   // C degree symbol
const char characterF[] = {8,20,8,0,7,4,6,4};   // F degree symbol

/*
 * print custom character on LCD
 */
void CustomChar(const char *def, unsigned char n, char pos_row, char pos_char)
        {
        char    i ;

        LCD_Cmd(64 + n * 8) ;
        for(i = 0 ; i <= 7 ; i++)
                {
                LCD_Chr_Cp(def[i]) ;
                }
        LCD_Cmd(LCD_RETURN_HOME) ;
        LCD_Chr(pos_row, pos_char, n) ;
        }

/*
 * print v with fixed-size integer and decimal parts
 */
void    LCD_printFix(unsigned int v)
        {
        unsigned int w ;
        unsigned int d ;
        unsigned char n ;
        unsigned char  blk = 1 ;           // zero blanking

        if(v >= 0)
                {
                LCD_Chr_Cp('+') ;
                }
        else
                {
                LCD_Chr_Cp('-') ;
                }

        v = abs(v) ;
        w = v / DEC_RANGE ;
        for(d = INT_RANGE / 10 ; d > 0 ; d /= 10)
                {
                n = (w / d) % 10 ;
                if(n)
                        {
                        blk = 0 ;
                        }
                if(blk)
                        {
                        LCD_Chr_Cp(' ') ;
                        }
                else
                        {
                        LCD_Chr_Cp('0' + n) ;
                        }
                }
        LCD_Chr_Cp('.') ;
        w = v % DEC_RANGE ;
        for(d = DEC_RANGE / 10 ; d > 0 ; d /= 10)
                {
                LCD_Chr_Cp('0' + (w / d) % 10) ;
                }
        }

/*
 * interrupt routine, called on each timer0 overflow
 */
void    interrupt(void)
        {
        if(INTCON.T0IF)
                {
                cntr++ ;
                INTCON.T0IF = 0 ;
                }
        }

/*
 * program entry
 */
void    main()
        {
        ADCON1 = 0x00 ;                         // PORTA as analog input
        TRISA = 0xff ;                          // PORTA as inputs
        TRISD = 0 ;                             // PORTD is output
        LCD_Init(&PORTD) ;                      // Initialize LCD on PORTD
        LCD_Cmd(Lcd_CLEAR) ;
        LCD_Cmd(Lcd_CURSOR_OFF) ;
        LCD_Out(1, 1, "MCP9700A EXAMPLE") ;

        OPTION_REG = 0x80 ;                     // start timer 0, no prescaler
        INTCON = 0xA0 ;                         // allow timer 0 overflow interrupt

        for(;;)
                {
                if(cntr >= 4000)                // enough time since last sample
                        {
                        /*
                         * read the sensor
                         */
                        temp = Adc_Read(7) * 10 - ref ;      // read RE2 ADC, adjust to 0C

                        /*
                         * get the result in celcius * 10
                         * sensor coefficient is +10mV/C
                         * ADC resolution is 5000/1024 = 4.88 mV
                         * one ADC point is 0.488C
                         */
                        temp *= 488 ;
                        temp /= 1000 ;

                        fahr = ((9 * temp) / 5 ) + 320 ;       // convert C to F * 10

                        /* print temperature in C on LCD */
                        LCD_Out(2, 1, "") ;
                        LCD_printFix(temp) ;
                        CustomChar(characterC, 0, 2, 7) ;

                        /* print temperature in F on LCD */
                        LCD_Out(2, 10, "") ;
                        LCD_printFix(fahr) ;
                        CustomChar(characterF, 1, 2, 16) ;

                        cntr = 0 ;
                        }
                }
        }