I'm using the Dallas/Maxim DS18B20 to measure temperature. Every few minutes it gives a bad reading. I sample temperature several times a second. The device is powered on the Vdd pin rather than using parasitic power. After giving a start conversion command, I check for an end of conversion by issuing a read slot and waiting for a high. I have tried to implement the timing requirements specified in the data sheet (480us min write slots and 60us min read slots).
Has anyone else had a similar problem? The only thing I can think of are that there may be spikes on the 5v from the USB cable, so I'll add a capacitor for filtering. Possibly the timing is borderline and delays could be increased. Implementing CRC checking would probably sort out all these problems.
This is the code which is quite long. Maybe some experts would spot something!
boolean DS18B20Initialize(int pin)
{
unsigned long start_time;
boolean low_detected=false;
int state;
char string[17];
digitalWrite(pin,HIGH); // make sure pin is high before enabling output
pinMode(pin,OUTPUT);
digitalWrite(pin,LOW);
delayMicroseconds(480);
pinMode(pin,INPUT);
start_time = micros();
while(!digitalRead); // wait for line to be pulled high
while((micros()-start_time)<480L)
{
if(!digitalRead(pin))
low_detected=true; // a device responded
}
//delayMicroseconds(5); // delay before next command
if (low_detected)
return(true);
else
return(false);
}
void DS18B20Write(int pin,byte data)
{
byte n;
for(n=0; n<8; n++)
{
if ((data & 0x01) == 1) // test least significant bit
{
digitalWrite(pin, LOW);
pinMode(pin, OUTPUT);
delayMicroseconds(5); // > a low of >1us needed for a "high" . delayMicroseconds accurate for delay > 3us so use 5us
pinMode(pin, INPUT);
delayMicroseconds(60); // sensor reads during a 60us max window
}
else
{
digitalWrite(pin, LOW);
pinMode(pin, OUTPUT);
delayMicroseconds(60); // minimum of 60us required for a low
pinMode(pin, INPUT); // release bus and let the resistor pull the input high
delayMicroseconds(5); // 1us required between write slots
}
data=data>>1; // now the next bit is in the least significant bit position.
}
}
byte DS18B20Read(int pin)
{
int n;
int state;
byte data=0;
for (n=0; n<8; n++)
{
digitalWrite(pin,LOW);
pinMode(pin,OUTPUT);
delayMicroseconds(5); // a low of >1us needed at beginning of read slot delayMicroseconds accurate for delay > 3us so use 5us
pinMode(pin,INPUT); // release bus and let the resistor pull the input high
delayMicroseconds(5); // wait another 5us and then read state of line within the 15us deadline required
state=digitalRead(pin);
delayMicroseconds(60); // complete the 60us read slot + add 5 us at the end
data = (data >> 1) | (state<<7);
}
return(data);
}
boolean DS18B20ReadROMCode(int pin, byte *array)
{
int i;
if(!DS18B20Initialize(tempsensor_pin))
return(false);
DS18B20Write(tempsensor_pin,0x33); // Read the sensor's ROM code
for(i=0;i<8;i++)
{
*array = DS18B20Read(tempsensor_pin);
array++;
}
}
void DS18B20WMatchROMCode(int pin, byte array[])
{
int i;
DS18B20Write(tempsensor_pin,0x55); // Match the sensor's ROM code
for(i=0;i<8;i++)
{
DS18B20Write(tempsensor_pin,array[i]);
}
}
float ReadTemperature(int pin)
{
int LoByte,HiByte,TReading,SignBit, Tc_100, Whole, Fract;
int state;
float temperature;
static int errors=0;
// Initialize temperature sensor
if(DS18B20Initialize(tempsensor_pin))
{
//DS18B20Write(tempsensor_pin,0xCC); // skip rom
DS18B20WMatchROMCode(tempsensor_pin,TempSensorROMCode);
DS18B20Write(tempsensor_pin,0x44); // start conversion
}
else
{
Message("Cant Init Sensor");
return(1111);
}
// check to see if conversion is complete by issuing read slots and waiting for a "1"
do
{
digitalWrite(pin,LOW);
pinMode(pin,OUTPUT);
delayMicroseconds(5); // a low of >1us needed at beginning of read slot delay. delayMicroseconds accurate for delay > 3us so use 5us
pinMode(pin,INPUT); // release bus and let the resistor pull the input high
delayMicroseconds(5); // wait another 5us and then read state of line within the 15us deadline required
state=digitalRead(pin);
delayMicroseconds(60); // complete the 60us read slot + add 5 us at the end
} while (state==LOW);
if(DS18B20Initialize(tempsensor_pin))
{
//DS18B20Write(tempsensor_pin,0xCC); // skip rom
DS18B20WMatchROMCode(tempsensor_pin,TempSensorROMCode);
DS18B20Write(tempsensor_pin,0xBE); // read scratchpad
LoByte=DS18B20Read(tempsensor_pin);
HiByte=DS18B20Read(tempsensor_pin);
}
else
{
Message("Cant Init Sensor");
return(1111);
}
TReading = (HiByte << 8) + LoByte;
SignBit = TReading & 0x8000; // test most significant bit
if (SignBit) // negative
{
TReading = (TReading ^ 0xffff) + 1; // 2's comp
}
// Work out the whole and decimal parts
Whole = TReading >> 4;
if(Whole > 30 || Whole < 0)
{
digitalWrite(onboard_led,HIGH);
errors++;
printNumber(errors);
}
//Fract = (TReading & 0x000F) * 6 + (TReading & 0x000F) / 4; // Convert two decimal places to an integer
temperature = TReading * 0.0625;
if(SignBit)
temperature = temperature * (-1);
return(temperature);
}