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.
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 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 ; } } }