Skip to main content

Experiment No. 4 : Reading Temperature Values from DS1820 using 1-Wire Protocol

In this experiment, we are going to build a digital temperature meter using DS1820 connected to our PIC16F628A development board. The temperature value will be displayed on the LCD display. I have modified the sample program that comes with the compiler according to our PIC board requirements. Also I have elaborated comments in the program so that every step will be more clear to the readers.

Experimental Setup:
The experimental setup is very straight-forward. Place DS1820 device on the three-pin female header that we recently added to our board. And also connect the data pin of DS1820 to RB.0 pin of PIC16F628A using a jumper wire.

 
 Circuit Diagram
 
Software:
Here is the program written in microC that reads temperature values from DS1820 device using OneWire Library.
/* Project name:
     One Wire Communication Test between PIC16F628A and DS1820
 * Copyright:
     (c) Rajendra Bhatt, 2009.
 * Description:
     This code demonstrates how to use One Wire Communication Protocol
     between PIC16F628A and a 1-wire peripheral device. The peripheral
     device used here is DS1820, digital temperature sensor.
     MCU:             PIC16F628A
     Oscillator:      XT, 4.0 MHz
*/
// LCD connections definitions
sbit LCD_RS at RA0_bit;
sbit LCD_EN at RA1_bit;
sbit LCD_D4 at RB4_bit;
sbit LCD_D5 at RB5_bit;
sbit LCD_D6 at RB6_bit;
sbit LCD_D7 at RB7_bit;
sbit LCD_RS_Direction at TRISA0_bit;
sbit LCD_EN_Direction at TRISA1_bit;
sbit LCD_D4_Direction at TRISB4_bit;
sbit LCD_D5_Direction at TRISB5_bit;
sbit LCD_D6_Direction at TRISB6_bit;
sbit LCD_D7_Direction at TRISB7_bit;
// End LCD connections definitions

// String array to store temperature value to display
char *temp = "000.00";

// Temperature Resolution : No. of bits in temp value = 9
const unsigned short TEMP_RES = 9;

// Variable to store temperature register value
unsigned temp_value;

void Display_Temperature(unsigned int temp2write) {
  const unsigned short RES_SHIFT = TEMP_RES - 8;

  // Variable to store Integer value of temperature
  char temp_whole;

  // Variable to store Fraction value of temperature
  unsigned int temp_fraction;
  unsigned short isNegative = 0x00; 

  // check if temperature is negative
  if (temp2write & 0x8000) {
     temp[0] = '-';
     // Negative temp values are stored in 2's complement form
     temp2write = ~temp2write + 1;
     isNegative = 1;   // Temp is -ive
     }

  // Get temp_whole by dividing by 2 (DS1820 9-bit resolution with 
  // 0.5 Centigrade step )
  temp_whole = temp2write >> RES_SHIFT ;


  // convert temp_whole to characters
 if (!isNegative) {
     if (temp_whole/100)
   // 48 is the decimal character code value for displaying 0 on LCD
     temp[0] = temp_whole/100  + 48;
     else
     temp[0] = '0';
  }

  temp[1] = (temp_whole/10)%10 + 48;             // Extract tens digit
  temp[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
  temp[4] =  temp_fraction/1000    + 48;         // Extract tens digit
  temp[5] = (temp_fraction/100)%10 + 48;         // Extract ones digit

  // print temperature on LCD
  Lcd_Out(2, 5, temp);
}

void main() {
  CMCON  |= 7;                       // Disable Comparators
  Lcd_Init();                                    // Initialize LCD
  Lcd_Cmd(_LCD_CLEAR);                           // Clear LCD
  Lcd_Cmd(_LCD_CURSOR_OFF);                      // Turn cursor off
  Lcd_Out(1, 3, "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(&PORTB, 0);      // Onewire reset signal
    Ow_Write(&PORTB, 0, 0xCC);   // Issue command SKIP_ROM
    Ow_Write(&PORTB, 0, 0x44);   // Issue command CONVERT_T
    Delay_ms(600);
    // If this delay is less than 500ms, you will see the first reading on LCD 
    //85C which is (if you remember from my article on DS1820) 
    //a power-on-reset value. 
    
    Ow_Reset(&PORTB, 0);
    Ow_Write(&PORTB, 0, 0xCC);    // Issue command SKIP_ROM
    Ow_Write(&PORTB, 0, 0xBE);    // Issue command READ_SCRATCHPAD

    // Read Byte 0 from Scratchpad
    temp_value =  Ow_Read(&PORTB, 0);
    // Then read Byte 1 from Scratchpad and shift 8 bit left and add the Byte 0
    temp_value = (Ow_Read(&PORTB, 0) << 8) + temp_value;

    //--- Format and display result on Lcd
    Display_Temperature(temp_value);

    } while (1);
}

Experimental Output:
The temperature reading will be displayed on the LCD screen and will be updated every 600ms. Look at some snapshots below showing output.

 
 

Comments

  1. Hi mr Raj.
    Do you have a single example with 7 segments displays?
    Tanks.

    ReplyDelete
  2. Hello Mr. Raj i have been testes both version of temperature sensor (DS1820 and DS18B20) and i found a little bug, in both version cannot display symbol "-" when read a negative temperature.
    Do you have any idea how to solve this problem?
    I try to solve the problem by myself, with no results.
    By the way you did a great gob with this site.

    Regards,
    ducu

    ReplyDelete
  3. My code should work to display negative temperature too. Negative temperature are in 2's complement form, see my code
    // check if temperature is negative
    if (temp2write & 0x8000) {
    temp[0] = '-';
    // Negative temp values are stored in 2's complement form
    temp2write = ~temp2write + 1;
    }

    ReplyDelete
  4. Fabio,
    Here is my experiment with Seven segment Displays.
    http://pic16f628a.blogspot.com/2009/10/experiment-no-5-multiplexed-seven.html

    ReplyDelete
  5. Dear Sir,
    I used DS18S20. it did not works it shows 'Temperature:
    000.00 C
    no temperature detects. I use same code. whats wrong?
    Nimal

    ReplyDelete
  6. Try increasing the delay_ms(600) to delay_ms(800) and see if it works.

    Ow_Write(&PORTB, 0, 0x44);
    Delay_ms(800);
    // If this delay is less than 500ms, you will see the first reading on

    Also Read this
    http://www.picbasic.co.uk/forum/showthread.php?t=13388

    ReplyDelete
  7. If LCD is 10 meters away from DS18S20 what kind of cable I have to used?

    ReplyDelete
  8. i want this circuit diagram anybody help me

    ReplyDelete
  9. Krishna,
    I have posted the circuit diagram. Enjoy!

    ReplyDelete
  10. do you have hex for this example

    ReplyDelete
  11. Kuzmin,
    Here it is
    http://embedded-lab.com/uploads/HexFiles/PIC16F628A/PIC16F628A_DS1820.zip

    ReplyDelete
  12. hello;
    I'm working on a development board where the peak and the LCD are already connected together, I have to connect the sensor SRF02 as extention, but when I run C code on the LCD I get a funny message! and I don't know whence the error!

    Here is my source code I use(MikroC):


    /*Project name: SRF02 */

    #include "SRF02_SIMPLE.h"


    // LCD module connections
    sbit LCD_RS at LATD2_bit;
    sbit LCD_EN at LATD3_bit;
    sbit LCD_D4 at LATD4_bit;
    sbit LCD_D5 at LATD5_bit;
    sbit LCD_D6 at LATD6_bit;
    sbit LCD_D7 at LATD7_bit;

    sbit LCD_RS_Direction at TRISD2_bit;
    sbit LCD_EN_Direction at TRISD3_bit;
    sbit LCD_D4_Direction at TRISD4_bit;
    sbit LCD_D5_Direction at TRISD5_bit;
    sbit LCD_D6_Direction at TRISD6_bit;
    sbit LCD_D7_Direction at TRISD7_bit;
    // End LCD module connections



    void delay2S(){ // 2 seconds delay function
    Delay_ms(1000);
    }

    //char someData[] = "SRF02";


    // Main
    void main()
    {
    int i;
    char tmpdata;
    SRF02_SIMPLE_Init(); // performs I2C initialization
    ADCON1 |= 0x0F; // Configure AN pins as digital
    CMCON |= 7;
    while(1)
    { // Disable comparators
    Lcd_Init();
    Lcd_Cmd(_LCD_CLEAR); // clear Lcd
    Lcd_Cmd(_LCD_CURSOR_OFF); // set cursor off
    // Example for single-byte read
    i = 1;
    tmpdata = 1;
    while ((tmpdata = SRF02_SIMPLE_RdSingle(i)) != 0)
    {


    Lcd_Out(1,1,"la distance est"); // Write string
    Lcd_Out(2,1,tmpdata); // Write string
    Lcd_Out(2,15,"cm");
    delay2S();
    tmpdata++;
    Lcd_Out(1,1,"la distance est"); // Write string
    Lcd_Out(2,1,tmpdata); // Write string
    Lcd_Out(2,14,"cm");
    delay2S();
    }
    i++ ;
    }

    Lcd_Cmd(_LCD_CLEAR);
    Lcd_Out(1,4,"la distance est:");
    SRF02_SIMPLE_RdSeq(2, tmpdata,10);
    Lcd_Out(2,1,tmpdata);
    }
    //}

    // SRF02 read library


    //--------------- Performs SRF02 Init
    void SRF02_SIMPLE_Init() {
    I2C1_Init(100000);
    }


    //--------------- Reads data from SRF02 - single location (random)
    unsigned short SRF02_SIMPLE_RdSingle(unsigned short rAddr)
    {
    unsigned short reslt;
    I2C1_Start(); // issue I2C1 start signal
    I2C1_Wr(0x70); // send byte via I2C1 (device address + W)
    I2C1_Wr(0x00);
    I2C1_Wr(0x51); // command to start raging in cm
    I2C1_stop(); // send stop sequence

    delay_ms(70); // delay for 70ms.

    I2C1_Start(); // issue I2C1 start signal
    I2C1_Wr(0x70); // send byte via I2C1 (device address + W)
    I2C1_Wr(rAddr); // send byte (data address)
    I2C1_Repeated_Start(); // issue I2C1 signal repeated start
    I2C1_Wr(0x71); // send byte (device address + R)
    reslt = I2C1_Rd(0u); // Read the data (NO acknowledge)
    while (!I2C1_Is_Idle())
    asm nop; // Wait for the read cycle to finish
    I2C1_Stop();
    return reslt;
    }

    //--------------- Reads data from SRF02_SIMPLE - sequential read
    void SRF02_SIMPLE_RdSeq(unsigned short rAddr,
    unsigned char *rdData,
    unsigned short rLen) {
    unsigned short i;
    I2C1_Start(); // issue I2C1 start signal
    I2C1_Wr(0x70); // send byte via I2C1 (device address + W)
    I2C1_Wr(rAddr); // send byte (address of SRF02 location)
    I2C1_Repeated_Start(); // issue I2C1 signal repeated start
    I2C1_Wr(0x71); // send byte (device address + R)
    i = 0;
    while (i < rLen) {
    rdData[i] = I2C1_Rd(1u); // read data (acknowledge)
    Delay_ms(20);
    i++ ;
    }
    rdData[i] = I2C1_Rd(0u); // last data is read (no acknowledge)
    I2C1_Stop();
    }


    I will be grateful if you can help me! Your suggestions/opinions are much much anticipated.

    KL

    ReplyDelete
  13. Mr.Raj , circuit is not working,,showing 000.50'c on lcd .... ihave made the changes as u define delay 600 to 800 tb again nt working....i m using ds18s20 or ds18b20 ....tb stil same result 000.50'c .......plz help .. :(

    ReplyDelete
  14. hi great project. But I have a problem... Im using ds1821c+ and the display shows 000.050 C, and I already changed 600ms to 800 and nothing happed.Any ideas?thank in advance for ypur help

    ReplyDelete
  15. Can you translate to hex file ?

    ReplyDelete
  16. hi it´s a great project,but does the pin 1 of the sensor needs to be grounded?
    Or can be cutted?

    thanks in advance

    ReplyDelete
  17. Nice project, but how I can read two sensors on different ports? Thanks!

    ReplyDelete

Post a Comment

Popular posts from this blog

Contact less tachometer using PIC16F628A

Introduction
Tachometer is a device that gives you the information about the rotational speed of any shaft or disc. It usually measures the speed in revolutions per minute (RPM). Today we are going to make a simple tachometer that could measure the rotation speed of a disk without making any physical contact (that's why it is contact less) with the rotating object. The range of this tachometer is 0 - 9999 RPM and displays the RPM on a multiplexed 4-digit seven-segment display. Of course, we are going to do this project on our usual PIC16F628A development board.

Infrared sensor
Contact-less measurement of RPM will be achieved through an IR sensor. An IR diode will send a beam of infrared towards the rotating disc, and any reflected pulse will be received by a photo diode. The resistance of a photo diode drops drastically when exposed to infrared. An infrared is reflected by a white surface and absorbed by the dark ones. The test disc for this project is shown below. You can see the …

Experiment No. 2 : Push Button and Seven Segment Display Interface

In this experiment, we will program the PIC16F628A as an UP/DOWN Decade Counter. The count value will be displayed on a Seven-Segment Display and will be incremented/decremented by two push buttons on the board.

Experimental Setup:
The board has built in interface for a multiplexed 4-digit seven segment display (HS-5461AS2 from www.futurlec.com).We will select only one digit by connecting a Digit Select pin to Vcc, as shown in figure below. A black jumper wire is used for this purpose. The seven segments will be driven through PORTB (already wired on the board). Connect Push Buttons (PB3 and PB4) to RA1 and RA0 female headers using jumper wires.


PIC16F628A Development Board

The development board we are going to make for our experimental microcontroller PIC16F628A will look like this. Here are the features it is going to have:
Access to all I/O pins through female header pins4 Push Buttons for Input4 LEDs for OutputAn LCD Interface PortA 4-digit Seven-Segment Display InterfaceLCD Backlight Switch and Contrast AdjustmentICSP Programming (Very Important)