Arduino and 1-wire

I have the grounds connected, the DQ pin on the DS18S20P connected to the pin of the Arduino, and a 4.7kohm resistor from DQ to +5v as the pullup. It is good to connect the Vdd pin of the DS18S20P to ground also so if you get a non-parasite version (DS18S20) it will also work in parasite mode.

If you are going to use more than a few of these on the same pin you will need to use a pullup transistor and another pin, as shown in the DS18S20 datasheet, but for a few, say less than 10? of them the Arduino has enough current capacity.

The solution is to not let the external pull-up bring the pin high after the low period of the final bit of the 0x44 is written, force it high with the output driver. Then after the 750ms conversion period passes flip the pin back to an input and let the external pull-up take over.

Do you use the same pin for this? In yerg2k's code I bring the pin high immediately after the ds_writebyte(0x44) function. But it still doesn't work. I was wondering if it maybe takes too much time to finish the ds_writebyte() function and that you are doing someting different with an additional pin.

You almost certainly have a DS18S20P on your hands.

Hmm, overlooked this one but indeed I have the DS18S20P. So far I still couldn't find what I am doing wrong. I am using the 750 uS delay after the 44h write, then pulling the pin high. Why don't I see what's going wrong?

This http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=41771&highlight=ds18s20 thread explains something about connecting the DS18S20. To it seems it is about the powered sensor. Unfortunately, because I have the DS18S20P I can't connect to it like "kartman" explains.

:slight_smile: YES YES
Finally, it works. I'll do a quick clean up of the code and post it. Though I rewrote almost everything it was a hardware >:( problem after all. I don't really understand it, maybe someone can explain it to me. There are some other issues that I found out by trial and error. So, I am not there yet, but there is a start to get 1-wire working.

This program is specifically for the DS18S20P. But it is probably easier to get a non P(arasite) version working. To avoid misunderstandings let's start with the DS18S20P connections.

GND and Vdd to GND, Dq to pin 6 AND to pin 7 AND via a 4k7 resistor to +5V on arduino board.

Thanks to yerg2k to get me started and jims to get me thinking.
Comments are welcome.

/* DS18S20P Temperature chip i/o 
 * ---------------
 *
 * See http://pdfserv.maxim-ic.com/en/ds/DS1820-DS1820S.pdf for the datasheet.
 *
 * (copyleft) 2006 by Derek Yerger - Free to distribute freely.
 * (sorry Derek, great inspiration but I rewrote it completely)
 *  heavily modified by bigengineer
 * inspired by: http://microsyl.com/
 * and Dallas 1-wire datasheets
 *
 */
#define DQ 7  //data pin 
#define PU 6  //separate pin for pull up
#define pin13 13
#define VERSION 01

void setup(void) 
{
  // initialize inputs/outputs
  // start serial port
  pinMode(DQ,INPUT);
  pinMode(PU,INPUT);
  pinHigh();
  Serial.begin(9600);
}
byte reset()
{
  pinLow();
  delayMicroseconds(500);
  pinIn();
  delayMicroseconds(70);
  if (digitalRead(DQ) == LOW)
  {
    delayMicroseconds(500);
    return(1); 
  }
  return(0);
}
void WriteByte(byte data)
{
  byte i;
  for(i=0;i<=7;i++)
  {
    pinLow();
    if (data & 0x01) //write 1
    {
      delayMicroseconds(7);
      pinIn();
      delayMicroseconds(70);      
    }
    else //write 0
    {
      delayMicroseconds(70);
      pinIn();
      delayMicroseconds(7);
    }
    data>>=1;
  }
}
void convertTemp()
{
  byte i;
  byte data = 0x44;
 
  for(i=0;i<=7;i++)
  {
    pinLow();
    if (data & 0x01) //write 1
    {
      delayMicroseconds(7);
      pinIn();
      delayMicroseconds(70);      
    }
    else //write 0
    {
      delayMicroseconds(70);
      pinIn();
      delayMicroseconds(7);
    }
    data>>=1;
  }
  pullupHigh(); //pull pin 6 high for the conversion
  delay(750); //conversion time is 750 milliseconds
  pullupIn(); //switch off pin 6
  pinIn();
}
byte readByte()
{
  /* timing is critical here. But timing values are different
   * from the datasheets. These values are found by trial & error.
   * The delay's should be somewhere around 15 uS.
   */
  byte data=0;
  byte i;
  byte bit;
  for(i=0;i<8;i++)
  {
    pinLow();
    delayMicroseconds(1); // > 2 doesn't work
    pinIn();
    delayMicroseconds(1); // >5 doesn't work
    bit = digitalRead(DQ) & 0x01;
    data >>= 1;
    if (bit) data |= 0x80;
    delayMicroseconds(50); //doesn't seem to be necessary
  }
  return(data);
}

void pinHigh()
{
  pinMode(DQ,OUTPUT);
  digitalWrite(DQ,HIGH);
}
void pinLow()
{
  pinMode(DQ,OUTPUT);
  digitalWrite(DQ,LOW);
}
void pinIn()
{
  pinMode(DQ,INPUT);
  //pullupIn(); //om de resistor pull-up te laten werken
}

void pullupHigh()
{
  pinMode(PU,OUTPUT);
  digitalWrite(PU,HIGH);
  digitalWrite(pin13, HIGH);
}
void pullupLow()
{
  pinMode(PU,OUTPUT);
  digitalWrite(PU,LOW);
  digitalWrite(pin13, LOW);
}
void pullupIn()
{
  pinMode(PU,INPUT); //necessary for resistor pull-up
  digitalWrite(pin13, LOW);
}

void readRom()
{
  byte j;
  byte pad[9];

  reset();
  WriteByte(0x33);
  for(j=0;j<8;j++)
  {
    pad[j] = readByte();
  }
  for(j=0;j<8;j++)
  {
    Serial.print(pad[j], HEX);
    Serial.print(" ");
  }
  Serial.println("read rom");
}
void readScratchpad()
{
  byte j;
  byte pad[9];
  int msb,lsb;

  WriteByte(0xBE);
  for(j=0;j<9;j++)
  {
    pad[j] = readByte();
  }
  for(j=0;j<9;j++)
  {
    Serial.print(pad[j], HEX);
    Serial.print(" ");
  }
  Serial.print("read scratchpad  ");
  msb = pad[1];
  lsb = pad[0];
  if (msb <= 0x80)lsb = lsb/2;
  msb = msb & 0x80;
  if (msb >=0x80) lsb = (~lsb)+1;
  if (msb >=0x80) lsb = lsb/2;
  if (msb >=0x80) lsb = ((-1)*lsb);
  Serial.print("T =  ");
  Serial.print(lsb);
  Serial.print(" ");
    
}
void loop(void) 
{
  readRom();
  reset();
  WriteByte(0xCC);
  convertTemp();
  reset();
  WriteByte(0xCC);
  readScratchpad();
  Serial.print("version: ");
  Serial.println(VERSION);
   delay(1000);                 // Lets not flood.
}

[edit]changed typo that cosinekitty discovered[/edit]

This line of code scares my kitty cat :wink:

  if (digitalRead(DQ == LOW))

This compares DQ to LOW (7 == 0), which evaluates to false, or 0, then does a digitalRead of pin 0 and asks whether it returned HIGH or not.

I think you meant:

  if (digitalRead(DQ) == LOW)

But hey, maybe it works anyway... ????

I've finished. I packaged the 1-wire functions into a library for Arduino. It includes the read and write byte functions, reset, device enumeration, and CRC computation. The comments about how one might use it are in the library source. Sadly, it won't fit in a post anymore.

You can pick up the files at http://core.federated.com/~jim/onewire/

Create an arduino-0007/lib/targets/libraries/OneWire/ directory and put them in there. You will probably need to quit the arduino program and restart to get it to notice. The test.c program doesn't go in the library, it was a little test program you might find useful.

The test is working fine on my unit with 4 DS18S20s connected.

Physically, I have all the DQ lines connected to my IO pin, all the grounds connected to a ground, and 4.7k ohm resistor from a Vcc to the DQ lines. It would be best to connect all the remaining pins of the DS18S20s to either Vcc or GND, then a regular DS18S20 (not a -P) would still work in either normal or parasite mode depending how you connected it.

If you are going to have any kind of wire run I would suggest looking at some of the ESD protection variations (resistor in series with IO pin and 5.5v Zener diode to ground) to keep the stress down when bad things happen. Likewise, I think it would be possible to make this work using the internal pull-up of the Arduino, but decided that would be a needless stress with there is a short, and the resistor is a bit too big so it would be bad on longer cable runs and possibly not able to supply parasite power.

Physically, I have all the DQ lines connected to my IO pin, all the grounds connected to a ground, and 4.7k ohm resistor from a Vcc to the DQ lines. It would be best to connect all the remaining pins of the DS18S20s to either Vcc or GND, then a regular DS18S20 (not a -P) would still work in either normal or parasite mode depending how you connected it.

Strange, my code started working when I used another pin to supply current to Dq during the temperature conversion.

I am very glad that you have the device enumeration already working, that saves me a lot of time!

I will try it and report back.

Well jims, your code is working! I don't understand why I needed an extra pin to get my code working but your code works with just pin 7 and GND connected.

At the moment I have 3 sensors connected and all 3 give a temperature reading. Your library should become a standard library.

Big thanks to bigengineer and JimS! I'd never have expected it to be that delay right before conversion. Things have been busy here, so I won't get to try this out, but way to go on cracking this one guys!

Wow, jims, very cool!

What would be even cooler is if you or someone else with a working one-wire device packaged the code up as a C++ library (like Wire or SoftwareSerial), with a keywords.txt file and examples. There's some (very sparse) documentation at http://www.arduino.cc/en/Main/Libraries) along with an example library that should be easy to adapt. Any takers?

I have a (simple) working example, that could be added. What is still missing from the library is readout in degrees celsius, I have that too. Also missing is more precise readout. The Application note in which it is explained seems to have disappeared. Except for the keywords.txt I think the library is pretty much done.

It is all jims work, so I guess he will want to pack it up too. Otherwise I will give it a shot. But I need someone to have look at it afterwards.

Oh OK. After I got done putting in all the rubbish to make the C++ and C symbols work together I did feel it would be better as a class. I'm away from that hardware until Tuesday, I'll redo it as C++ then.

Awesome.

Having things like:

OneWire(pin);
OneWire.read();
OneWire.write(value, power)

Would make the code that much easier to use and more consistent with the other libraries.

All packaged in C++ form. Well, not the keywords.txt file. I'm not sure what that is, though I guess it has something to do with the color coding of the build in editor.

http://www.federated.com/~jim/onewire/ contains the library and a sample program. Feel free to vacuum it up into anything you like.

This library is general 1-wire. It might be nice to derive a DS18S20 class from this that knows about temperature to handle the conversions, or that might start making too much object code. Maybe I'm being too sensitive to code bloat, but it seems that higher level libraries will end up containing a lot of unused functions for any given application. e.g. I won't use the alarm threshold registers in my application but I'd end up with functions for them linked into my code. I had enough worry about that in just the generic functions that I ended up with a couple nasty preprocessor symbols to omit some of the larger functions that people might not need.

Very nice. I may try to write up a bit of documentation for it in the playground, unless someone else decides to do it first.

I will make the keywords.txt then. That seems to be the easiest part. :slight_smile:

I made a rough outline at Arduino Playground - OneWire

When I get some time later today, I'll go through and edit it up.

So, the easiest jobis done too, although I am not sure if I got it right. I thought I read something about the keywords.txt file, but I can't find it anymore.

#######################################
# Syntax Coloring Map For OneWire
#######################################

#######################################
# Datatypes (KEYWORD1)
#######################################

OneWire    KEYWORD1

#######################################
# Methods and Functions (KEYWORD2)
#######################################

reset      KEYWORD2
write_bit      KEYWORD2
read_bit      KEYWORD2
write      KEYWORD2
read      KEYWORD2
select      KEYWORD2
depower      KEYWORD2
reset_search      KEYWORD2
search      KEYWORD2
crc8      KEYWORD2
crc16      KEYWORD2

#######################################
# Instances (KEYWORD2)
#######################################


#######################################
# Constants (LITERAL1)
#######################################

[edit]changed the keywords.txt[/edit]

You can check out the keywords.txt of the existing libraries (in lib/targets/libraries). It looks good, except that OneWire should be in the datatypes section and a KEYWORD1. Now we just need to zip it all and upload it somewhere (the playground?).