View previous topic :: View next topic |
Author |
Message |
h.a.j.molenaar
Joined: 04 May 2005 Posts: 9
|
Applying DS1629 with higher temperature resolution |
Posted: Thu Jun 23, 2005 3:19 am |
|
|
Hi all,
In a small temperature datalogger is the DS1629 from Dallas semiconductor http://www.maxim-ic.com used for converting the temperature.An algoritme is given in the datasheet to obtain a higher temperature resolution.
The data obtained with this higher resolution shows strange steps, so or the component can not measure properly or the algortime implemented by me is not correct.
Question: who have experience with applying the DS1629 with the high resolution temperature measurement.
Greetings Hugo. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jun 23, 2005 12:03 pm |
|
|
Dallas Semiconductor appnote 105 has some C source code at the
end of the document which shows how to do this. Here's the link.
http://www.eetasia.com/ARTICLES/2001APR/2001APR09_AMD_AN.PDF
I think you should post your full routine that does the calculations,
and be sure to post the variable declarations. Also post the printf()
statement that displays the result. If you're new to CCS, there
could easily be problems in your routine with proper variable sizes,
data type casting in math operations, and the printf() format specification. |
|
|
h.a.j.molenaar
Joined: 04 May 2005 Posts: 9
|
Applying DS1629 with higher temperature resolution |
Posted: Tue Jul 05, 2005 5:13 am |
|
|
Hi, it took some time but here is the C-code.
The datasheet and the application note is to my opinion rather confusing.
The high resolution temperatures read from the DS1629 shows jumps of 0.5 degrees. I do not know or it is due to:
- wrong impementation of algoritme.
- the DS1629 instabilitly or so.
Due to memmory size it is not possible to perform a float calculation and
the pic controlls the DS1629 stores the result in external serial eeprom.
Afterwards a dockinstation reads these results. Due the small size of the
datalogger it is not possible to display any register or variable.
// Function : TempSensorRTC
// Parameters : None
// Returns : MSB LSB 16 bit temperature from sensor in rtc
// Affects :
// Description : Reads high resolution temperature from DS1629
// Attention, function returns a long integer as LSB and MSB but the
// buffer needs MSB, LSB. Therefore this two are swapped at the end
// of the function.
//
// Function uses the following equation.
// TempSensorRTSC = temperature (nine bits) - 0.25 degrees + ((count - remain) / count)
// __________________________________________________________________________
signed long int TempSensorRTC()
{
signed long int temperature;
unsigned int remain;
unsigned int count;
unsigned long int resolution;
unsigned long int substraction;
unsigned int swap_byte;
i2c_start();
i2c_write(RTCWRITE); // Write to rtc.
i2c_write(CMD_START_CONVERT); // Start conversion,(takes one
i2c_stop(); // second).
delay_ms(1200); // Wait one second.
i2c_start();
i2c_write(RTCWRITE); // Write to rtc.
i2c_write(CMD_READTEMP);
i2c_stop();
i2c_start(); // Start.
i2c_write(RTCREAD); // Read from rtc.
temperature = i2c_read(1); // MSB of temp, Acknowledge.
temperature <<= 8; // Shift in place.
temperature |= i2c_read(0); // Read LSB.
i2c_stop(); //
i2c_start();
i2c_write(RTCWRITE); // Write to rtc.
i2c_write(CMD_COUNTREMAIN); // read count.
i2c_stop();
i2c_start(); // Repeated start.
i2c_write(RTCREAD); // Read from rtc.
remain = i2c_read(0); // no acknowledge.
i2c_stop();
i2c_start();
i2c_write(RTCWRITE); // Write to rtc.
i2c_write(CMD_COUNTC); // read slope.
i2c_stop();
i2c_start(); // Repeated start.
i2c_write(RTCREAD); // Read from rtc.
count = i2c_read(0); // no acknowledge.
i2c_stop();
if (count != 0) // Only if count is not equal to zero
{ // remain and count have to be taken
// into the calculation.
substraction = (count - remain);
substraction <<= 8; // Multiply substraction with 255.
resolution = substraction / count;// res. is a number between 1 and 255.
// Substract 0.25 degrees and add resolution.
temperature = temperature - 0x0040 + resolution;
}
temperature &= 0xFFF0; // 12 bits precision.
swap_byte = temperature; // swap_byte is LSB.
temperature >>=8; // Shift MSB to LSB position.
(*(&temperature+1))= swap_byte; // Highest byte of temperature.
return(temperature);
} |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Jul 06, 2005 1:01 am |
|
|
I'm working on your problem. It might be another day or two
before I can post a reply. I don't have a ds1629, but I do have
a ds1621 and it's very similar, so that's what I'm using to test the code. |
|
|
h.a.j.molenaar
Joined: 04 May 2005 Posts: 9
|
High resolution temperature measurement |
Posted: Wed Jul 06, 2005 1:32 pm |
|
|
Fantastic, I am still working on the problem and let you know if I find out more. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jul 07, 2005 11:57 am |
|
|
I made a working high resolution driver for the ds1621.
It does the final calculations in floating point. I know
you wanted to do it with integer math, but that's really
a separate problem. I thought the most important thing
would be to get a driver that produced a stable output.
This driver should work for the ds1629 if the i2c write
and read addresses are changed to 0x9E and 0x9F.
Here is sample output. The values are in degrees Centigrade.
Code: |
22.35 // This is room temperature.
22.35
22.35
22.35
22.35
22.35
22.35 // I just touched the ds1621 for an instant.
22.38 // It's going up slightly.
22.40
22.55
22.57
22.55 // Now it's cooling down again.
22.55
22.53
22.53
22.51
22.51
22.51
22.48
|
Here is the demo program that calls the driver.
Code: |
#include <16F877.h>
#fuses XT, NOWDT, NOPROTECT, PUT, BROWNOUT, NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)
#use i2c(Master, sda=PIN_C4, scl=PIN_C3)
#include <ds1621hr.c>
void main()
{
float result;
ds1621_init();
while(1)
{
result = ds1621_read_temp_hires();
printf("%3.2f\r\n", result);
delay_ms(1000);
}
} |
Here is the driver.
Code: |
// ds1621hr.c -- High resolution output driver for the ds1621.
// Output is a floating point number in degrees
// centigrade. It should be displayed by printf()
// with this precision: %3.2f
// i2c addresses
#define DS1621_I2C_WRITE_ADDRESS 0x90
#define DS1621_I2C_READ_ADDRESS 0x91
// DS1621 commands
#define DS1621_CMD_READ_TEMP 0xAA
#define DS1621_CMD_READ_SLOPE 0xA9
#define DS1621_CMD_READ_COUNTER 0xA8
#define DS1621_CMD_START_CONVERSION 0xEE
#define DS1621_CMD_STOP_CONVERSION 0x22
#define DS1621_CMD_ACCESS_CONFIG 0xAC
#define DS1621_CONFIG_INIT 0x09 // Use one-shot conversions
#define DS1621_CONVERSION_DONE_MASK 0x80
//======================================
void ds1621_init(void)
{
i2c_start();
i2c_write(DS1621_I2C_WRITE_ADDRESS);
i2c_write(DS1621_CMD_ACCESS_CONFIG);
i2c_write(DS1621_CONFIG_INIT);
i2c_stop();
}
//--------------------------------------
int8 ds1621_read_config(void)
{
int8 config;
i2c_start();
i2c_write(DS1621_I2C_WRITE_ADDRESS);
i2c_write(DS1621_CMD_ACCESS_CONFIG);
i2c_start();
i2c_write(DS1621_I2C_READ_ADDRESS);
config = i2c_read(0);
i2c_stop();
return(config);
}
//--------------------------------------
float ds1621_read_temp_hires(void)
{
int8 count_remain;
int8 count_per_degree;
signed int16 temp_read;
float frac_deg;
int16 k;
int8 status;
i2c_start();
i2c_write(DS1621_I2C_WRITE_ADDRESS);
i2c_write(DS1621_CMD_START_CONVERSION);
i2c_stop();
// Poll the conversion done bit in the Config register.
// When it goes high, then we can proceed. It should
// go high in 1 second or less. If it takes 2 seconds,
// we will abort and display an error message.
for(k = 0; k < 2000; k++)
{
status = ds1621_read_config();
if(status & DS1621_CONVERSION_DONE_MASK)
break;
delay_ms(1);
}
if(k == 2000)
{
printf("Error: Conversion Timed out. Result is invalid.\n\r");
return(0.0);
}
i2c_start();
i2c_write(DS1621_I2C_WRITE_ADDRESS);
i2c_write(DS1621_CMD_READ_TEMP);
i2c_start();
i2c_write(DS1621_I2C_READ_ADDRESS);
temp_read = i2c_read(); // Read MSB
temp_read <<= 8;
temp_read |= i2c_read(0); // Read LSB
i2c_stop();
// Read the 8-bit counter value.
i2c_start();
i2c_write(DS1621_I2C_WRITE_ADDRESS);
i2c_write(DS1621_CMD_READ_COUNTER);
i2c_start();
i2c_write(DS1621_I2C_READ_ADDRESS);
count_remain = i2c_read(0);
i2c_stop();
// Read the 8-bit slope value.
i2c_start();
i2c_write(DS1621_I2C_WRITE_ADDRESS);
i2c_write(DS1621_CMD_READ_SLOPE);
i2c_start();
i2c_write(DS1621_I2C_READ_ADDRESS);
count_per_degree = i2c_read(0);
i2c_stop();
// The following code mostly follows the CalcHiResTemp() function
// shown on page 18 of AN105 from Dallas Semiconductor.
// Here is the link to that appnote:
// http://www.eetasia.com/ARTICLES/2001APR/2001APR09_AMD_AN.PDF
// (Maxim/Dallas doesn't have the appnote on their website).
temp_read >>= 8; // Right-justify the 9-bit value and divide by 2
if(bit_test(temp_read, 7)) // Check if negative number
temp_read -= 256; // If so, convert to two's comp. value
if(count_per_degree != 0)
frac_deg = (float)(count_per_degree - count_remain) /
((float)count_per_degree);
else
frac_deg = .25;
return((float)temp_read - .25 + frac_deg);
} |
|
|
|
h.a.j.molenaar
Joined: 04 May 2005 Posts: 9
|
|
Posted: Tue Jul 12, 2005 7:59 am |
|
|
PCM programmer, thank you for the effort you have done. It was a usefull help to deal with the problem.
Here follows the calculating algoritme with only (long) integers so that the result is 12 bits long. 8 bits for the temperature and 4 bits for the fraction.
This is like how DS1775 represents the temperature and it facilitates to store the temperature in eeprom.
signed long int TempSensorRTC()
{
signed long int temperature;
unsigned int count_remain;
unsigned int count_per_c;
unsigned long int fraction;
temperature = 0;
// Assume to read all the values from the register
// Read MSB of temperature.
// Read 8-bit counter value.
// Read 8-bit slope value
if (count_per_c != 0) // Only if count_per_c is not equal to
{ // zero, remain and count have to be
// taken into the calculation.
fraction = (count_per_c - count_remain);
fraction <<= 8; // Multiply fraction with 256.
fraction /= count_per_c; }
else
{
fraction = 0x0040;
}
temperature = temperature - 0x0040 + fraction;
temperature &= 0xFFF0; // 12 bits precision.
return(temperature);
} |
|
|
|