PIC16F877A Thermometer with MCP9700A
Using a Microchip MCP9700A analog temperature sensor
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.
Plug and Play
On the EasyPIC board, put the MCP9700A in the DS1820 socket. Connect JP14 to RE2.
Circuit Schematic
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 ;
}
}
}