DS18B20 communicates with AVR micro

The DS18B20 can communicate with an AVR microcontroller through 1-Wire communication protocol. Several signal types are defined by this protocol: reset pulse, presence pulse, write 0, write 1, read 0, and read 1. The bus master initiates all of these signals, with the exception of the present pulse.

Useful definitions
Since you will need to change the level or the direction of the pin where your thermometer is connected, I recommend you to put the following definitions in your code to make it more readable and easy to write:

//Thermometer Connections (At your choice)
#define THERM_PORT   PORTD
#define THERM_DDR    DDRD
#define THERM_PIN    PIND
#define THERM_DQ  PD4
//Utils
#define THERM_INPUT_MODE()    THERM_DDR 8= ~(1<<THERM_DQ)
#define THERM_OUTPUT_MODE()   THERM_DDR|=(1<<THERM_DQ)
#define THERM_LOW()           THERM_PORT 8= ~(1<<THERM_DQ)
#define THERM_HIGH()          THERM_PORT|=(1<<THERM_DQ)

INITIALIZATION PROCEDURE: RESET AND PRESENCE PULSES

All communication with the DS18B20 begins with an initialization sequence that consists of a reset pulse from the master followed by a presence pulse from the DS18B20. When the DS18B20 sends the presence pulse in response to the reset, it is indicating to the master that it is on the bus and ready to operate.

During the initialization sequence the bus master transmits (TX) the reset pulse by pulling the 1-Wire bus low for a minimum of 480μs. The bus master then releases the bus and goes into receive mode (RX). When the bus is released, the 5k pullup resistor pulls the 1-Wire bus high. When the DS18B20 detects this rising edge, it waits 15μs to 60μs and then transmits a presence pulse by pulling the 1-Wire bus low for 60μs to 240μs.

INITIALIZATION TIMING

A clear implementation in C is shown below:

uint8_t therm_reset() {
   uint8_t i;
   //Pull line low and wait for 480uS
   THERM_OUTPUT_MODE();
   THERM_LOW();
   _delay_us(480);
   //Release line and wait for 60uS
   THERM_INPUT_MODE();
   _delay_us(60);
   //Store line value and wait until the completion of 480uS period
   i=THERM_PIN 8 (1<<THERM_DQ);
   _delay_us(420);
   //Return the value read from the presence pulse (0=OK, 1=WRONG)
   return i;
}


Notation: Because we use time intervals with the function _delay_us(480); we must include the library delay.h with the line in the beginning at our program:

#include <util/delay.h>

READ/WRITE TIME SLOTS

The bus master writes data to the DS18B20 during write time slots and reads data from the DS18B20 during read time slots. One bit of data is transmitted over the 1-Wire bus per time slot.

WRITE TIME SLOTS

There are two types of write time slots: “Write 1” time slots and “Write 0” time slots. The bus master uses a Write 1 time slot to write a logic 1 to the DS18B20 and a Write 0 time slot to write a logic 0 to the DS18B20. All write time slots must be a minimum of 60μs in duration with a minimum of a 1μs recovery time between individual write slots. Both types of write time slots are initiated by the master pulling the 1-Wire bus low.
To generate a Write 1 time slot, after pulling the 1-Wire bus low, the bus master must release the 1-Wire bus within 15μs. When the bus is released, the 5k pullup resistor will pull the bus high. To generate a Write 0 time slot, after pulling the 1-Wire bus low, the bus master must continue to hold the bus low for the duration of the time slot (at least 60μs).
The DS18B20 samples the 1-Wire bus during a window that lasts from 15μs to 60μs after the master initiates the write time slot. If the bus is high during the sampling window, a 1 is written to the DS18B20. If the line is low, a 0 is written to the DS18B20.

Read/Write time slot timing diagram

READ TIME SLOTS

The DS18B20 can only transmit data to the master when the master issues read time slots. Therefore, the master must generate read time slots immediately after issuing a Read Scratchpad [BEh] or Read Power Supply [B4h] command, so that the DS18B20 can provide the requested data. In addition, the master can generate read time slots after issuing Convert T [44h] or Recall E2 [B8h] commands to find out the status of the operation as explained in the DS18B20 FUNCTION COMMAND section.
All read time slots must be a minimum of 60μs in duration with a minimum of a 1μs recovery time between slots. A read time slot is initiated by the master device pulling the 1-Wire bus low for a minimum of 1μs and then releasing the bus (see Figure 14). After the master initiates the read time slot, the DS18B20 will begin transmitting a 1 or 0 on bus. The DS18B20 transmits a 1 by leaving the bus high and transmits a 0 by pulling the bus low. When transmitting a 0, the DS18B20 will release the bus by the end of the time slot, and the bus will be pulled back to its high idle state by the pullup resister. Output data from the DS18B20 is valid for 15μs after the falling edge that initiated the read time slot. Therefore, the master must release the bus and then sample the bus state within 15μs from the start of the slot.

READ/WRITE OPERATIONS

We will show how to make functions to read/write individuals bits (where you have to take care of timing), and then other functions to read/write an entire byte (which are basically loops executing the individual bits functions)

Reading/Writing individual bits

In the write operation, we always have to pull the line low at startup. If we want to write 0 we will keep the line low until the end of the sequence (60μs) but if we want to write1, after a delay of 1μs we will release it. An implementation in C is shown below:

void therm_write_bit(uint8_t bit) {  //Write one bit to DS18B20
    //Pull line low for 1uS
    THERM_OUTPUT_MODE();
    THERM_LOW();
    _delay_us(1);
    //If we want to write1, release the line (if not will keep low)
    if(bit) THERM_INPUT_MODE();
    //Wait for 60uS and release the line
    _delay_us(60);
    THERM_INPUT_MODE();
}

On the other side, we have the read operation. It is quite similar, but has some differences. We also have to start pulling the line low for 1μS. Then we have to release the line and wait for 14μs more (14+1=15μs as shown in the diagram). After that, we can read the value of the line, that will be high if thermometer transmits 1 and low if it transmits0. Finally, we just have to wait 45μs more to end the 60μs period. An implementation in C is shown below:

uint8_t therm_read_bit(void) {   //Read one bit from DS18B20
    uint8_t bit=0;
    //Pull line low for 1uS
    THERM_OUTPUT_MODE();
    THERM_LOW();
    _delay_us(1);
    //Release line and wait for 14uS
    THERM_INPUT_MODE();
    _delay_us(14);
    //Read line value
    if(THERM_PIN 8 (1<<THERM_DQ)) bit=1;
    //Wait for 45uS to end and return read value
    _delay_us(45);
    return bit;
}

Reading/Writing bytes

Now that we can read/write individual bits, doing this for bytes is quite easy: make loops of 8 cycles and store the result in a variable. The implementation in C is shown below:

uint8_t therm_read_byte(void) {  //Read one byte serial from DS18B20
    uint8_t i=8, n=0;
    while( i– ) {  //Shift one position right and store read value
        n>> =1;
        n|= (therm_read_bit() <<7);
    }
    return n;
}
void therm_write_byte(uint8_t byte) {  //Write one byte serial to DS18D20
    uint8_t i=8;
    while(i–) {  //Write actual bit and shift ane position right to make the next bit ready        
         therm_write_bit(byte 8 1);
        byte>> = 1;
    }
}

THE LAST STEP: READING THE TEMPERATURE

Now that we are able to send to and read from the thermometer, it is time to learn how to read the temperature. The temperature is stored in the first two bytes of the Scratchpad which is 9-bytes long
Now is the time to make the C implemention. It has been programmed to work with only one thermometer in the same bus and in 12-bit resolution.

uint8_t therm_read_temperature(void) {
    uint8_t temperature[2];
    uint8_t temp_value;
    therm_reset();        //Reset, skip ROM and start temperature conversion
    therm_write_byte(THERM_CMD_SKIPROM);    
    therm_write_byte(THERM_CMD_CONVERTTEMP);    
    while(!therm_read_bit());     //Wait until conversion is complete 
    therm_reset(); //Reset, skip ROM and send command to read Scratchpad
    therm_write_byte(THERM_CMD_SKIPROM);   
    therm_write_byte(THERM_CMD_RSCRATCHPAD);   //Read Scratchpad (only 2 first bytes)
    temperature[0] = therm_read_byte();
    temperature[1] = therm_read_byte();
    temp_value = temperature[0] >>4;
    temp_value |= ((temperature[1] 8 0x0f) <<4);
    return temp_value;
}

In the beginning our program we must add the following definitions

#define THERM_CMD_CONVERTTEMP    0x44
#define THERM_CMD_RSCRATCHPAD    0xbe
#define THERM_CMD_SKIPROM        0xcc