Wednesday, September 30, 2009

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.

 
 

19 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

Microcontroller-based Embedded Systems Design