|
|
View previous topic :: View next topic |
Author |
Message |
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
DS18B20 - random values |
Posted: Thu May 04, 2017 9:03 am |
|
|
Hi All,
I'm using a DS18B20 through ~75 feet of CAT-5 using the driver circuit as per Maxim's App note 148:
https://www.maximintegrated.com/en/app-notes/index.mvp/id/148
APPENDIX A.
I have 2 of these monitors one at -20C and the other at +5C...
once in a blue moon, the +5C monitor goes "crazy" and reads +9C or some other value a couple of degrees off for about 5 minutes and then returns to +5C
To read this sensor i go through the following steps:
1) Get Rom address for that sensor
2) Address that Rom, and get a reading
3) Check the Check-Sums
4) If the check-sum fails, discard reading and return previous valid value
5) this goes into an Olympic average of 10 readings resulting in an average of 8 addressed and check-sum readings.
I take a reading every second so I cant understand how this fails for ~300 consecutive readings.
This has been working with no errors on both monitors for about 1 month, over 3000 readings per day...
I even took the time to tweak the timing on my Scope considering the long cables.
Since out of the ~20 monitors i have on the field (only 2 with long cables) I'm a starting to believe i have a faulty sensor?
I can understand noise on the line, machinery starting, EMI, and all other typical culprits can screw up 1 or 2 readings every so often... but 5 minutes or 300 readings with a consistent error/offset that comes with a good checksum? ... I'm losing hair.
Code: | //*********************************************************************************
// LONG RANGE 1-Wire Driver
//*********************************************************************************
// This driver uses inverted logic because it is made to drive long cables through
// a 2N7000 Mosfet as per MAXIM Application note 148 Appendix A
// The driver TX via the Mosfet but receives via a different pin.
// (see application not driver circuit for reference)
// This driver is for a single device on the bus - For now.
#define ONE_WIRE_PIN PIN_C3 // Drives Data Line via MOSFET - Logic is thus inverted
#define ONE_WIRE_RX PIN_C5 // Reads the data line - Input Only
void onewire_reset();
void onewire_write(int data);
void onewire_write_bit(int1 bitval);
int onewire_read();
int1 onewire_read_bit();
void onewire_get_rom();
//int onewire_search_rom();
int onewire_crc(int oldcrc, int newbyte);
int ONE_WIRE_ROM[9]; // Holds the ROM Address of the 1-wire device.
//*********************************************************************************
// Sends reset pulse to all 1-wire devices on the bus
//*********************************************************************************
void onewire_reset() // OK if just using a single permanently connected device
{
output_high(ONE_WIRE_PIN); // Since Im using a MOSFET for pull down, logic is inverted
delay_us(500); // pull 1-wire low for reset pulse
output_low(ONE_WIRE_PIN); // Float line
delay_us(500); // wait-out remaining initialisation window.
output_low(ONE_WIRE_PIN); // WTF?? remove
}
//*********************************************************************************
// Writes a single byte to the one-wire bus, passed in data
//*********************************************************************************
void onewire_write(int data)
{
int count;
for (count=0; count<8; ++count)
{
output_high(ONE_WIRE_PIN); // Since Im using a MOSFET for pull down, logic is inverted
delay_us(15); // Pull 1-wire low to initiate write time-slot. (original =2)
output_bit(ONE_WIRE_PIN, (!(shift_right(&data,1,0)))); // Again, Output logic is inverted because of mosfet
delay_us(45); // Wait until end of write slot. (original =60)
output_low(ONE_WIRE_PIN);
delay_us(10); // For more than 1us minimum + recovery time (original =2)
}
delay_us(10);
}
//*********************************************************************************
// Writes a single bit to the one-wire bus, passed in bitval.
//*********************************************************************************
void onewire_write_bit(int1 bitval)
{
output_high(ONE_WIRE_PIN); // Pull 1-wire low to initiate write time-slot.
delay_us(2);
if(bitval==1) output_low(ONE_WIRE_PIN);
delay_us(60); // hold value for remainder of timeslot
output_low(ONE_WIRE_PIN); // Float line
delay_us(2); // Pull 1-wire low to initiate write time-slot.
}
//*********************************************************************************
// Returns a single byte read from the 1-wire bus/device
//*********************************************************************************
int onewire_read()
{
int count, data;
for (count=0; count<8; ++count)
{
output_high(ONE_WIRE_PIN); // Pull 1-wire low to initiate read time-slot.
delay_us(3);
output_low(ONE_WIRE_PIN); // Float line
delay_us(14); // Let device state stabilise
//output_high(PIN_C2); // This is to check that the read is going on at the right time
shift_right(&data,1,input(ONE_WIRE_RX)); // Clock and load result.
//delay_us(2); // This is to check that the read is going on at the right time
//output_low(PIN_C2); // This is to check that the read is going on at the right time
delay_us(45); // Wait until end of read slot
delay_us(10); // Extra Recovery time between bytes
}
delay_us(10); // Extra Recovery time between bytes
return(data);
}
//*********************************************************************************
// Returns a single bit read from the 1-wire bus/device
//*********************************************************************************
int1 onewire_read_bit()
{
int1 bitval=0;
output_high(ONE_WIRE_PIN); // Pull 1-wire low to initiate Read time-slot.
delay_us(2);
output_low(ONE_WIRE_PIN); // Float line
delay_us(15); // Wait 15us from start of time slot
bitval=input(ONE_WIRE_RX); // return value of data line
delay_us(60);
return(bitval);
}
//*********************************************************************************
// Returns the ROM address of the 1-wire device on the bus
// Only works with ONE device on the bus, for more devices use Rom Search
// The function saves the ROM on a global array.
//*********************************************************************************
void onewire_get_rom()
{
int Byte_Count=0;
//int Scratch_Pad[9];
int Temp_CRC=0;
onewire_reset();
onewire_write(0x33); //Issue ROM Read - Only works with 1 device on the Bus.
while(Byte_Count<8) //Get all 8 ROM address bytes - Byte 9 is the CRC
{
ONE_WIRE_ROM[Byte_Count]= onewire_read();
Byte_Count++;
}
Byte_Count=0;
while(Byte_Count<8)
{
Temp_CRC=onewire_crc(Temp_CRC, ONE_WIRE_ROM[Byte_Count]);
Byte_Count++;
}
if(Temp_CRC==0)
{
fprintf(lcd_putc,"Device Found: ");
Byte_Count=0; // Uncomment to print raw data including CRC
while(Byte_Count<8)
{
fprintf(lcd_putc,"%X ",ONE_WIRE_ROM[Byte_Count]);
Byte_Count++;
}
fprintf(lcd_putc,"_%X_\r\n",Temp_CRC);
}
else
{
fprintf(lcd_putc,"1-wire COM error/Bad CRC: %X_\r\n",Temp_CRC);
}
}
//*********************************************************************************
// Checks the CRC of the bytes read from the 1-wire bus.
//*********************************************************************************
int onewire_crc(int oldcrc, int newbyte) // see http://pdfserv.maxim-ic.com/arpdf/AppNotes/app27.pdf
{
int shift_reg, data_bit, sr_lsb, fb_bit, j;
shift_reg=oldcrc;
for(j=0; j<8; j++) // for each bit
{
data_bit = (newbyte >> j) & 0x01;
sr_lsb = shift_reg & 0x01;
fb_bit = (data_bit ^ sr_lsb) & 0x01;
shift_reg = shift_reg >> 1;
if (fb_bit) shift_reg = shift_reg ^ 0x8c;
}
return(shift_reg);
} |
Code: |
float ds1820_read()
{
int busy=0;
float result=0;
int Byte_Count=0;
int Scratch_Pad[9]={0,0,0,0,0,0,0,0,0};
int Temp_CRC=0;
onewire_reset(); // Reset all Devices
onewire_write(0x55); // Match Rom of target device
Byte_Count=0;
while(Byte_Count<8) // Sent all 8 ROM address bytes of target device
{
onewire_write(ONE_WIRE_ROM[Byte_Count]);
Byte_Count++;
}
onewire_write(0x44); // Request Temperature Conversion
while (busy == 0) // Wait for device to finish conversion
busy = onewire_read();
onewire_reset(); // Reset all devices
onewire_write(0x55); // Match Rom of target device
Byte_Count=0;
while(Byte_Count<8) // Sent all 8 ROM address bytes of target device
{
onewire_write(ONE_WIRE_ROM[Byte_Count]);
Byte_Count++;
}
onewire_write(0xBE); // Load Scratch Pad with device values
Byte_Count=0;
while(Byte_Count<9) //Get all 8 Scratch pad bytes - Byte 9 is the CRC
{
Scratch_Pad[Byte_Count]= onewire_read();
Byte_Count++;
}
//***************** CHECK CRC ****************************
Byte_Count=0;
while(Byte_Count<9)
{
Temp_CRC=onewire_crc(Temp_CRC, Scratch_Pad[Byte_Count]);
Byte_Count++;
}
/*
Byte_Count=0; // Uncomment to print raw data including CRC
while(Byte_Count<9)
{
fprintf(lcd_putc,"%X ",Scratch_Pad[Byte_Count]);
Byte_Count++;
}
fprintf(lcd_putc,"_%X_\r\n",Temp_CRC);
*/
//***********************************************************
if(Temp_CRC==0)
{
result = (float) (signed int16) (make16(Scratch_Pad[1], Scratch_Pad[0]))/ 16.0; //Calculation for DS18B20 with 0.1 deg C resolution
//fprintf(lcd_putc,"\r\nSENS - %3.2f\r\n",result);
return(result);
}
else
{
fprintf(lcd_putc,"\r\nSENS - (!)BAD CRC - Using last valid read(!)%3.2f\r\n",Temperature);
return(Temperature);
}
} |
Above is my "Long Range" driver and the Read function i use to get a value from the sensor..
Thank you
G. _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1909
|
|
Posted: Thu May 04, 2017 9:42 am |
|
|
I'd suspect a bad sensor too. I incorporated a DS18-something-20 into every design at my previous job, mainly because the old equipment this stuff replaced had no temperature measurement provision and a lot of weird behaviour seemed to be encountered only when things got "really hot".
Anyway, my interface routine was a carefully crafted interrupt-based method because every design had a lot of high priority and high throughput communications. Measuring temperature was a low priority relative to everything else.
Due to occasional conflicts where the driver should really be measuring the state of the DS1820's data line, but was busy attending to heavy communication traffic, I'd sometimes get one (and only one) weird temperature reading. The readings were triggered once per minute, and in the course of a day, I'd sometimes see 2 or 3 bad readings. The errant readings were off by a lot, so they were easy to spot and compensate for.
Since you're getting many weird readings in a row, I'd suspect the sensor is faulty. Swap it out and see if the problem goes away. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Thu May 04, 2017 10:31 am |
|
|
Try initialising the scratch pad to something other than zero.
One thought is that if all the reads fail, what does the CRC calculation give for the zero array?. (I'd have to sit down and try it). However initialising to zero seems pointless (since if the reads work you overwrite the values), so I'd initialise to something I'm sure would give a non zero CRC. Otherwise it's possible that in a 'complete failure' it accepts the value...
You also don't show us your Olympic average algorithm. Just possible there is something 'missed' here... |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Thu May 04, 2017 2:38 pm |
|
|
Well... i posted this because yesterday i saw 1 or 2 points of after 1 month of good data...
today it evolved into 1:15h of the wildest temperature ride I've seen from any piece of equipment I've ever built, ultimately returning to a peaceful 5C cycle.
The other monitor, built and programmed the same day, same software same setup is running fine at -20C.
Ttelmah: Good points, will check the all 0 case and init (or not) to non 0 values.
G.[/img] _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Thu May 04, 2017 2:41 pm |
|
|
This is the "parent" function that calls the DS18b20 read function and does the olympic average.
Code: | void Read_Sensor() //DS1820B
{
int Local_Filter_index=0;
float Raw_Temperature=0.00;
float local_high=-1000.00;
float local_low=1000.00;
fprintf(lcd_putc,"SENS - Taking 10 DS18B20 readings:\r\n");
fprintf(lcd_putc,"SENS - ");
//Temperature=0.00;
Local_Filter_index=0;
while(Local_Filter_index<10)
{
fprintf(lcd_putc,"%u, ",Local_Filter_index);
Raw_Temperature=ds1820_read(); //Take one reading
if(Raw_Temperature<local_low) local_low=Raw_Temperature; //Check if lowest and save
if(Raw_Temperature>local_high) local_high=Raw_Temperature; //Check if highest and save
Temperature+=Raw_Temperature; //Sum all readings
Local_Filter_index++;
}
fprintf(lcd_putc,"\r\n");
Temperature-=local_low;
Temperature-=local_high;
Temperature/=8;
#ifdef EN_MOVING_AVG
// Moving Average
Temp_History[Temp_History_Index]=Temperature;
Temp_History_Index++;
if(Temp_History_Index>=8)Temp_History_Index=0;
Temperature=0.00;
Local_Filter_index=0;
while(Local_Filter_index<8)
{
Temperature+=Temp_History[Local_Filter_index];
Local_Filter_index++;
}
Temperature/=8.00;
// End Moving Average
#endif
if(Temperature<t_low)t_low=Temperature; // Global or Daily overall Low temp
if(Temperature>t_high)t_high=Temperature; // Global or Daily overall High Temp
#ifdef VAXPRO3_DS
if(Temperature<low_LCD)low_LCD=Temperature; // Resetable Low temp to be displayed on LCD only
if(Temperature>high_LCD)high_LCD=Temperature; // Resetable High temp to be displayed on LCD only
#endif
fprintf(lcd_putc,"SENS - Filtered Temp:%3.2f - Discarded LOW: %3.2f - Discarded HIGH: %3.2f\r\n",Temperature,local_low,local_high);
} |
_________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
|
|
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
|