Saturday, April 4, 2009

DS18B20 1-wire Driver for CCS C

I got my hands on a few of these DS18B20 1-wire digital temperature sensors. They’re really awesome. They’re small, easy to work with, and they run on the 1-wire bus which means they can run on a minimum of two wires. However, I found it easier to just run these devices with 3 lines: +5V, GND, Bus – saves a lot of design complexity.

I found a few good 1-wire drivers for CCS C (especially for these devices):

DS18S20 & DS18B20 Codes

One DS18B20 in powered mode

dallas onewire primitives library and ds1822 driver code

I then took ideas from them and made my own little driver. Some of the code is copied, some of it isn’t. Here it is:

main.c

#include "main.h"
#include "1wire.c"
#include "ds1820.c"

float value = 0.0;

void main() {
    setup_adc_ports(NO_ANALOGS|VSS_VDD);
    setup_adc(ADC_OFF);
    setup_spi(SPI_SS_DISABLED);
    setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
    setup_timer_1(T1_DISABLED);
    setup_timer_2(T2_DISABLED,0,1);    
    setup_oscillator(OSC_8MHZ);
    setup_uart(9600);
    
    delay_ms(1000);
    
    printf("Starting...\t\n");
    while(TRUE) {        
        value = ds1820_read();
        printf("%f\t\n", value);        
    }
}

main.h

#ifndef MAIN_H
#define MAIN_H

#include <16F690.h>
#device adc=8

#FUSES NOWDT                     //No Watch Dog Timer
#FUSES INTRC_IO                  //Internal RC Osc, no CLKOUT
#FUSES NOPROTECT                 //Code not protected from reading
#FUSES NOBROWNOUT                //No brownout reset
#FUSES NOMCLR                    //Master Clear pin used for I/O
#FUSES NOCPD                     //No EE protection
#FUSES PUT                       //Power Up Timer
#FUSES IESO                      //Internal External Switch Over mode enabled
#FUSES FCMEN                     //Fail-safe clock monitor enabled

#use delay(clock=8000000)
#use rs232(baud=9600, parity=N, UART1, bits=8, stop=1)

#endif /*MAIN_H*/

1wire.c

#ifndef ONE_WIRE_C
#define ONE_WIRE_C

/*
 * One wire (1-wire) driver for CCS C compiler. Suitable for use with devices
 * such as the DS18B20 1-wire digital temperature sensor.
 */

#define ONE_WIRE_PIN PIN_C5

/*
 * onewire_reset()
 * Description: Initiates the one wire bus.
 */
// OK if just using a single permanently connected device
void onewire_reset() {
    output_low(ONE_WIRE_PIN);       // pull the bus low for reset
    delay_us(500);
    output_float(ONE_WIRE_PIN);     // float the bus high
    delay_us(500);                  // wait-out remaining initialisation window
    output_float(ONE_WIRE_PIN);
}


/*
 * onewire_write(int8 data)
 * Arguments: a byte of data.
 * Description: writes a byte of data to the device.
 */
void onewire_write(int8 data) {
    int8 count;

    for(count = 0; count < 8; ++count) {
        output_low(ONE_WIRE_PIN);
        delay_us(2);                // pull 1-wire low to initiate write time-slot.
        output_bit(ONE_WIRE_PIN, shift_right(&data, 1, 0)); // set output bit on 1-wire
        delay_us(60);               // wait until end of write slot.
        output_float(ONE_WIRE_PIN); // set 1-wire high again,
        delay_us(2);                // for more than 1us minimum.
    }
}

/*
 * onewire_read()
 * Description: reads and returns a byte of data from the device.
 */
int onewire_read() {
    int count, data;

    for(count = 0; count < 8; ++count) {
        output_low(ONE_WIRE_PIN);
        delay_us(2);                // pull 1-wire low to initiate read time-slot.
        output_float(ONE_WIRE_PIN); // now let 1-wire float high,
        delay_us(8);                // let device state stabilise,
        shift_right(&data, 1, input(ONE_WIRE_PIN)); // and load result.
        delay_us(120);              // wait until end of read slot.
    }
    return data;
} 

#endif /*ONE_WIRE_C*/

ds1820.c

#ifndef DS1820_C
#define DS1820_C

#include "1wire.c"

float ds1820_read();
void ds1820_configure(int8 TH, int8 TL, int8 config);

/*
 * ds1820_read()
 * Description: reads the ds18x20 device on the 1-wire bus and returns
 *              the temperature
 */
 
float ds1820_read() {
    int8 busy=0, temp1, temp2;
    signed int16 temp3;
    float result;
    
    //ds1820_configure(0x00, 0x00, 0x00);     //9 bit resolution

    onewire_reset();
    onewire_write(0xCC);            //Skip ROM, address all devices
    onewire_write(0x44);            //Start temperature conversion

    while(busy == 0)                //Wait while busy (bus is low)
        busy = onewire_read();

    onewire_reset();
    onewire_write(0xCC);            //Skip ROM, address all devices
    onewire_write(0xBE);            //Read scratchpad
    temp1 = onewire_read();
    temp2 = onewire_read();
    temp3 = make16(temp2, temp1);
 
    //result = (float) temp3 / 2.0;   //Calculation for DS18S20 with 0.5 deg C resolution
    result = (float) temp3 / 16.0;    //Calculation for DS18B20
 
    delay_ms(200);
    return(result);
}

/*
 * ds1820_configure(int8 TH, int8 LH, int8 config)
 * Description: writes configuration data to the DS18x20 device
 * Arguments: alarm trigger high, alarm trigger low, configuration
 */

void ds1820_configure(int8 TH, int8 TL, int8 config) {
    onewire_reset();
    onewire_write(0xCC);            //Skip ROM, address all devices
    onewire_write(0x4E);            //Write to scratchpad
    onewire_write(TH);
    onewire_write(TL);
    onewire_write(config);
}

#endif /*DS1820_C*/

All you have to do is set the define to the appropriate pin you’re using for the 1-wire bus. Remember to attach a 4.7k pullup resistor on the bus to VDD. The value of the pullup resistor is not critical. If I remember correctly, I tested resistors anywhere from 1k to 10k and they worked fine. If not, just stick with the 4.7k pullup as recommended in the DS18B20 datasheet.

10 comments:

  1. Thanks Man, Really!!!
    Cut, Paste, working...
    You, ROCK...

    Thanks for posting, you saved me a lot of time, and memory ;)

    ReplyDelete
  2. Hi, I'm using a pic 18F4550 with the CCS compiler, I modified the file in the main.h # include <16F690.h> to # include <18f4550.h> and compile error mark me, I have to make further modifications libraries?

    I used some other sensor drivers ds18b20.cy program if errors are compiled, but the LCD is shown as TEMP: 0.0, does not change the temperature value, even to approximate the environment.

    I would greatly appreciate some help regarding the correct use of this sensor, because it's really interesting because it requires no calibration and is very small, my email is snoopdog_06@hotmail.com.

    Greetings.

    ReplyDelete
    Replies
    1. Hi, I'm having the same problem, I've hours searching for other libraries, but nothing change, I just do not know where is the problem, I made the same change that you did and nothing, did you have answer ?I would really apreciate your help

      Delete
  3. Very good, my frend, work fine thanks

    ReplyDelete
  4. hi, i am using 16f877a with lcd ds18b20, and i controlled by hand help me

    ReplyDelete
  5. This may be a little dangerous:

    while(busy == 0)
    busy = onewire_read();

    ReplyDelete
  6. I've just converted this code to HITECH C. The following project is for the PIC16F88, but it could easily be converted to something else.

    http://jwandrews.co.uk/files/controller.zip

    ReplyDelete
  7. I'm using PIC18F4550 and it works perfectly in simulation but it doesn't work on protoboard, can you tell me what i need to change in the code to make it run on 18F4550?

    ReplyDelete
  8. i m using Atmega16, can u plz tell me at which port should i connect this temp sensor..plz

    ReplyDelete
  9. Thanks man:) I have used this library of yours before and somehow I lost it. Now I'm back on track. It is quite neat and memory efficient :)

    ReplyDelete