Experiment #16. One wire and DS18b20.

Goal: To get temperature data from DS18b20 sensor

What we have: PIC16f628a, DS18b20, MAX232 level converter, devboard, proteus.

There is example of working with one DS18b20 at line, and you can find some useful functions for work with 1-wire protocol.

So, we have quite simple goal – to get temperature value, first of all we have to read a datasheet very carefully. The first thing is power, I did it by usual way:


The data line should be pulled up to VDD via resisor (4.7 KOhm recommended in the datasheet). Next – memory organization:

There are only 9 bytes of memory:

  1. LSB temperature byte
  2. MSB temperature byte
  3. High bond trigger
  4. Low bond trigger
  5. Configuration register
  6. Not for us (:
  7. Not for us
  8. Again not for us
  9. CRC

Most interesting for us – 0,1 and 4-th (of course, CRC is the good thing too, but here I didn’t use it)

4-th byte – configuration register:

Here rewritable bites is 5-th and 6-th which sets measure accuracy. Default value is 12 bits resolution, which is equal to 0.0625 degrees accuracy. We can use also:

  • 9 bit – 0.5 degrees
  • 10 bit – 0.25 degrees
  • 11 bit – 0.125 degrees

R1 and R0 values for configuration:

You should admit conversion time also because you have to wait this time until the next byte can be written.

Let’s look at temperature registers:

There is 4 low bits at LS byte which are for fractional part, integer is placed in 4 high bits of LS byte and 3 low bits of MS byte. Bits with S sign is for temperature sign (S = 1 – negative temperature).

Let’s move to basic procedures of work with 1-wire, any commands sequence starts with initialization:

For first, uC should pull up line to ground for 480 us, then line’ll releasing and uC waits until sensor pulls line to ground again. If this happened then all is ok, if not – then something is going wrong. I’m going to write my own function for initialization and remember that we work only with tris registers, not with direct ports.

For start I’d made:

#define STATE TRISB4
#define PIN RB4


static bit INIT(void){
static bit b;
STATE = 1;
STATE = 0;         //line to ground
__delay_us(500);   //wait 500 us
STATE = 1;         //direction to input
__delay_us(65);    //wait 65 us
b = PIN;           //look at our line
__delay_us(450);   //wait another 450 us
return b;          //return 0 or 1

This function returns 0 if there is sensor at line and 1 if not.

The next thing we have to do is function for writing to sensor:

If we want to write 0, we should pull up line to ground for 60 us, for transition of “1” – at least as 1 us, and then line should be released. Don’t forget that low bit is going first.

void TX(unsigned char cmd){

unsigned char temp = 0;
unsigned char i = 0;
temp = cmd;
for (i=0;i<8;i++) {
                  if (temp&0x01) {
                                 STATE = 0;              //"1" transition
                                 STATE = 1;
                                 } else {                //"0" transition
                                        STATE = 0;
                                        STATE = 1;
                                 temp >>= 1;

Now, about reading:

We have to pull up line to ground at least for 1s for successful reading and then change direction to input. Time for reading is only 15 us.

unsigned char RX() {

unsigned char d = 0;
unsigned char i = 0;
for (i=0;i<8;i++){
                 STATE = 0;                 //pull up to ground
                 STATE = 1;
                 d>>=1;                     //shift every bit
                 if (PIN == 1) d |= 0x80;   //if there is 1 we write 1
                 __delay_us(70);            //wait needed time
return d;

These three functions creates enough basis for work with 1-wire protocol.

Let me show simple example for case where only single sensor at line.

Our sequence'll look something like:

  1. Initialization
  2. 0xCC - skip the identification
  3. 0х44 - start the conversation procedure
  4. wait the needed time(750 ms for 12 bits accuracy)
  5. repeat initialization
  6. 0xCC - skip the identefication
  7. 0хBE - read all registers

I've made single function for this sequence:

void get_temp() {
static bit init;

unsigned char temp1;
unsigned char temp2;
init = INIT();
             if (!init) {                 //is initialization successful?
                        __delay_ms(150);  //wait 750 ms
                        __delay_ms(150); }
              init = INIT();              //repeat initialization
              if (!init) {
                         TX(0xBE);        //reading start
                         temp1 = RX();    //read LSB
                         temp2 = RX();    //read MSB

temp_drob = temp1 & 0b00001111;           //fractional part to variable
temp_drob = ((temp_drob*6)+2)/10;         //convertation
temp1 >>= 4;
sign = temp2 & 0x80;                      //Which sign?
temp2 <<= 4;
temp2 &= 0b01110000;
temp2 |= temp1;                           //combine all parts

if (sign) {                               //if negative
            temperature = 127-temp2;      //to global variable for integer part
            temp_drob = 10 - temp_drob;   //to global variable for fractional part
           }   else temperature = temp2;

To check workability I've made prototype version at devboard and display information through uart.

void main() {
unsigned char input = 0;

printf("\ftemperatura -- ");
if (sign) printf("-"); else printf("+");
printf("%d", temperature);
printf(".%d", temp_drob);

        input = getch();
        if (input == 50) {
                         printf("\r\ntemperatura -- ");
                         if (sign) printf("-"); else printf("+");
                         printf("%d", temperature);
                         printf(".%d", temp_drob);

This is what I'd got:

Sources here.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.