# 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:

#### hyedenny

##### Active Member
Shouldn't you also set ADCON0 = 0?

#### 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.

Loading