Temperature Sensor (DS18S20 + PIC16F877A)
Here's a temperature sensor (thermometer) circuit that you can easily
build. It uses the popular PIC 16F877A microcontroller. The temperature
sensor is DS18S20. The DS18S20 communicates through the one-wire protocol. The PIC16F877A communicates with the DS18S20 with the one-wire protocol and gets the information for the temperature and displays it on the LCD.
The temperature range of this circuit is -55'C to +125'C.
The methods of communicating with the DS18S20 and sending/receiving commands, and reading the temperature value, are all explained in the DS18S20 datasheet (datasheets.maximintegrated.com/en/ds/DS18S20.pdf).
Here is the code for the PIC16F877A:
(You can download the source file from: https://rapidshare.com/files/1817975964/DS18S20PIC16F877A.c)
--------------------------------------------------------------------------------------------------------------
//Programmer: Syed Tahmid Mahbub
//Compiler: mikroC PRO for PIC v4.60
//Target PIC: PIC16F877A
--------------------------------------------------------------------------------------------------------------
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;
sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
unsigned char TempH;
unsigned char TempL;
unsigned char TLow;
unsigned char vDisp[9];
unsigned char DP;
void main() {
PORTB = 0;
TRISB = 0;
LCD_Init();
LCD_CMD(_LCD_CURSOR_OFF);
LCD_CMD(_LCD_CLEAR);
PORTD = 0;
TRISD = 0x01;
delay_ms(200); //Wait for sensor and LCD to stabilize
//vDisp = "+124.5 'C"
vDisp[4] = '.';
vDisp[7] = 39; // '
vDisp[8] = 'C';
LCD_Out(1,1, "Temp:");
while (1){
OW_Reset(&PORTD, 0); // 'Reset command to initialize One-Wire
OW_Write(&PORTD, 0, 0xCC); // 'Skip ROM Command
OW_Write(&PORTD, 0, 0x44); // 'Convert_T command
delay_ms(800); // 'Provide delay for conversion
RD7_bit = ~RD7_bit;
OW_Reset(&PORTD, 0); // 'Reset command to initialize One-Wire
OW_Write(&PORTD, 0, 0xCC); // 'Skip ROM Command
OW_Write(&PORTD, 0, 0xBE); // 'Read Scratchpad Command
TempL = OW_Read(&PORTD,0); //Read Temperature low byte
TempH = OW_Read(&PORTD,0); //Read Temperature high byte
DP = TempL & 0x01; // 'Check if Temperature is integer or fractional
if (TempH){ //If reading is negative
vDisp[0] = '-';
TempL = ((~TempL) + 1) >> 1;
}
else{
vDisp[0] = '+';
TempL = TempL >> 1; // 'Shift one position right (divide by 2) to get integer reading and get rid of decimal point
}
vDisp[1] = (TempL / 100) + 48; // 'Get hundreds and convert to ASCII
vDisp[2] = ((TempL / 10) % 10) + 48; // 'Get tens and convert to ASCII
vDisp[3] = (TempL % 10) + 48; // 'Get units and convert to ASCII
if (DP){ // 'If reading is fractional, ie has 0.5 at end
vDisp[5] = '5';
}
else{ // 'If reading is a whole number
vDisp[5] = '0';
}
Lcd_Chr(1,8, vDisp[0]);
Lcd_Chr(1,9, vDisp[1]);
Lcd_Chr(1,10, vDisp[2]);
Lcd_Chr(1,11, vDisp[3]);
Lcd_Chr(1,12, vDisp[4]);
Lcd_Chr(1,13, vDisp[5]);
Lcd_Chr(1,14, vDisp[6]);
Lcd_Chr(1,15, vDisp[7]);
Lcd_Chr(1,16, vDisp[8]);
}
}
--------------------------------------------------------------------------------------------------------------
Reference documents:
DS18S20 datasheet:datasheets.maximintegrated.com/en/ds/DS18S20.pdf
PIC16F877A datasheet: ww1.microchip.com/downloads/en/devicedoc/39582b.pdf
mikroC LCD library: http://www.mikroe.com/download/eng/documents/compilers/mikroc/pro/pic/help/lcd_library.htm
mikroC One-Wire library: http://www.mikroe.com/download/eng/documents/compilers/mikroc/pro/pic/help/onewire_library.htm
The temperature range of this circuit is -55'C to +125'C.
The methods of communicating with the DS18S20 and sending/receiving commands, and reading the temperature value, are all explained in the DS18S20 datasheet (datasheets.maximintegrated.com/en/ds/DS18S20.pdf).
Here is the code for the PIC16F877A:
(You can download the source file from: https://rapidshare.com/files/1817975964/DS18S20PIC16F877A.c)
--------------------------------------------------------------------------------------------------------------
//Programmer: Syed Tahmid Mahbub
//Compiler: mikroC PRO for PIC v4.60
//Target PIC: PIC16F877A
--------------------------------------------------------------------------------------------------------------
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;
sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
unsigned char TempH;
unsigned char TempL;
unsigned char TLow;
unsigned char vDisp[9];
unsigned char DP;
void main() {
PORTB = 0;
TRISB = 0;
LCD_Init();
LCD_CMD(_LCD_CURSOR_OFF);
LCD_CMD(_LCD_CLEAR);
PORTD = 0;
TRISD = 0x01;
delay_ms(200); //Wait for sensor and LCD to stabilize
//vDisp = "+124.5 'C"
vDisp[4] = '.';
vDisp[7] = 39; // '
vDisp[8] = 'C';
LCD_Out(1,1, "Temp:");
while (1){
OW_Reset(&PORTD, 0); // 'Reset command to initialize One-Wire
OW_Write(&PORTD, 0, 0xCC); // 'Skip ROM Command
OW_Write(&PORTD, 0, 0x44); // 'Convert_T command
delay_ms(800); // 'Provide delay for conversion
RD7_bit = ~RD7_bit;
OW_Reset(&PORTD, 0); // 'Reset command to initialize One-Wire
OW_Write(&PORTD, 0, 0xCC); // 'Skip ROM Command
OW_Write(&PORTD, 0, 0xBE); // 'Read Scratchpad Command
TempL = OW_Read(&PORTD,0); //Read Temperature low byte
TempH = OW_Read(&PORTD,0); //Read Temperature high byte
DP = TempL & 0x01; // 'Check if Temperature is integer or fractional
if (TempH){ //If reading is negative
vDisp[0] = '-';
TempL = ((~TempL) + 1) >> 1;
}
else{
vDisp[0] = '+';
TempL = TempL >> 1; // 'Shift one position right (divide by 2) to get integer reading and get rid of decimal point
}
vDisp[1] = (TempL / 100) + 48; // 'Get hundreds and convert to ASCII
vDisp[2] = ((TempL / 10) % 10) + 48; // 'Get tens and convert to ASCII
vDisp[3] = (TempL % 10) + 48; // 'Get units and convert to ASCII
if (DP){ // 'If reading is fractional, ie has 0.5 at end
vDisp[5] = '5';
}
else{ // 'If reading is a whole number
vDisp[5] = '0';
}
Lcd_Chr(1,8, vDisp[0]);
Lcd_Chr(1,9, vDisp[1]);
Lcd_Chr(1,10, vDisp[2]);
Lcd_Chr(1,11, vDisp[3]);
Lcd_Chr(1,12, vDisp[4]);
Lcd_Chr(1,13, vDisp[5]);
Lcd_Chr(1,14, vDisp[6]);
Lcd_Chr(1,15, vDisp[7]);
Lcd_Chr(1,16, vDisp[8]);
}
}
--------------------------------------------------------------------------------------------------------------
Reference documents:
DS18S20 datasheet:
PIC16F877A datasheet: ww1.microchip.com/downloads/en/devicedoc/39582b.pdf
mikroC LCD library: http://www.mikroe.com/download/eng/documents/compilers/mikroc/pro/pic/help/lcd_library.htm
mikroC One-Wire library: http://www.mikroe.com/download/eng/documents/compilers/mikroc/pro/pic/help/onewire_library.htm
This comment has been removed by the author.
ReplyDeleteI have used DS18B20. But the program does not work properly. It shows different temperature. Please give me some suggestion.
ReplyDeleteThe DS18B20 is slightly different from the DS18S20, which is what is used in my circuit.
ReplyDeleteFor a comparison of the 2 devices, check this out:
http://www.maximintegrated.com/app-notes/index.mvp/id/4377
For a circuit/code utilizing DS18B20, check out:
http://www.edaboard.com/thread279990.html#post1199130
Regards,
Tahmid.
hello tahmid , i am using led instead of lcd ,can i use this coding ? if not ,can you give some suggestion regarding the code , ireally need your help , this is for my final year project ,my email : zu_aida87@yahoo.com
ReplyDeleteYou need to change the code that handles the display. The LCD code is written for the HD44780 controller. You need to change that to be able to display to an LED display.
Deletetahmid brother, i've made a project using 18b20 from ur codes given here.but the problem is that i have added a relay for certain range of temperature.i have used register A for that.the relay is fluctuating. it should be turn on and remain steady.here is my code:
ReplyDelete// LCD module connections
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;
sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
// End LCD module connections
// Set TEMP_RESOLUTION to the corresponding resolution of used DS18x20 sensor:
// 18S20: 9 (default setting; can be 9,10,11,or 12)
// 18B20: 12
const unsigned short TEMP_RESOLUTION = 12;
char *text = "000.00";
unsigned temp;
void Display_Temperature(unsigned int temp2write) {
const unsigned short RES_SHIFT = TEMP_RESOLUTION - 8;
unsigned char temp_whole;
unsigned int temp_fraction;
PORTA=0;
TRISA=0;
// Check if temperature is negative
if (temp2write & 0x8000) {
LCD_Chr(2,4,'-');
temp2write = ~temp2write + 1;
}
else{
LCD_Chr(2,4,' ');
}
// Extract temp_whole
temp_whole = temp2write >> RES_SHIFT ;
//led blinking
if(temp_whole>=20 && temp_whole<40)
{
porta.f0=1;
}
if(temp_whole>=40 && temp_whole<60)
{
portd.f1=1;
}
if(temp_whole>=60)
{
portd.f2=1;
}
// Convert temp_whole to characters
if (temp_whole/100)
text[0] = temp_whole/100 + 48;
else
text[0] = '0';
text[1] = (temp_whole/10)%10 + 48; // Extract tens digit
text[2] = temp_whole%10 + 48; // Extract ones digit
// Extract temp_fraction and convert it to unsigned int
temp_fraction = temp2write << (4-RES_SHIFT);
temp_fraction &= 0x000F;
temp_fraction *= 625;
// Convert temp_fraction to characters
text[4] = temp_fraction/1000 + 48; // Extract thousands digit
text[5] = (temp_fraction/100)%10 + 48; // Extract hundreds digit
// Print temperature on LCD
Lcd_Out(2, 5, text);
}
void main() {
ADCON1=0x06;
Lcd_Init(); // Initialize LCD
Lcd_Cmd(_LCD_CLEAR); // Clear LCD
Lcd_Cmd(_LCD_CURSOR_OFF); // Turn cursor off
Lcd_Out(1, 1, " Temperature: ");
// Print degree character, 'C' for Centigrades
Lcd_Chr(2,11,223); // Different LCD displays have different char code for degree
// If you see greek alpha letter try typing 178 instead of 223
Lcd_Chr(2,12,'C');
//--- Main loop
do {
//--- Perform temperature reading
Ow_Reset(&PORTE, 2); // Onewire reset signal
Ow_Write(&PORTE, 2, 0xCC); // Issue command SKIP_ROM
Ow_Write(&PORTE, 2, 0x44); // Issue command CONVERT_T
Delay_us(120);
Ow_Reset(&PORTE, 2);
Ow_Write(&PORTE, 2, 0xCC); // Issue command SKIP_ROM
Ow_Write(&PORTE, 2, 0xBE); // Issue command READ_SCRATCHPAD
temp = Ow_Read(&PORTE, 2);
temp = (Ow_Read(&PORTE, 2) << 8) + temp;
//--- Format and display result on Lcd
Display_Temperature(temp);
Delay_ms(500);
} while (1);
}
Dear Tahmid,,
ReplyDeleteit 's good project..,,,can you post the code using hitech compiler
Hello all !!! Masud Al Hasan -> your problem in code (led blinking) is caused by TRISA & PORTA . This command must to be out of ,, void Display_Temperature(unsigned int temp2write) " , at the begining of code. Good luck ;)
ReplyDeletehello, i need DS1822 codes to connect it with pic16f877a some help please
ReplyDeleteDear Tahmid,
ReplyDeleteIf I using DS18S20 to detect the temperature and i want it (the temperature) shows visual basic in my PC . can I get some help and suggestion please my email : claralavita52@gmail.com
thank you
Hello .
ReplyDeleteYour ds18s20 code is good work just protues . But when i work real hardware not working. Why not work what's problem can you help me this code.
Hello .
ReplyDeleteYour ds18s20 code is good work just protues . But when i work real hardware not working. Why not work what's problem can you help me this code.