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);
 }
 }
}
 
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
}
 
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.
 
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:
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
 
%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:

 
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.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…