OneWire - DS18B20 - PIC18F4550 code query

Thread Starter

GrafZeppelin

Joined May 3, 2013
11
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 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
 

JWHassler

Joined Sep 25, 2013
308
The code seems to be doing this:
- Read the lower byte of the temperature into TempL
- Read the upper byte into TempH
- Divide the LSB by 16, removing the fractional degrees
- multiply the MSB by 16, dropping of four unneeded sign bits
- Merge the two numbers, making a value in the +125 to -55 range.. you will be seeing the middle 8 bits of the values in Table 2 of the datasheet

I never liked that datasheet
 

dannyf

Joined Sep 13, 2015
2,197
If I were you, I would feed tempL and tempH known good numbers right after you read thee device so you know if the issue is with your display routines or not.

Go from there.
 

Thread Starter

GrafZeppelin

Joined May 3, 2013
11
Thanks guys for your input. I have fiddled around with the wires connecting the MCU and LCD, and now the result is stable, almost. The outcome now is:

IMG_1353.JPG

Though for a short moment on a second line it displays 0-016.. I have no idea why. The code now is:
Code:
void main()
{
    char s[16];
   
    short tempL;
    short tempH;
  
    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

    while(1)
    {
        LCD_setCursor(1,1);
        LCD_writeString("Temperature:");
      
      
         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(2,1);
            LCD_writeString(s);
        }
     }
}
@MMcLaren, how should I create an 8-bit variable instead of 16bit?
And to add to my question, how should I display true temperature from a single variable?
 
Last edited:

Thread Starter

GrafZeppelin

Joined May 3, 2013
11
OK, so I got something working. I've tried combining the maxim code with some of the codes I found on the web, and of course the glorious DS18B20 datasheet was a big help. I am now able to see presence pulse(0), family code(0x28) and the temperature(11). The problem now is that in my room the tremperature is ~27 degrees C. Anybody know why the output is like that? Please see my codes:

DS18B20 header:
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);
               }
       }
}
 

Thread Starter

GrafZeppelin

Joined May 3, 2013
11
Well it's a hot summer where I am :) And by a problem, I meant it looks like I made a mistake somewhere in the code. If I put a hot cigarette lighter (not lit, just after it was lit for 5 sec), the temperature goes from 11 to 12 and then 13, and when I remove it, value goes from 13 to 11 again. So it means the problem is not with the actual sensor, I'm just really bad at coding :) Any help? Please?
 
Top