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

DS18B20 - random values

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Gabriel



Joined: 03 Aug 2009
Posts: 1067
Location: Panama

View user's profile Send private message

DS18B20 - random values
PostPosted: Thu May 04, 2017 9:03 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu May 04, 2017 9:42 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu May 04, 2017 10:31 am     Reply with quote

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

View user's profile Send private message

PostPosted: Thu May 04, 2017 2:38 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Thu May 04, 2017 2:41 pm     Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion 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