Hello
My project is working partially. I have designed a temperature display on LCD project that involves
the following components...
PIC18F4423
ceramic 20Mhz
C18 compiler
Thermistor: MCP9701A
LCD: 16X2
Im using full 12bit ADC and +Vref == VDD and -Vref == VSS.
Im displaying both the ADC value and the corresponding temperature on the LCD display.
The problem is that my temperature display output is about 12deg higher than the actual corresponding
ADC value display output. For example....
LCD output:
Line 1 reads: 670 (ADC value)
Line 2 reads: 34.3 C
Now according to this formula Vin == [(670)x(5)] / (4096) .... gives '817mV' which is '21.4C'
21.4C is what my precision digital thermometer is also displaying. So that is how i know that my ADC
value is displaying correctly...and that its the displayed temperature value that is 12 deg higher.
Usally the offset value is adjusted by a few bits only....I on the other hand have had to increase the offset
value to 100 steps more and then my temp read out displays correctly. BUT this is not good since when i go
down to -2C....then the displayed temperature value drops to -9C....and that is WAY too much offset! Also
the offset value 328 is properly caluculated as follows...
For the thermistor used:
1degC == 19.5mV
so 0.0626degC == 1.2207mV
And 1 ADC bit corresponds to 5/4096 == 1.2207mV
So 0degC or 400mV (factory calibrated setting of thermistor) == 328 ADC bits
So please can some one have a look at my code below and kindly suggest why the error in temp display?
Thank you
Haseeb
My project is working partially. I have designed a temperature display on LCD project that involves
the following components...
PIC18F4423
ceramic 20Mhz
C18 compiler
Thermistor: MCP9701A
LCD: 16X2
Im using full 12bit ADC and +Vref == VDD and -Vref == VSS.
Im displaying both the ADC value and the corresponding temperature on the LCD display.
The problem is that my temperature display output is about 12deg higher than the actual corresponding
ADC value display output. For example....
LCD output:
Line 1 reads: 670 (ADC value)
Line 2 reads: 34.3 C
Now according to this formula Vin == [(670)x(5)] / (4096) .... gives '817mV' which is '21.4C'
21.4C is what my precision digital thermometer is also displaying. So that is how i know that my ADC
value is displaying correctly...and that its the displayed temperature value that is 12 deg higher.
Usally the offset value is adjusted by a few bits only....I on the other hand have had to increase the offset
value to 100 steps more and then my temp read out displays correctly. BUT this is not good since when i go
down to -2C....then the displayed temperature value drops to -9C....and that is WAY too much offset! Also
the offset value 328 is properly caluculated as follows...
For the thermistor used:
1degC == 19.5mV
so 0.0626degC == 1.2207mV
And 1 ADC bit corresponds to 5/4096 == 1.2207mV
So 0degC or 400mV (factory calibrated setting of thermistor) == 328 ADC bits
So please can some one have a look at my code below and kindly suggest why the error in temp display?
Thank you
Haseeb
Code:
#include <p18f4423.h>
#include <delays.h>
#pragma config OSC = HS
#pragma config WDT = OFF
#pragma config LVP = OFF
void SendLCD(unsigned char Byte, unsigned char type); //LCD display function
#define LCD LATD //LCD Latch PORT
#define LCD_RS LATEbits.LATE0 //Register Select (0: Instruction/ 1: Data)
#define LCD_E LATEbits.LATE2 //Enable (Starts data read/write)
#define LED LATCbits.LATC3 //power up LED
unsigned char minus = 0; //-ve flag...for -ve sign activation
unsigned int
bin = 0, //temp buffer variable for ADC value for BCD conversion process
binADC = 0, //buffer variable for showing direct ADC value on LCD
//BCD coversion variables
d0 = 0,
d1 = 0,
d2 = 0;
void main(void)
{
//Configure ADC
ADCON1 = 0b00001110; //VREF- = VSS,
//VREF+ = VDD,
//Enable AN0 only...rest all Digital
ADCON0 = 0b00000000; //Select channel 0 (AN0),
//ADC Idle,
//ADC Dissabled
ADCON2 = 0b10001000; //Right Justified for 12bit ADC scaling
//ADC Acquisition Time 2TAD,
//ADC Conversion Clock FOSC/2
PORTA = 0; //initiallize PORTA
TRISAbits.TRISA0 = 1; // Analog Channel 0 (AN0 input)
PORTB = 0; //intialize PORTB
TRISBbits.TRISB3 = 1; //swtich 1 input
TRISBbits.TRISB4 = 1; //switch 2 input
TRISBbits.TRISB5 = 1; //switch 3 input
PORTC = 0; //intialize PORTC
TRISCbits.TRISC3 = 0; //LED
PORTD = 0; //initiallize PORTD
TRISD = 0x00; //LCD output
PORTE = 0; //initiallize PORTE
TRISEbits.TRISE0 = 0; //LCD Register Select (to LCD Pin 4)
TRISEbits.TRISE2 = 0; //LCD Enable (to LCD Pin 6)
INTCON = 0; //dissable all interrupts
Delay10KTCYx(10); //20ms wait for LCD power up
//Initialize the LCD
LCD = 0x00; //clear LCD PORTD pins
Delay1KTCYx(25); //delay 5mS
SendLCD(0x03,0); //Initialization command
Delay1KTCYx(25); //delay 5mS
SendLCD(0x03,0); //Initialization command
Delay100TCYx(8); //delay 160uS
SendLCD(0x03,0); //Initialization command
Delay100TCYx(8); //delay 160uS
SendLCD(0x3C,0); //Interface lenght is 8 bits long, 2-lines, 5x10 dots
Delay100TCYx(8); //delay 160uS
SendLCD(0x10,0); //Turn off LCD
Delay100TCYx(8); //delay 160uS
SendLCD(0x01,0); //Clear LCD
Delay1KTCYx(25); //delay 5mS
SendLCD(0x06,0); //Increment the cursor after each byte written
Delay100TCYx(8); //delay 160uS
SendLCD(0x0C,0); //Turn on LCD, cursor off, cursor blinking off
Delay100TCYx(8); //delay 160uS
//Power up flashing LED
LED = 1;
Delay10KTCYx(125); //250ms delay
LED = 0;
Delay10KTCYx(125); //250ms delay
LED = 1;
Delay10KTCYx(125); //250ms delay
LED = 0;
ADCON0bits.ADON = 1; //Enable ADC
while(1) //loop forever
{
/********************** READING 12bit ADC value ************************************/
ADCON0bits.GO_DONE = 1; //Start ADC Conversion
while (ADCON0bits.GO_DONE == 1); //Wait until Conversion finishes
bin = (ADRESH * 256) + ADRESL; //12bit ADC read...Merging High byte with low byte
/***********************************************************************************/
/*********** Below steps are for displaying the ADC value on LCD ***************/
binADC = bin; //assigning ADC value to buffer variable
//convert ADC value to BCD
d2 = binADC % 10;
d1 = (binADC / 10) % 10;
d0 = ((binADC / 10) / 10) % 10;
//convert BCD digit numbers to ASCII text characters for LCD
d0 += '0';
d1 += '0';
d2 += '0';
SendLCD(0x80,0); //activate LCD line 1
//print the ADC value on LCD
SendLCD(d0,1);
SendLCD(d1,1);
SendLCD(d2,1);
/*******************************************************************************/
/********************* Below are the steps to display the temperature on LCD ********************/
if(bin < 328) //below 0 deg C ... (0 deg C @ 400mV)
{
minus = 1; //activate -ve sign
bin = 328 - bin; //offset adjustment ... (0 deg C @ 400mV)
}
else
bin = bin - 328; //offset adjustment ... (0 deg C @ 400mV)
//convert ADC value to BCD
d2 = bin % 10;
d1 = (bin / 10) % 10;
d0 = ((bin / 10) / 10) % 10;
//convert BCD digit numbers to ASCII text characters for LCD
d0 += '0';
d1 += '0';
d2 += '0';
SendLCD(0xC0,0); //activate LCD line 2
//if temperature is in -ve ... then print -ve sign on LCD
if(minus == 1)
{
SendLCD('-',1);
minus = 0; //reset minus sign flag
}
else //temperature is in +ve so erase minus sign (blank space print)
SendLCD(' ',1);
//print the temperature on LCD
SendLCD(d0,1);
SendLCD(d1,1);
SendLCD('.',1);
SendLCD(d2,1);
SendLCD('C',1);
/********************************************************************************************/
Delay10KTCYx(250); //500ms cycle delay
}// end of main while loop
} //end of main()
void SendLCD(unsigned char Byte, unsigned char type)
{
LCD_RS = type; //Set whether it is a Command (0) or Data/Char (1)
Delay100TCYx(8); //delay 160uS
LCD = Byte; //assign the new data to the LCD PORTD
Delay100TCYx(8); //delay 160uS
LCD_E = 1; //Set Enable High
Delay100TCYx(8); //delay 160uS
LCD_E = 0; //Set Enable Low
}