1-Wire

the thermometer

So, we are going to write a piece of code that implements the 1-wire protocol.

Start by gathering info, the first thing to look at is the DS18B20 datasheet, get a feeling of what is about. No need to understand everything in the datasheet. On Maxim's site there are tones of application notes, I would suggest application notes 162,187,126,120, with this sequence, probably first AVR318 application note which is easy to follow. Come on, show an aggressive attitude, although you don't understand everything, I don't either. Do not copy/paste pieces of code hoping it's going to work, it will not. From the ground we go up. Try to simplify thinks by asking yourself simple questions.

You see that many thermos can be connected together on a bus, a micro talks to them, so they have to be addressed with a unique ID (think ethernet & IP analogy). There is a single wire, so only one speaks at a time. Who coordinates discussion? The master, the micro (forget ethernet analogy). Well, if it does how the hell it knows which thermo is on the bus? There is an algorithm for doing that, the search algorithm. Do I care? No, not for this project, we have a single thermo on the bus. Is there a way to identify communication errors or malfunctioning thermos? The CRC does that.

If you were a microcontroller, and wanted to talk over your half-duplex conference phone to your fellow thermometers, what interogation commands you would like to have? There are a few simple concepts, that reasonably fit into the puzzle. Don't bypass them.

Hmm, where to start? The first think to try after getting the idea is sending 1s and 0s. Reading 1s and 0s would help too. It comes down to holding the pin for output and releasing it for input. When set for output, the pin can be written, when set for input the pin can be read ... Have a look at the following defs and see if they make any sense.


// set pin mask   
#define wmask     0x08               
// set 1-wire pin for output
#define wOut      DDRA |= wmask
// set 1-wire pin for input (bus released)     
#define wIn       DDRA &= ~wmask
// set 1-wire bus high     
#define wH        PORTA |= wmask
// set 1-wire bus low     
#define wL        PORTA &= ~wmask
// get 1-wire bus input (bus released)   
#define wR        PINA & wmask       
 

Now, this is just pin toggling, from that we need to get to the basic bus signals. Let's go one level up. Hmm, wait a minute, it looks like we need a delay first. OK. Think of ...


// delay = 5.70 + (1.22 * count)us
void uDelay(u8 count)
{
    while(count--);                 
}
 

This is a delay but how long does it last? You need to simulate your code with AVRStudio, please do so. Go to Debug => AVR Simulator Options => Frequency=7.3728 MHz. After compiling, Debug => Start Debugging, press F11 a couple of times and look at the stopwatch. You may reset your stopwatch by right clicking on it. I hope you get the same result as I did: delay = 5.70 + 1.22 * count microseconds for a 7.3728MHz clock. One time slot is 60us and looking at the AVR318 app. note we can realize how to output 1s and 0s....


void wTxbit (u8 bit)
{
   wOut;wL;
   if (bit)
   {
      uDelay (4);      // 10.58us
      wIn;
      uDelay (46);     // 61.82us
   }
   else
   {
      uDelay (46);     // 61.82us
      wIn;             // better releash the bus
      uDelay (4);      // 10.58us
   }
}
 

Delay constrains have to be met but, the protocol timing is not very strict. Onto the read routine ...


u8 wRxbit (void)
{
   u8 data;

   wOut;wL;
   uDelay (0);         // 10.58us
   wIn;
   uDelay (0);         // 10.58us
   data=wR;
   uDelay (23);        // 61.82us

   return data;
}
 

Your time has come, after clearly understanding the above, you have to implement the Reset/Presence signal. Lucky you!

Links
http://www.maxim-ic.com/appnotes10.cfm/ac_pk/1 http://www.atmel.com/dyn/products/app_notes.asp?family_id=60
 
 
Visit my other site!