I2C temp sensor reading several degrees low

Go To Last Post
11 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi folks,

I'm working with an SE95 temp sensor which communicates through the I2C interface. This sensor shoud bet +-1 degree celsius accuracy but I'm getting a readout that is around 3-4 degrees celsius too low.

Can you take a look at my code and let me know if you see anything that may be causing the problems. I have multiplied the temp reading by 1000 in order to retain the .125 increments without using floating point math.

This is running on a mega8 with a clock-speed of 8MHz (internal rc).

Thanks!

#define F_CPU 8000000UL
#define TempSensor 0x92 //Address of temperate sensor

#include 
#include 
#include "lcd.h"

volatile long int temp = 0;
int old_temp = 0;
int raw_temp = 0;

void init_timers(void)
{
  TCCR1B |= (1<<CS11) | (1<<CS10); 	//Start 16-bit Timer1 with prescaler of 64 (overflows ~2/sec)
  TIMSK |= (1<<TOIE1);			//Enable Timer Overflow Interrupt
  sei();				//Enable Global Interrupts
}

void twi_start(unsigned char SlvAddr)
{
  TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTA);  	//Send start command
  while(!(TWCR & (1<<TWINT)));                 	//Wait for bus to become ready
  TWDR = SlvAddr;					     	//Write device address to data register
  TWCR = (1<<TWINT) | (1<<TWEN);			//Send device address
  while(!(TWCR & (1<<TWINT)));			//Wait for bus to become ready
}

void twi_stop(void)
{
  TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
}

char twi_read_ack(void)
{
  TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
  while(!(TWCR & (1<<TWINT)));
  return TWDR;
}

char twi_read_nack(void)
{
  TWCR = (1<<TWINT) | (1<<TWEN);
  while(!(TWCR & (1<<TWINT)));
  return TWDR;  
}

void ReadTemp(void)  			//Loads into from temp sensor into raw_temp variable
{
  cli();
  raw_temp = 0;
  twi_start(TempSensor + 1);
  raw_temp = (twi_read_ack()<<8); 	//Read MSB
  raw_temp += twi_read_nack(); 	//Read LSB
  twi_stop();
  sei();
}

void DispTemp(char Format)
{
  cli();		//Atomic!
  temp = raw_temp>>5;   //Shift the int to work with 11-bit temp readout
  sei();
  temp *= 1000;         //Software handled floating point
  temp /= 8;            //Multiply by the value resolution of the sensor (0.125 C)
  if (Format)           //Conversion for Fahrenheit
  {
    temp *= 9;
    temp /= 5;
    temp += 32000;
  }
  char hunds = temp/100000;
  char tens = (temp%100000)/10000;
  char ones = (temp%10000)/1000;
  char tenths = (temp%1000)/100;
  char hundreths = (temp%100)/10;
  char thousandths = temp%10;
  if(hunds) lcd_putc(hunds);
  if ((tens) | (hunds)) lcd_putc(tens + '0');
  lcd_putc(ones + '0');
  lcd_putc('.');
  lcd_putc(tenths + '0');
  lcd_putc(hundreths + '0');
  lcd_putc(thousandths + '0');
  lcd_putc(0xDF);
  if (Format) lcd_putc('F');
  else lcd_putc('C');
/*
lcd_putc(temp/10 + '0');
lcd_putc(temp%10 + '0');
*/
}


int main(void)
{
  lcd_init(LCD_DISP_ON);  //Initialize LCD with the cursor off

  lcd_clrscr();           //Clear the LCD screen
  TWBR = 32;		  //Set I2C speed

  ReadTemp();
  DispTemp(0);
  lcd_gotoxy(0,10);
  DispTemp(1);

  old_temp = raw_temp;
  init_timers();

  for (;;)
  {
    // Do nothing forever
  }
}

ISR(TIMER1_OVF_vect)
{
  ReadTemp();
  if (old_temp != raw_temp)
  {
    lcd_clrscr();
    DispTemp(0);
    lcd_gotoxy(0,10);
    DispTemp(1);
    old_temp = temp;
  }
}

Edit: Clarified that degrees are in celsius.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I can't help you with any potential code problems but I can't help wonder what sort of device you are comparing the SE95 against (your "gold" standard so to speak)? Another way to put it is what is telling you that your readings are 4 degrees off?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Personally I would just say:

long temp1000 = raw_temp * 31.25 + 5;
lcd_puts(ltoa(temp1000 /1000));
lcd_putc('.');
lcd_puts(ltoa(temp1000 % 1000));

It would be interesting to see the difference in code size between the two methods. It seems unwise to throw away the lsbs from your sensor. Why not keep everything but just display say 2 decimal places.

I have not simulated your code, but you are going to have rounding errors at least.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

SteveN wrote:
I can't help you with any potential code problems but I can't help wonder what sort of device you are comparing the SE95 against (your "gold" standard so to speak)? Another way to put it is what is telling you that your readings are 4 degrees off?

The thermometer shows 18.625 C which is 65.525 F.... I can tell by feel that it's at least 5 degrees F warmer than that. I also have two clocks (different models) that register withing .1 degree F of each other reading 73 right now. I'd say there is definitely a problem.

David, thanks for the input. I'll give the new code a try and report back.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Clocks usually use an on-board thermistor to measure temperature, you sure it's not the clock's internal casing temperature you're measuring 5 degrees higher?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Interesting chip.

One might argue with the data sheet's description: Ultra high accuracy digital temperature sensor and thermal wtchdog, is a bit misleading.

Ultra high resolution might be a better description, with 0.03125'C resolution available, +/- 1'C accuracy.

That said, C isn't my language, but:

Did you put the specified bypass capacitor across the SE95's power supply pins, as close to the chip as possible? If not, tack one down onto your board and see if it makes a difference.

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

DocJC wrote:
That said, C isn't my language, but:

Did you put the specified bypass capacitor across the SE95's power supply pins, as close to the chip as possible? If not, tack one down onto your board and see if it makes a difference.

JC

We have a winner. Thank you for pointing this out. I failed to include the capacitor at all in my design... popped one in and I think the temp is right on the money now. Thank you!

Pointless rambling to follow, feel free to stop reading:

I've been doing a lot of things at once for this project. This is the first homebrew PCB I've made, the first time I've soldered a TSSOP chip, and the first time I've used the I2C (or should I call it TWI?) communications.

When I designed the board I made it to interface with the usual 2x5 pin header. The first time I soldered the chip on up-side down.... noticed that right away before I soldered the rest of the components. Once I had it hooked up I found that I had the connection for SDA and SCL lines flipped, now I find that I needed to have a cap connected. Guess it's time for version 0.2 of this board.

Thanks again!

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Great!

I'm glad it now works for you. Now go cut those long legs off that cap and tack it down directly against the board with as short of leads as possible.

BTW, you are ahead of me, all of my boards have been through - hole components... My first SMT project is still on paper...

Congrats on your project!

JC

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Now that I've done one smd chip I'd like to do more of that. Saves me from drilling the holes. I've got a dremel drill press and a set of very fine carbide bits but it's time consuming making sure you are drilling in the exact center of the holes.

I found that using the toner transfer method is the hardest part of the process. I've found a paper that works well, but I haven't yet mastered the ironing and it takes me several tries to get a clean, non-smearing transfer.

Then again, my hole pcb process is pretty sketchy... I haven't figured out quite how to balance out the home-made cupric chloride as an etchant. Oh well... gives me something to do.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There's a homemade PCB board group on yahoo with all sorts of formulas and archives of data. I use a laminator to make the toner transfer film adhere to the board, and pulsar (expensive) paper to print on. I use mixed SMD and through hole, with the SMD stuff being the I2C buffer and the I2C LED controller.

One thing you can do for toner transfer is to only transfer one side, protect the other side with contact paper (clear self adhesive shelf liner plastic film), then drill a few holes, align the other side with that, then repeat. Takes longer, but the alignment procedure is easier.

For the Vias I use eyelets soldered in place.

Harvey

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is a new code. Try it out.

// Send a byte to the sensor
// -----------------------------------------------------------------------

int SendByte(char byte) {
char tempbyte;
int i;

DATA_LINE_OUT;
tempbyte=byte;

for (i=0x80;i>0;i/=2) {

if (tempbyte & i)
DATA_LINE_HIGH;
else
DATA_LINE_LOW;

CLOCK_LINE_HIGH;
usleep(1000);
CLOCK_LINE_LOW;
}

DATA_LINE_IN;
CLOCK_LINE_HIGH;
CLOCK_LINE_LOW;
return 1;
}

// -----------------------------------------------------------------------
// Read a byte from the sensor
// withack
// 1 = send the ACK
// 0 = don't send the ACK
// -----------------------------------------------------------------------

char ReadByte(int withack) {
char tempbyte;
int i;

tempbyte=0;
DATA_LINE_IN;

for (i=0x80;i>0;i/=2) {
CLOCK_LINE_HIGH;
if (DATA_LINE_READ) tempbyte |= i;
CLOCK_LINE_LOW;
}

if (withack) {
// Acknowledge del byte
DATA_LINE_OUT;
DATA_LINE_LOW;
CLOCK_LINE_HIGH;
CLOCK_LINE_LOW;
DATA_LINE_IN;
} else {
// Senza acknowledge
DATA_LINE_OUT;
DATA_LINE_HIGH;
CLOCK_LINE_HIGH;
CLOCK_LINE_LOW;
DATA_LINE_IN;
}

return tempbyte;

}

===========================================

napster

New Jobs