CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Dallas DS18B20, 1 wire bus, +/-, multi device, Light codes.

 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
cotestatnt



Joined: 01 Mar 2010
Posts: 3

View user's profile Send private message

Dallas DS18B20, 1 wire bus, +/-, multi device, Light codes.
PostPosted: Mon Mar 01, 2010 12:16 pm     Reply with quote

Some times ago i was looking in the forum about handling multiple Dallas DS18B20 sensor for a temperature logger over RS232.
I found something, but the codes was too much "heavy" for the PIC i was planning to use (16F628A with only 3.5k of ROM memory)

Starting from the codes founded in this discussion, ( http://www.ccsinfo.com/forum/viewtopic.php?t=19255),
i rewrite a couple of function for getting my purpose.

I basically rewrote the CRC function (from driver DS2432.c of standard library) and I have avoided using float numbers in the main(). Float operation indeed, take a lot of space in PIC.
Again, i edit the FindDevices() funtion that now return the number of devices on the bus.

With this code and with PCM compiler v4.084 i use only 62% of ROM and 54-63% of RAM.
The sample project attached, use the Timer1 for timed output versus PC (software inverted RS232 for direct connection without any kind of hardware - NO MAX232, NO transistor. Just for testing ) Cool
The readings is separated with semicolumn ";" for an easy logging into a .csv file (i wrote a little phyton script).

TempLogger.c
Code:

// Temperature Logger - TNT_1.0 - Cotesta Tolentino - cotestatnt@yahoo.com

// ************************************************************************************** //
// This project is based on PIC16F628A. It sends a string over serial pin with
// formatted string with temperatures (positive and negaive), every PERIOD * 524ms@4Mhz
// I use the onewire.c library from "tesla80" user in the CCS forum with some
// modifications. The CRC function is the one from driver DS2432.c of standard library.
// It is smaller and faster and take less ROM space.
// The function FindDevices() returns the number of devices founded on the bus
// (it scan until 8 devices but everyone can easily edit)
// All the arithmetics operations on variables is without float number for ROM space saving:
// actually it takes about 62% of the PIC16F628A ROM, so some extra functions can be done.
// ************************************************************************************** //

// This program is free software; you can redistribuite it and/or modify it under
// the terms of the GNU/General Pubblic License as published the Free software Foundation;
// either version 3 of the License, or (at your opinion) any later version.

#include "TempLogger.h"
#include "onewire.c"
#define PERIOD 10
// #define PERIOD 1717 // about 15 minutes

void init(void);
int16 time = 101;
int1 RST = 0;
// other global variables in the "onewire.c" file

// main function
void main(void)
{
   int8 i, tmp, numDev = 0;
   int16 sensData, celsius, fract;
   int8 scratch[9];     
   unsigned char sign;
   
   init();
   output_float(DQ);       // Set as input. 4k7 pullup on bus.
   
   // Find devices on the bus
   numDev = FindDevices();   
   for(i=1; i<=numDev; i++)
   {
      printf("Device_%u: ", i);
      for (tmp=0; tmp<=8; tmp++)
         printf("%X", FoundROM[i][tmp]);
      printf("\n");
   }
   
   while(TRUE)
   { 
      // I'm alive!
      if (RST){output_toggle(LED); RST = 0;}
     
      if ((!ow_reset())&&(time > PERIOD))     // If a device is present and it's time to send string
      {
         time = 0;
         write_byte(0xCC); // Skip Rom command
         write_byte(0x44); // Temperature convert command
         output_float(DQ);
         delay_ms(750);    // Max. conv. time is 750mS for 12 bit
         ow_reset();
         
         // read all devices on bus
         for (numRoms=1; numRoms <= numDev; numRoms++)
         {
            if (Send_MatchRom())
            {
               write_byte(0xBE); // Read scratch pad command               
               for(i=0; i<2; i++)
               {
                  scratch[i]= read_byte();
               }           
               // raw sensor data (16bit)
               sensData = make16(scratch[1], scratch[0]);
               
               // check negative
               if (bit_test(sensData, 15))
               {
                  sign = '-';
                  sensData = ~sensData + 1;               
               } else
                     sign = '+';
   
               fract = 0;
               tmp = sensData&0xF;        // obtain the fractional part nibble               
               celsius = sensData >> 4 ;  // calculate the whole number part
               
               if (tmp == 0xFF)
                   celsius = celsius + 1;    // Calculate the fractional part           
               else
                  for (i=0; i<tmp; i++)   
                     fract = fract + 0625;   
       
               printf("Device_%u;%c%03lu.%04lu;", numRoms, sign, celsius, fract); 


               
            }     // if (Send_MatchRom())
         }     // for (numRoms=1; numRoms <= numDev; numRoms++) 
         
         printf ("\n");  // new line when end of all devices on the bus temperature readings is done
         
      }     // if ((!ow_reset())&&(time > PERIOD))
   }     // while (TRUE)
}     // main


void init()
{
   enable_interrupts(INT_TIMER1);
   enable_interrupts(GLOBAL);
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
}

#int_TIMER1
void  TIMER1_isr(void)
{
   time++;
   RST = 1;
}



TempLogger.h
Code:

#include <16F628A.h>
#device *=16
#device adc=8

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES INTRC_IO                 //Internal RC Osc, no CLKOUT
#FUSES PUT                      //Power Up Timer
#FUSES NOMCLR                   //Master Clear pin used for I/O
#FUSES BROWNOUT                 //Reset when brownout detected
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD                    //No EE protection
#FUSES NOPROTECT                //Code not protected from reading

#use delay(clock=4000000,RESTART_WDT)

#define DQ PIN_B0      // One Wire Bus pin assignment
#define LED PIN_B1     // Status LED


// Software usart will be used with "invert" option.
// so direct connect without interfaces to PC is available
#use rs232(baud=9600,parity=N,xmit=PIN_B4,rcv=PIN_B5,bits=8, invert)


onewire.c
Code:


// Global variables
int8 RomBytes[8];     
int8 lastDiscrep = 0;
short doneFlag = 0;
int8 FoundROM[9][8];    // Table of found ROM codes, 8 bytes for each
int8 numROMs;
int8 dowcrc;            // crc is accumulated in this variable


//calc_CRC - INTERNAL FUNCTION
//Purpose:    To calculate an 8-bit CRC based on a polynomial and the series
//            of data bytes
//Note:       Polynomial used x^8 + x^5 + x^4 + 1 = 10001100
//Inputs:     A pointer to an array of the data bytes and an int saying how many
//            bytes there are in the data array
//Outputs:    An int8 which is the calculated CRC
int8 calc_CRC(int8* data, int8 bytes)
{
   #define CRC_POLY      0x8C
   int8 shift_register = 0, i, datab, bits;

   for(i = 0; i < bytes; ++i)
   {
      datab = *(data + i);

      for(bits = 0; bits < 8; ++bits)
      {
         if(bit_test((shift_register ^ datab), 0))
         {
            shift_register = shift_register >> 1;
            shift_register ^= CRC_POLY;
         }
         else
         {
            shift_register = shift_register >> 1;
         }

         datab = datab >> 1;
      }
   }
   return shift_register;
} //calc_CRC


// Returns 0 for one wire device presence, 1 for none
int8 ow_reset(void)
{
   int8 presence;
   
   output_low(DQ);
   delay_us(488);          // Min. 480uS
   output_float(DQ);
   delay_us(72);           // Takes 15 to 60uS for devices to respond
   presence = input(DQ);
   delay_us(424);          // Wait for end of timeslot
   return(presence);
}

//******************************************************************************
// Read bit on one wire bus
int8 read_bit(void)
{
   output_low(DQ);
   delay_us(1);         // Added, 1uS min. Code relied on 8051 being slow.
   output_float(DQ);
   delay_us(12);        // Read within 15uS from start of time slot
   return(input(DQ));   
}   

//******************************************************************************
void write_bit(int8 bitval)
{
   output_low(DQ);

   if(bitval == 1) {
      delay_us(1);      // 1uS min. Code relied on 8051 being slow.
      output_float(DQ);
   }
   delay_us(105);       // Wait for end of timeslot
   output_float(DQ);
}

//******************************************************************************
int8 read_byte(void)
{
   int8 i;
   int8 val = 0;

   for(i=0;i<8;i++)
   {
      if(read_bit()) val |= (0x01 << i);
      delay_us(120);  // To finish time slot
   }

   return val;
}

//******************************************************************************
void write_byte(int8 val)
{
   int8 i;
   int8 temp;

   for (i=0;i<8;i++)
   {
      temp = val >> i;
      temp &= 0x01;
      write_bit(temp);
   }

   delay_us(105);
}

//******************************************************************************
// One wire crc
int8 ow_crc(int8 x)
{
   dowcrc = calc_CRC(x,8);
   return dowcrc;
}

//******************************************************************************
// Searches for the next device on the one wire bus. If there are no more
// devices on the bus then false is returned.
int8 Next(void)
{
   int8 m = 1;             // ROM Bit index
   int8 n = 0;             // ROM Byte index
   int8 k = 1;             // Bit mask
   int8 x = 0;
   int8 discrepMarker = 0;
   int8 g;                 // Output bit
   int8 nxt;               // Return value
   short flag;

   nxt = FALSE;            // Reset next flag to false
   dowcrc = 0;             // Reset the dowcrc
   flag = ow_reset();

   if (flag||doneFlag)     // If no parts return false
   {
      lastDiscrep = 0;     // Reset the search
      return FALSE;
   }
   
   write_byte(0xF0);       // Send SearchROM command
   do
   {
      x = 0;
      if (read_bit() == 1)
         x = 2;
      delay_us(120);
      if (read_bit() == 1)
         x |= 1;                    // And it's complement 
      if (x == 3)                   // There are no devices on the one wire bus
         break;
      else
      {
         if (x > 0)                 // All devices coupled have 0 or 1
            g = x >> 1;             // Bit write value for search

         // If this discrepancy is before the last discrepancy on a previous
         // Next then pick the same as last time.
         else
         {
            if (m < lastDiscrep)
               g = ((RomBytes[n] & k) > 0);
            // If equal to last pick 1
            else
               g = (m == lastDiscrep);  // If not then pick 0

               // If 0 was picked then record position with mask k
               if (g == 0) discrepMarker = m;
         }

         // Isolate bit in ROM[n] with mask k
         if (g == 1) RomBytes[n] |= k;
         else RomBytes[n] &= ~k;

         write_bit(g);  // ROM search write

         m++;           // Increment bit counter m
         k = k << 1;    // and shift the bit mask k
         // If the mask is 0 then go to new ROM
         if (k == 0)
         {  // Byte n and reset mask
            ow_crc(RomBytes[n]);      // Accumulate the crc
            n++;
            k++;
         }
      }
   } while (n < 8);  // Loop through until through all ROM bytes 0-7

   if (m < (65||dowcrc))   // If search was unsuccessful then
      lastDiscrep = 0;     // reset the last Discrepancy to zero
   else  // Search was successful, so set lastDiscrep, lastOne, nxt
   {
      lastDiscrep = discrepMarker;
      doneFlag = (lastDiscrep == 0);
      nxt = TRUE; // Indicates search not yet complete, more parts remain
   }

   return nxt;
}

//******************************************************************************
// Resets current state of a ROM search and calls Next to find the first device
// on the one wire bus.
int8 First(void)
{
   lastDiscrep = 0;
   doneFlag = FALSE;
   return Next();    // Call Next and return it's return value;
}

//******************************************************************************
int8 FindDevices(void)
{
   int8 m, cont = 0;
   if(!ow_reset())
   {
      if(First())    // Begins when at least one part found
      {
         numROMs = 0;
         do
         {
            numROMs++; 
            cont++;
            for (m=0;m<8;m++)
            {
               FoundROM[numROMs][m] = RomBytes[m];
            }
         } while (Next());   // Continues until no additional                             
      }
   }
   return cont;

}

//******************************************************************************
// Sends Match ROM command to bus then device address
int8 Send_MatchRom(void)
{
   int8 i;
   if (ow_reset()) return FALSE;          // 0 if device present
   write_byte(0x55);                      // Match ROM

   for (i=0;i<8;i++)
   {
      write_byte(FoundRom[numROMs][i]);   // Send ROM code
   }

   return TRUE;
}
Brampje



Joined: 13 Jun 2010
Posts: 1

View user's profile Send private message

PostPosted: Sun Jun 13, 2010 1:37 pm     Reply with quote

Could someone confirm that this code does work?

When I'm trying this code on a PIC16F777, of course with the correct fuses and settings, the PIC can't find any sensors on the bus. I'm using the normal DS18B20+ sensors with a pullup resistor.
creative_35



Joined: 02 Jan 2007
Posts: 15

View user's profile Send private message

Dallas DS18B20, 1 wire bus, +/-, multi device, Light codes.
PostPosted: Thu Aug 26, 2010 12:47 pm     Reply with quote

Hi cotestatnt, Thanks for the code.
The code is working fine with 876A@10Mhz.
But when I tried to do @20MHz it's not identifying the device.
I tried with several crystals, and it's almost OK up to 11.5Mhz.
Anybody can solve the issue?


NB: In my experiments it's recognizing the devices up to 14Mhz in temperatures below 30 degree centigrade.
cotestatnt



Joined: 01 Mar 2010
Posts: 3

View user's profile Send private message

PostPosted: Thu Aug 26, 2010 1:41 pm     Reply with quote

Hi creative_35, Thank you for your testing!
It seems to be like a thermal drift that, with the high frequency clock, brings out DS18B20 timing problems.

I think that maybe when we call some delay function for example delay_us(105) the PIC doesn't wait really 105uS but somewhat else.
In this manner we can't respect the correct timings for the sensor as you can see in the datasheet.
Do you have an oscilloscope? You should check if the delay_us function is really precise @20Mhz, for example generating a square wave or like that.
Otherwise you could try increasing the timings in the onewire.c library, especially when we call delay_us(1) (in the datasheet we can see >1uS not equal).

Let know us!
creative_35



Joined: 02 Jan 2007
Posts: 15

View user's profile Send private message

Dallas DS18B20, 1 wire bus, +/-, multi device, Light codes.
PostPosted: Sun Aug 29, 2010 10:25 am     Reply with quote

Thanks for the reply. First of all I am sorry to say that I don't have an oscilloscope :(
I tested the timings in MBLAB simulator/stopwatch and it's perfect but don't know what's happening in real world. Anyway I will try to change the delays in one_wire.c. The result will be published soon!
FFT



Joined: 07 Jul 2010
Posts: 92

View user's profile Send private message

PostPosted: Mon Aug 30, 2010 9:12 am     Reply with quote

You can try it also by changing your xtall. Some crystals have big tolerance.
And use more then 1 sensor for testing.
creative_35



Joined: 02 Jan 2007
Posts: 15

View user's profile Send private message

PostPosted: Wed Sep 01, 2010 10:51 am     Reply with quote

Thanks everyone. It's working fine @ 20Mhz with some minor modifications.
Through trial and error I found some values matching.
Code:
//******************************************************************************
// Read bit on one wire bus
int8 read_bit(void)
{
   output_low(DQ);
   delay_us(5);         // Added, 1uS min.(@4Mhz 1-2@20Mhz 3-9)
   output_float(DQ);
   delay_us(18);        // Read within 15uS from start of time slot (@4Mhz 6-11 @20Mhz 15-22)
   return(input(DQ));   
}   

//******************************************************************************
void write_bit(int8 bitval)
{
   output_low(DQ);

   if(bitval == 1) {
      delay_us(5);      // 1uS min. (@4Mhz 1-2 @20Mhz 3-9)
      output_float(DQ);
   }
   delay_us(105);       
   output_float(DQ);
}

//******************************************************************************


It's working fine now.
cotestatnt



Joined: 01 Mar 2010
Posts: 3

View user's profile Send private message

PostPosted: Wed Sep 01, 2010 2:44 pm     Reply with quote

Great!

Thank you for the very useful feedback Idea
ljbeng



Joined: 10 Feb 2004
Posts: 205

View user's profile Send private message

PostPosted: Tue Dec 21, 2010 10:56 am     Reply with quote

I have this code working on a 18F2685 @ 4MHz. I have 2 DS18B20+ devices on 1 pin and it sees both serial numbers. It is always reading 85.000 degrees for both sensors. Is it a timing issue?
ljbeng



Joined: 10 Feb 2004
Posts: 205

View user's profile Send private message

PostPosted: Tue Dec 21, 2010 12:12 pm     Reply with quote

Ok, it works now. Here's the thing. Do this once for each part:
Code:

write_byte(0xCC);
write_byte(0x4E);

write_byte(125);
write_byte(-55); //this should be done for proper working of DS18B20
write_byte(127);
//!
ds18b20_initialization();
write_byte(0xCC);
write_byte(0x48);
delay_ms(15);


Then take it out of the code and reset the probes.....
kontakt



Joined: 27 Jan 2011
Posts: 7
Location: HU

View user's profile Send private message

Lot of DS18 sensor
PostPosted: Thu Jan 27, 2011 7:58 am     Reply with quote

Hello,

I tried to use this TempLogger code and it works up to 8 sensors. When I connected 22 sensors (DS18B20 each) it saw them but from 9. sensor it can not write the RomCode and its temp value. If I connect more then 22 sensor it can not see any sensor.
Could you help me what would be the probleme?
kontakt



Joined: 27 Jan 2011
Posts: 7
Location: HU

View user's profile Send private message

PostPosted: Thu Jan 27, 2011 8:21 am     Reply with quote

The first problem is ok, i had to write through the int8 FoundROM[9][8]; to int8 FoundROM[32][8]; because i have 32 sensors. It works fine up to 27 sensors. I tried to get out some sensors and connect in other but it still works up to 27 sensors.
What would be the problem?
farhan882



Joined: 19 Feb 2014
Posts: 1

View user's profile Send private message

PostPosted: Wed Feb 19, 2014 7:04 am     Reply with quote

I used your ccs library for onewire temperature sensors. It is working great for some sensors but isn't working for others. Then I realized that there is a small difference in each one.

The sensors that are working with your code have 'C4' mentioned on them in 3rd line while those which aren't working has 'C3'. I searched for these terms in the datasheet and on forums but still can't find anything.

If anyone knows anything please help.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group