• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

DS18B20 > OneWire > PIC18F4550 > code query

Status
Not open for further replies.

GraffZeppelin

New Member
Hello all,

In the last three days I was struggling to read temperature data from a single DS18B20 when using non-parasitic OneWire protocol and a PIC18F4550. 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 config.h
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);
 }
 }
}
 

Dr_Doggy

Well-Known Member
you maybe in luck, i just finished working with the DS18S20 , maybe the code is similar since the part number is too,,
the part that had me snagged is that DS18S20 output pin needs a 5k pull-up resistor.
but my code is for arduino, im glad it worked for me with just cut and paste....maybe it will still help you, there is a conversion code at the bottom:

Code:
#include <OneWire.h>
OneWire ds(4);  //DS18S20 Signal pin on digital pin 4

float getTemp(){
   //returns the temperature from one DS18S20 in DEG Celsius
   byte data[12];
   byte addr[8];
   if (!ds.search(addr)) {
     //no more sensors on chain, reset search
     ds.reset_search();
     return -1000;
   }
   if (OneWire::crc8(addr, 7) != addr[7]) {
     Serial.println("CRC is not valid!");
     return -1000;
   }
   if (addr[0] != 0x10 && addr[0] != 0x28) {
     Serial.print("Device is not recognized");
     return -1000;
   }
   ds.reset();
   ds.select(addr);
   ds.write(0x44, 1); // start conversion, with parasite power on at the end

   byte present = ds.reset();
   ds.select(addr);
   ds.write(0xBE); // Read Scratchpad


   for (int i = 0; i < 9; i++) { // we need 9 bytes
     data[i] = ds.read();
   }

   ds.reset_search();

   byte MSB = data[1];
   byte LSB = data[0];

   float tempRead = ((MSB << 8) | LSB); //using two's compliment
   float TemperatureSum = tempRead / 16;

   return TemperatureSum;

}

void loop() 
{
   float temperature = getTemp();
   Serial.println(temperature);
   delay(100); //just here to slow down the output so it is easier to read
}
 

House0Fwax

Member
I can't help with your code (as I can only speak assembly), though having played with said DS18B20's I have some code, and the order I have been using is;

0xCC ;Skip ROM
0x44 ;CONVERT
-Delay-
-Reset-
0xCC ;Skip ROM
0xBE ;READ SCRATCHPAD

Hope that helps. :)
 

GraffZeppelin

New Member
Thanks guys for your input, I feel that I have pushed further. Now the code looks like:

Code:
    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];
                          
          tempRead = ((temp_msb << 8) | temp_lsb);
        
          TrueTemp = tempRead/16;
        
            sprintf(buf3,"%2.2f",TrueTemp);
            LCD_setCursor(2,4);
            LCD_writeString(buf3);
          
            delay_ms(1000);
              }
      }
}
The result I get now is 40.75 .. which is somewhat closer than the previous one, but definitely not true. I know that DS18S20 has a bit different temperature register, and I am now trying to understand how to tweak the 18S20 code to work on the 18B20. Any insights will be greatly appreciated!

EDIT: I can see approx. correct temperature only when I shift the MSB << 7, but I have no idea why this is like it is..
 
Last edited:

Dr_Doggy

Well-Known Member
27 celcius is quite warm,
also i dont understand this line: sprintf(buf3,"%2.2f",TrueTemp);

what is %2.2f , could it be that your multiplying there??
41/2.2 = 18 celcius,,, but that is a bit cool (to me anyway)

..... just guessing
 

GraffZeppelin

New Member
%2.2 is just a placeholder for a float, and by writing it I just tell the compiler I want to see a float with two digits before a comma and two digits after the comma. It is a warm summer where I am, it's 21:38 in the evening and outside it is 20C. In my room, there is an old-fashioned thermometer, which is currently displaying ~24 degrees, and it is very close to what I see on the LCD. See my pictures:

IMG_1354.JPG IMG_1134.JPG
 

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
I used the ds18s20 a couple of times... The digitally read value needed to be multiplied by 5... So very bit was 0.5 of a degree.... On the ds18b20 the value has to be divided by 16... if the digital reading is 78 ( for instance ) the temperature is 4.87 degrees.. The 4 lower bits are precision....
 
Status
Not open for further replies.

Latest threads

EE World Online Articles

Loading
Top