| 
	
	|  |  |  
	
		| View previous topic :: View next topic |  
		| Author | Message |  
		| cotestatnt 
 
 
 Joined: 01 Mar 2010
 Posts: 3
 
 
 
			    
 
 | 
			
				| Dallas DS18B20, 1 wire bus, +/-, multi device, Light codes. |  
				|  Posted: Mon Mar 01, 2010 12:16 pm |   |  
				| 
 |  
				| 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 )
   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
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Sun Jun 13, 2010 1:37 pm |   |  
				| 
 |  
				| 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
 
 
 
			    
 
 | 
			
				| Dallas DS18B20, 1 wire bus, +/-, multi device, Light codes. |  
				|  Posted: Thu Aug 26, 2010 12:47 pm |   |  
				| 
 |  
				| 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
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu Aug 26, 2010 1:41 pm |   |  
				| 
 |  
				| 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
 
 
 
			    
 
 | 
			
				| Dallas DS18B20, 1 wire bus, +/-, multi device, Light codes. |  
				|  Posted: Sun Aug 29, 2010 10:25 am |   |  
				| 
 |  
				| 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
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Mon Aug 30, 2010 9:12 am |   |  
				| 
 |  
				| 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
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Wed Sep 01, 2010 10:51 am |   |  
				| 
 |  
				| 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
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Wed Sep 01, 2010 2:44 pm |   |  
				| 
 |  
				| Great! 
 Thank you for the very useful feedback
  |  |  
		|  |  
		| ljbeng 
 
 
 Joined: 10 Feb 2004
 Posts: 205
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Tue Dec 21, 2010 10:56 am |   |  
				| 
 |  
				| 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
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Tue Dec 21, 2010 12:12 pm |   |  
				| 
 |  
				| 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
 
 
			    
 
 | 
			
				| Lot of DS18 sensor |  
				|  Posted: Thu Jan 27, 2011 7:58 am |   |  
				| 
 |  
				| 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
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu Jan 27, 2011 8:21 am |   |  
				| 
 |  
				| 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
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Wed Feb 19, 2014 7:04 am |   |  
				| 
 |  
				| 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.
 |  |  
		|  |  
		|  |  
  
	| 
 
 | 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
 
 |