|
|
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
|