Interfacing with a Dallas DS1624 Thermometer
/* Program DS1624_1.C
**
** Illustrates an interface with a Dallas DS1624 Thermometer and EEPROM.
** This device is controled using the Philips I2C protocol.
**
** Continually performs temperature measurement and displays
** using the full 13 bit result.
**
** The fractional part of the temperature is in the high five bits of the
** second byte fecthed from the DS1624. Thus, 10101000 would be nominally
** 500/1000 + 125/1000 + 31/1000.
**
** Flashlite DS1624
**
** P2.1 ------------------> SCL
** P2.0 <-----------------> SDA
**
** Note that the local address (A2, A1 A0) is strapped for 0.
**
** Note that this implementation does not deal with temperatures less
** than 0.
**
** copyright Peter H. Anderson and Onya Barnes, Baltimore, MD, Sept, '00
*/
#include <stdio.h>
#include <dos.h>
#define SEG 0xf000
#define P2_OFFSET 0xff10
#define PM2_OFFSET 0xff11
#define PMC2_OFFSET 0xff12
typedef unsigned char byte;
/* function in program */
int ds1624_compute_fraction(byte t_fract);
void ds1624_config(byte dev_adr, byte mode);
void ds1624_init(byte dev_adr);
void ds1624_meas_temp(byte dev_adr, byte *p_whole, byte *p_fract);
/* common i2c routines */
byte i2c_in_byte(void);
void i2c_out_byte(byte o_byte);
void i2c_nack(void);
void i2c_ack(void);
void i2c_start(void);
void i2c_stop(void);
void i2c_high_sda(void);
void i2c_low_sda(void);
void i2c_high_scl(void);
void i2c_low_scl(void);
/* note global */
byte far *p2;
byte far *pm2;
byte far *pmc2;
byte dirs2, outs2;
void main(void)
{
byte t_whole, t_fract;
int fract;
p2=MK_FP(SEG, P2_OFFSET);
pm2=MK_FP(SEG, PM2_OFFSET);
pmc2=MK_FP(SEG, PMC2_OFFSET);
dirs2=0xff; /* make all of P2 inputs */
*pmc2=0x00;
*pm2=dirs2;
ds1624_config(0x00,0x01); /* dev adr is 0x00, mode is 0x01 - 1 shot */
while(1)
{
ds1624_init(0x00);
/* note that pointers are passed */
ds1624_meas_temp(0x00, &t_whole, &t_fract);
fract = ds1624_compute_fraction(t_fract)/10;
/*convert to decimal format*/
printf("%d.%d\n", t_whole, fract);
delay(1000);
}
}
int ds1624_compute_fraction(byte t_fract)
/* converts high five bits in t_fract to a number in the range of
** 0 - 1000.
*/
{
int sum = 0;
byte y, n;
const int dec_vals[5] = {31, 62, 125, 250, 500};
/* 31.25 / 1000, 62.5/1000, 125/1000, etc*/
y = t_fract >> 3; /* fractional part is now in lowest five bits*/
for (n=0; n<5; n++)
{
if (y&0x01)
{
sum = sum + dec_vals[n];
}
y = y >> 1;
}
return(sum);
}
void ds1624_config(byte dev_adr, byte mode)
/* configures DS1624 in specified mode */
{
i2c_start();
i2c_out_byte(0x90 | (dev_adr << 1));
i2c_nack();
i2c_out_byte(0xac); /* access configuration */
i2c_nack();
i2c_out_byte(mode);
i2c_nack();
i2c_stop();
delay(25); /* wait for EEPROM to program */
}
void ds1624_init(byte dev_adr)
{
i2c_start();
i2c_out_byte(0x90 | (dev_adr << 1));
i2c_nack();
i2c_out_byte(0xee); /*start conversion*/
i2c_nack();
i2c_stop();
delay(1000);
}
void ds1624_meas_temp(byte dev_adr, byte *p_whole, byte *p_fract)
/* fetches temperature result. Values t_whole and t_fract returned using
** pointers
*/
{
i2c_start();
i2c_out_byte(0x90 | (dev_adr << 1));
i2c_nack();
i2c_out_byte(0xaa); /* fetch temperature */
i2c_nack();
i2c_start(); /* no intermediate stop */
i2c_out_byte(0x90 | (dev_adr << 1) | 0x01);
i2c_nack();
*p_whole=i2c_in_byte(); /* value pointed to by p_whole */
i2c_ack();
*p_fract=i2c_in_byte();
i2c_stop();
}
/* Common I2C Routines*/
byte i2c_in_byte(void)
{
byte i_byte=0, n;
i2c_high_sda();
for (n=0; n<8; n++)
{
i2c_high_scl();
if (*(p2) & 0x01)
{
i_byte = (i_byte << 1) | 0x01; /* msbit first */
}
else
{
i_byte = i_byte << 1;
}
i2c_low_scl();
}
return(i_byte);
}
void i2c_out_byte(byte o_byte)
{
byte n;
for(n=0; n<8; n++)
{
if(o_byte&0x80)
{
i2c_high_sda();
}
else
{
i2c_low_sda();
}
i2c_high_scl();
i2c_low_scl();
o_byte = o_byte << 1;
}
i2c_high_sda();
}
void i2c_nack(void)
{
i2c_high_sda(); /*data at one*/
i2c_high_scl(); /*clock pulse*/
i2c_low_scl();
}
void i2c_ack(void)
{
i2c_low_sda(); /*bring data low and clock*/
i2c_high_scl();
i2c_low_scl();
i2c_high_sda();
}
void i2c_start(void)
{
i2c_low_scl();
i2c_high_sda();
i2c_high_scl(); /* bring SDA low while SCL is high*/
i2c_low_sda();
i2c_low_scl();
}
void i2c_stop(void)
{
i2c_low_scl();
i2c_low_sda();
i2c_high_scl();
i2c_high_sda(); /*bring SDA high while SCL is high*/
/*idle is SDA high and SCL high*/
}
void i2c_high_sda(void)
{
dirs2 = dirs2 | 0x01;
*pm2 = dirs2;
#ifdef D /* used for debugging */
printf("SDA_HIGH %x\n", dirs2);
delay(500);
#endif
}
void i2c_low_sda(void)
{
outs2 = outs2 & (~0x01); /* zero the output pin */
*p2 = outs2;
dirs2 = dirs2 & (~0x01); /* and output */
*pm2 = dirs2;
#ifdef D
printf("SDA_LOW %x\n", dirs2);
delay(500);
#endif
}
void i2c_high_scl(void)
{
dirs2 = dirs2 | 0x02; /* bring SCL to high impedance */
*pm2 = dirs2;
#ifdef D
printf("SCL_HIGH %x\n", dirs2);
delay(500);
#endif
}
void i2c_low_scl(void)
{
outs2 = outs2 & (~0x02);
*p2 = outs2; /* zero the output pin */
dirs2 = dirs2 & (~0x02); /* and output */
*pm2 = dirs2;
#ifdef D
printf("SCL_LOW %x\n", dirs2);
delay(500);
#endif
}