Maker Pro
Maker Pro

OneWire - DS18B20 - PIC18F4550 code query

Hello all,

I am trying to read temperature from DS18B20 sensor using the OneWire protocol (non parasitic) and a PIC18F4550 (Aptinex development board with a built-in DS18B20). I've read both OneWire and DS18B20 datasheets, then I tried to look up some example codes just to understand how it all works, but the more I tried to understand the main function part, the more confused I got. I think I understand how reset, write and read functions work (clear explanations in the datasheet), but the part that confuses me the most is how to actually read data from the sensor. Below is a code that I found somewhere on the net, and after I build it, the result is in the pic. Also, after 3 seconds, the screen goes blank. The LCD module is 100% working. I really do not understand what is going on this part:

tempL = read();
tempH = read();

tempL >>= 4;
tempH <<= 4;
tempH += tempL;
tempL = DEC2BCD(tempH);

Could someone please give any insights what is going on in that part and why the outcome is like that. Any help will be greatly appreciated!

Code:
#define _XTAL_FREQ 8000000

#include <xc.h>
#include <stdio.h>
#include "delay.h"
#include "LCD_4bit_config.h"

#define _XTAL_FREQ 8000000

#define DEC2BCD(dec) (((dec / 10) << 4) + (dec % 10))

#define Skip_ROM 0xCC                // 0b11001100
#define Convert_temperature 0x44    // 0b01000100
#define Read_scratchpad 0xBE            // 0b10111110
#define Write_scratchpad 0x4E

#define Data_pin LATB0

unsigned short tempL, tempH;

char reset()
{
TRISB0 = 0;             // Drive bus low
__delay_us(480);        // Delay 480us
TRISB0 = 1;                // Release bus
__delay_us(70);            // Delay 70us

if (Data_pin == 0)        // Sample bus
    {
        __delay_us(410);
        return 0;        // Device present
    }
    else
    {
        __delay_us(410);
        return 1;        // No device present
    }
}

write(char a)
{
    char i;
    Data_pin = 1;
   
        for (i=0;i<8;i++)
        {
            if ((a & (1<<i)) != 0 )
            {
                TRISB0 = 0;            // Write 1 bit
                Data_pin = 0;
                __delay_us(6);
                TRISB0 = 1;
                __delay_us(64);   
            }   
           
            else
            {
                TRISB0 = 0;            // Write 0 bit
                Data_pin = 0;
                __delay_us(60);
                TRISB0 = 1;   
                __delay_us(10);
            }
        }       
}

char read()
{
    char i, result = 0;
    TRISB0 = 1;                //RB0 as input
       
        for (i=0;i<8;i++)
        {
            TRISB0 = 0;        // Drive bus low
            Data_pin = 0;    // Generate low pulse for 2us
            __delay_us(6);
            TRISB0 = 1;        // Release the bus
            __delay_us(9);
           
            if (Data_pin != 0)            // Sample bus to read bit from slave
                {
                    result |= 1<<i;
                    __delay_us(55);   
                }
            return result;   
        }   
}

main()
{
    char s[20];
   
    OSCCON = 0b11110100;    // Set internal oscillator to 8 MHz
    ADCON1 = 0x0F;            // Set all pins as digital I/O
    CMCON = 0x07;             // Set all comparators as digital I/O

    TRISD = 0x00;                // Set PORTD as digital OUTPUT for the LCD
    LATD = 0;                  // Clear PORTD
   
    TRISB = 0xFF;                // Set PORTB as digital INPUT
    LATB = 0;                // Clear PORTB
   
    LCD_init();        // Initialize LCD module
    LCD_clr();
   
    while (1)
    {
        if (!reset())
        {
            write(Skip_ROM);           
            write(Convert_temperature);
            delay_ms(750);
           
            reset();
           
            write(Skip_ROM);
            write(Read_scratchpad);
           
            tempL = read();
            tempH = read();
           
            tempL >>= 4;
            tempH <<= 4;
            tempH += tempL;
            tempL = DEC2BCD(tempH);
                   
            sprintf(s,"%d  %d",tempL,tempH);
           
            LCD_setCursor(1,1);
            LCD_writeString(s);
        }   
    }
}


IMG_1352.JPG

OneWire_DS18B20.JPG
 
Finally I had a break-trough (at least I think I have), when I decided to take baby steps and : 1. Read a presence pulse; 2. Read device family code; 3. Attempt to read temperature data. So far points 1 and 2 were accomplished successfully, I was able to read the presence pulse (0) and a family code (0x28). But the last point, I am still struggling bad. I understand that in order to read temperature values, I first need to write a command to convert temperature (0x44), then reset the OneWire, give a 0.75s delay for the conversion to be completed, and then write to the scratchpad 0xBE to read from the register. I've tried combining the codes I found in maxim website and as well some other codes I found all over the web. LCD now displays Temperature: 11, when my room temperature is currently ~27 degrees C. Please can someone check my codes to see whether there is an issue somewhere? Thanks!
DS18B20 header file:
Code:
#define __XTAL_FREQ 8000000

#define Data_pin RB2
#define Data_bus TRISB2
#define Skip_ROM 0xCC                // 0b11001100
#define Convert_temperature 0x44    // 0b01000100
#define Read_scratchpad 0xBE            // 0b10111110
#define Read_deviceFamily 0x33

int OneWire_reset()
{
    Data_bus = 0;        //Set as output
    Data_pin = 0;        //Drive Low
    __delay_us(480);
    Data_bus = 1;        //Release, Set back as input
    __delay_us(70);
   
if (Data_pin == 0)        // Sample bus
    {
        __delay_us(410);
        return 0;        // Device present
    }
    else
    {
        __delay_us(410);
        return 1;        // No device present
    }
}

int OneWire_readByte(void)
{
    int l, result = 0;
    for(l=0;l<8;l++)
    {
        result >>= 1;
        if(OneWire_readBit())
            result |= 0x80;
    }
    return result;
}

int OneWire_readBit(void)
{
    unsigned int Read_state = 0;
   
    Data_bus = 0;        //Set as output
    Data_pin = 0;        //Drive low
    __delay_us(6);
    Data_bus = 1;        //Release, set as input
    __delay_us(9);
    Read_state = Data_pin;
   
    return Read_state;
}

void OneWire_writeBit(unsigned int b)
{
    Data_bus = 0;        //Set as output
       Data_pin = 0;        //Drive low

    if(b == 1)
    {
        __delay_us(3);
        Data_bus = 1;    //Release, set as input
        __delay_us(62);
    }
    else
    {
        __delay_us(57);
        Data_bus = 1;    //Release, set as input
        __delay_us(7);
    }
}

void OneWire_writeByte(unsigned int data)
{
    int l;
    for(l=0;l<8;l++)
    {
        OneWire_writeBit(data & 0x01);
        data >>= 1;
    }
}

And the main code:
Code:
#define _XTAL_FREQ 8000000

#include <xc.h>
#include <stdio.h>
#include "LCD_4bit_config.h"
#include "DS18B20_config.h"
#include "delay.h"

OneWire_init()
{
    int i;
    char buf1[10];
    char buf2[10];
       
    LCD_setCursor(1,1);
        LCD_writeString("Presence:");
       
        i = OneWire_reset();
           
        sprintf(buf1,"%d",i);
        LCD_setCursor(2,1);
        LCD_writeString(buf1);
       
        delay_ms(3000);
        LCD_clr();
           
        OneWire_reset();
       
        LCD_setCursor(1,1);
        LCD_writeString("Device family:");
           
        OneWire_writeByte(Read_deviceFamily);
           
        i = OneWire_readByte();
           
        sprintf(buf2,"%d",i);
        LCD_setCursor(2,1);
        LCD_writeString(buf2);
           
        delay_ms(3000);
        LCD_clr();
           
           OneWire_reset();
}

void main()
{   
    char temp_lsb,temp_msb,temp;
   
    char buf3[10];
   
    char getBit[10];

    int k;
     
    OSCCON = 0b11110010;    // Set PIC18F4550 internal oscillator at 8MHz
   
    ADCON1 = 0x0F;            // Set all pins as digital I/O
        CMCON = 0x07;             // Set all comparators as digital I/O
   
    LATD = 0;                // Clear port D
    TRISD = 0b00000000;        // Set all port D pins as digital outputs
   
    LATB = 0;
    TRISB = 0x00;
   
        LCD_init();                // Initialize LCD
        OneWire_init();
               
    while(1)
    {
               
           if (!OneWire_reset())
           {
               LCD_setCursor(1,1);
            LCD_writeString("Temperature:");
           
            OneWire_writeByte(Skip_ROM);         
            OneWire_writeByte(Convert_temperature);
       
            OneWire_reset();
            delay_ms(750);
           
            OneWire_writeByte(Skip_ROM);
            OneWire_writeByte(Read_scratchpad);
           
            for (k=0;k<9;k++)
                {
                    getBit[k] = OneWire_readByte();   
                }
               
            temp_msb = getBit[1];
            temp_lsb = getBit[0];
                           
            temp = (temp_msb << 8) + temp_lsb;
           
            temp = temp >> 4;
           
            sprintf(buf3,"%d",temp);
            LCD_setCursor(2,1);
            LCD_writeString(buf3);
           
            delay_ms(1000);
               }
       }
}
 
Top