Go Down

Topic: Interface with DS18s20 (Read 580 times) previous topic - next topic

ripleynewc

I have been trying for awhile to interface with a DS18s20. Was unsucessful with a Pic so I bought an uno. I found the onewire library and used the example and it worked fine. I wanted to try to program it myself to get experience with interfacing. I used the main code and rewrote the write, read and reset subroutines and set the code up for one sensor. To my amazement it also worked except when you hold the DS18s20 with your finger to see if the temperature display increases. It does but seems to saturate after a few degrees increase and the dispalay jumps to 127. If you take your finger off the DS18s20 it comes back down after a few minutes. It does not do this with the onewire library routine so it must be something I left off. Thought it might be timing but I checked the timing and it looks ok. Any ideas on what would cause this behavior?
Code: [Select]


#include <OneWire.h>
#include <LiquidCrystal.h>
// LCD=======================================================
//initialize the library with the numbers of the interface pins
// works but goes to 127 if you hold ds18s20 with finger
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
#define LCD_WIDTH 16
#define LCD_HEIGHT 2

void setup(void)
{
  lcd.begin(LCD_WIDTH, LCD_HEIGHT,1);
  lcd.setCursor(0,0);
  lcd.print("DS1820 Test");
  Serial.begin(9600);
}
int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract,i,y;
char buf[20];

void loop(void)
{
  byte data[12];

  reset();
  write(0xCC);
  write(0x44);         // start conversion, with parasite power on at the end


  digitalWrite(9,HIGH);
  delay(1000);     // maybe 750ms is enough, maybe not
  // we might do a ds.depower() here, but the reset will take care of it.

  reset();
  write(0xCC);
  write(0xBE);         // Read Scratchpad


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

  LowByte = data[0];
  HighByte = data[1];
  TReading = (HighByte << 8) + LowByte;
  SignBit = TReading & 0x8000;  // test most sig bit
  if (SignBit) // negative
  {
    TReading = (TReading ^ 0xffff) + 1; // 2's comp
  }
  Tc_100 = (TReading*100/2);   

  Whole = Tc_100 / 100;  // separate off the whole and fractional portions
  Fract = Tc_100 % 100;

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print(Whole);
  lcd.print(".");
  lcd.print(Fract);

}

void reset(void)
{
  digitalWrite(9,LOW);
  pinMode(9,OUTPUT);
  delayMicroseconds(500);
  pinMode(9,INPUT);
  delayMicroseconds(420);
}



int write(int v)
{
  for (i = 0; i <8; i++) {
    y = bitRead(v, i);
    if (y==1)
    {
      digitalWrite(9,LOW);
      pinMode(9,OUTPUT);
      delayMicroseconds(10);
      digitalWrite(9,HIGH);
      delayMicroseconds(55);
      pinMode(9,INPUT);
      digitalWrite(9,LOW);
    }
    else
    {
      digitalWrite(9,LOW);
      pinMode(9,OUTPUT);
      delayMicroseconds(65);
      digitalWrite(9,HIGH);
      delayMicroseconds(5);
      pinMode(9,INPUT);
      digitalWrite(9,LOW);
    }
  }
}

int read()
{
  int val=0,i,val1=0;
  for (i=0; i<8; i++){
    pinMode(9,OUTPUT);
    digitalWrite(9,LOW);
    pinMode(9,INPUT);
    val = digitalRead(9);
    delayMicroseconds(53);
    if (val == 1)
      bitSet(val1,i);
  }

  return val1;

}

pylon

In the read function you changed the timing quite notably. The 3 us delay after writing a low is almost compensated with your slow call of digitalWrite but the 10 us delay after switching the pin to input mode is probably relevant. You have to give the chip time to put it's data to the wire before you read it. Have you checked your version of the protocol against the OneWire library with a scope?

ripleynewc

Thanks for the reply. I am new to the arduino and also with trying interface with timing requirements. I do have a logic analyzer and saw that the timing on my version was not the same as the OneWire library version. It looks like the OneWire library version uses assemly language calls to speed things up and I found a way to do that in the playground. I can get the timing closer by using cbi and sbi instructions but probably need to work on it some more. The part I don't understand is that my version works at room temperature but runs up to maximum (display shows 127) if I raise the temperature by putting my finger on the chip. I don't understand why raising the temperature would cause the timing to change or be the cause of the problem. I am wondering if there is something else in the OneWire code that prevents the problem that I am seeing. I can't really follow some of the DIRECT_MODE commands in the OneWire version.

ripleynewc

I got a chance to look at this some more. I compared my write function to the one in the OneWire library and found that I had included two uncesessary lines; not sure why I did that.

Code: [Select]
//    pinMode(9,INPUT);
  //    digitalWrite(9,LOW);


When you remove the lines it works fine. So below is code that will interface with a single DS18s20 temperature sensor without using the OneWire library.

Code: [Select]
#include <OneWire.h>
#include <LiquidCrystal.h>
// LCD=======================================================
//initialize the library with the numbers of the interface pins

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
#define LCD_WIDTH 16
#define LCD_HEIGHT 2

void setup(void)
{
  lcd.begin(LCD_WIDTH, LCD_HEIGHT,1);
  lcd.setCursor(0,0);
  lcd.print("DS1820 Test");
  Serial.begin(9600);
}
int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract,i,y;
char buf[20];

void loop(void)
{
  byte data[12];

  reset();
  write(0xCC);
  write(0x44);         // start conversion, with parasite power on at the end


  digitalWrite(9,HIGH);
  delay(1000);     // maybe 750ms is enough, maybe not
  // we might do a ds.depower() here, but the reset will take care of it.

  reset();
  write(0xCC);
  write(0xBE);         // Read Scratchpad


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

  LowByte = data[0];
  HighByte = data[1];
  TReading = (HighByte << 8) + LowByte;
  SignBit = TReading & 0x8000;  // test most sig bit
  if (SignBit) // negative
  {
    TReading = (TReading ^ 0xffff) + 1; // 2's comp
  }
  Tc_100 = (TReading*100/2);   

  Whole = Tc_100 / 100;  // separate off the whole and fractional portions
  Fract = Tc_100 % 100;

lcd.clear();
lcd.setCursor(0,0);
lcd.print(Whole);
lcd.print(".");
lcd.print(Fract);

}

void reset(void)
{
  digitalWrite(9,LOW);
  pinMode(9,OUTPUT);
  delayMicroseconds(500);
  pinMode(9,INPUT);
  delayMicroseconds(420);
}



int write(int v)
{
  for (i = 0; i <8; i++) {
    y = bitRead(v, i);
    if (y==1)
    {
      digitalWrite(9,LOW);
      pinMode(9,OUTPUT);
      delayMicroseconds(10);
      digitalWrite(9,HIGH);
      delayMicroseconds(55);
  //    pinMode(9,INPUT);
  //    digitalWrite(9,LOW);
    }
    else
    {
      digitalWrite(9,LOW);
      pinMode(9,OUTPUT);
      delayMicroseconds(65);
      digitalWrite(9,HIGH);
      delayMicroseconds(5);
   //   pinMode(9,INPUT);
   //   digitalWrite(9,LOW);
    }
  }
}

int read()
{
  int val=0,i,val1=0;
  for (i=0; i<8; i++){
    pinMode(9,OUTPUT);
    digitalWrite(9,LOW);
    pinMode(9,INPUT);
    val = digitalRead(9);
    delayMicroseconds(53);
    if (val == 1)
      bitSet(val1,i);
  }

  return val1;

}




Go Up