DS1307 Time stamp and with DS1621 temp log.

Hello, what would be the best method to have two I2C devices working together in one app. and data logging to the same file? I am wanting to use the Arduino together with a DS1621 and a DS1307 (RTC) to data log a temperature reading and attach a time stamp, which I will then send to a MS Excel file and turned into a time stamped graph. I can't seem to get the two I2C code routines to work together? On their own, each seem to work great.
Thank you in anticipation.
Mactitan

There should be no problem using these two devices in the same sketch.

They each have unique addresses - DS1307 (address 0x68) and DS1621 (address 0x48-0x4F).

Both devices should use the same I2C clock and data lines.

Each will need a Wire.beginTransmission(DEV_ADDR), and Wire.endTransmission();

If none of this is news, then you need to give some more detail.

Thank you. This is the type of info I am looking for. I will let you know how I get along from here. (I am still new to the fantastic world of Arduino and I2C.)
Regards
Mactitan.

I am not having too much luck with getting the 2 lots of code to work together in on sketch. The two lots of code from Jon McPhalen are attached as as follows:

// DS1307 demo
// -- by Jon McPhalen (www.jonmcphalen.com) -- based on work by others
// -- 29 DEC 2007

// SDA pin is Analog4
// SCL pin is Analog5

#include <Wire.h>

#define DS1307 0xD0 >> 1 // shift required by Wire.h (silly...)

// DS1307 clock registers

#define R_SECS 0
#define R_MINS 1
#define R_HRS 2
#define R_WKDAY 3
#define R_DATE 4
#define R_MONTH 5
#define R_YEAR 6
#define R_SQW 7

byte second = 0x00; // default to 01 JAN 2007, midnight
byte minute = 0x00;
byte hour = 0x00;
byte wkDay = 0x02;
byte day = 0x01;
byte month = 0x01;
byte year = 0x07;
byte ctrl = 0x00;

void setup()
{
Wire.begin();
Serial.begin(9600);

second = 0x45; // demo time
minute = 0x59;
hour = 0x23;
wkDay = 0x07;
day = 0x29;
month = 0x12;
year = 0x07;
ctrl = 0x00; // disable SQW output
setClock();
}

void loop()
{
getClock();

printHex2(hour);
Serial.print(":");
printHex2(minute);
Serial.print(":");
printHex2(second);

Serial.print(" ");
printDayName(bcd2Dec(wkDay));
Serial.print(" ");

printHex2(day);
Serial.print(" ");
printMonthName(bcd2Dec(month));
Serial.print(" 20");
printHex2(year);
Serial.println();

//no need to rush
delay(1000);
}

void setClock()
{
Wire.beginTransmission(DS1307);
Wire.send(R_SECS);
Wire.send(second);
Wire.send(minute);
Wire.send(hour);
Wire.send(wkDay);
Wire.send(day);
Wire.send(month);
Wire.send(year);
Wire.send(ctrl);
Wire.endTransmission();
}

void getClock()
{
Wire.beginTransmission(DS1307);
Wire.send(R_SECS);
Wire.endTransmission();
Wire.requestFrom(DS1307, 8);
second = Wire.receive();
minute = Wire.receive();
hour = Wire.receive();
wkDay = Wire.receive();
day = Wire.receive();
month = Wire.receive();
year = Wire.receive();
ctrl = Wire.receive();
}

byte bcd2Dec(byte bcdVal)
{
return bcdVal / 16 * 10 + bcdVal % 16;
}

void printHex2(byte hexVal)
{
if (hexVal < 0x10)
Serial.print("0");
Serial.print(hexVal, HEX);
}

void printDec2(byte decVal)
{
if (decVal < 10)
Serial.print("0");
Serial.print(decVal, DEC);
}

void printDayName(byte d)
{
switch (d) {
case 1:
Serial.print("SUN");
break;
case 2:
Serial.print("MON");
break;
case 3:
Serial.print("TUE");
break;
case 4:
Serial.print("WED");
break;
case 5:
Serial.print("THU");
break;
case 6:
Serial.print("FRI");
break;
case 7:
Serial.print("SAT");
break;
default:
Serial.print("???");
}
}

void printMonthName(byte m)
{
switch (m) {
case 1:
Serial.print("JAN");
break;
case 2:
Serial.print("FEB");
break;
case 3:
Serial.print("MAR");
break;
case 4:
Serial.print("APR");
break;
case 5:
Serial.print("MAY");
break;
case 6:
Serial.print("JUN");
break;
case 7:
Serial.print("JUL");
break;
case 8:
Serial.print("AUG");
break;
case 9:
Serial.print("SEP");
break;
case 10:
Serial.print("OCT");
break;
case 11:
Serial.print("NOV");
break;
case 12:
Serial.print("DEC");
break;
default:
Serial.print("???");
}
}


#include <Wire.h>

// DS1621 demo
// -- by Jon McPhalen (www.jonmcphalen.com)
// -- 21 DEC 2007

// SDA pin is Analog4
// SCL pin is Analog5
// DS1621 has A2, A1, and A0 pins connected to GND

// device ID and address

#define DEV_TYPE 0x90 >> 1 // shift required by wire.h
#define DEV_ADDR 0x00 // DS1621 address is 0
#define SLAVE_ID DEV_TYPE | DEV_ADDR

// DS1621 Registers & Commands

#define RD_TEMP 0xAA // read temperature register
#define ACCESS_TH 0xA1 // access high temperature register
#define ACCESS_TL 0xA2 // access low temperature register
#define ACCESS_CFG 0xAC // access configuration register
#define RD_CNTR 0xA8 // read counter register
#define RD_SLOPE 0xA9 // read slope register
#define START_CNV 0xEE // start temperature conversion
#define STOP_CNV 0X22 // stop temperature conversion

// DS1621 configuration bits

#define DONE B10000000 // conversion is done
#define THF B01000000 // high temp flag
#define TLF B00100000 // low temp flag
#define NVB B00010000 // non-volatile memory is busy
#define POL B00000010 // output polarity (1 = high, 0 = low)
#define ONE_SHOT B00000001 // 1 = one conversion; 0 = continuous conversion

void setup()
{
Wire.begin(); // connect I2C
startConversion(false); // stop if presently set to continuous
setConfig(POL | ONE_SHOT); // Tout = active high; 1-shot mode
setThresh(ACCESS_TH, 27); // high temp threshold = 80F
setThresh(ACCESS_TL, 24); // low temp threshold = 75F

Serial.begin(9600);
delay(5);
Serial.println("DS1621 Demo");

int tHthresh = getTemp(ACCESS_TH);
Serial.print("High threshold = ");
Serial.println(tHthresh);

int tLthresh = getTemp(ACCESS_TL);
Serial.print("Low threshold = ");
Serial.println(tLthresh);
}

void loop()
{
int tC, tFrac;

tC = getHrTemp(); // read high-resolution temperature

if (tC < 0) {
tC = -tC; // fix for integer division
Serial.print("-"); // indicate negative
}

tFrac = tC % 100; // extract fractional part
tC /= 100; // extract whole part

Serial.print(tC);
Serial.print(".");
if (tFrac < 10)
Serial.print("0");
Serial.println(tFrac);

delay(500);
}

// Set configuration register

void setConfig(byte cfg)
{
Wire.beginTransmission(SLAVE_ID);
Wire.send(ACCESS_CFG);
Wire.send(cfg);
Wire.endTransmission();
delay(15); // allow EE write time to finish
}

// Read a DS1621 register

byte getReg(byte reg)
{
Wire.beginTransmission(SLAVE_ID);
Wire.send(reg); // set register to read
Wire.endTransmission();
Wire.requestFrom(SLAVE_ID, 1);
byte regVal = Wire.receive();
return regVal;
}

// Sets temperature threshold
// -- whole degrees C only
// -- works only with ACCESS_TL and ACCESS_TH

void setThresh(byte reg, int tC)
{
if (reg == ACCESS_TL || reg == ACCESS_TH) {
Wire.beginTransmission(SLAVE_ID);
Wire.send(reg); // select temperature reg
Wire.send(byte(tC)); // set threshold
Wire.send(0); // clear fractional bit
Wire.endTransmission();
delay(15);
}
}

// Start/Stop DS1621 temperature conversion

void startConversion(boolean start)
{
Wire.beginTransmission(SLAVE_ID);
if (start == true)
Wire.send(START_CNV);
else
Wire.send(STOP_CNV);
Wire.endTransmission();
}

// Reads temperature or threshold
// -- whole degrees C only
// -- works only with RD_TEMP, ACCESS_TL, and ACCESS_TH

int getTemp(byte reg)
{
int tC;

if (reg == RD_TEMP || reg == ACCESS_TL || reg == ACCESS_TH) {
byte tVal = getReg(reg);
if (tVal >= B10000000) { // negative?
tC = 0xFF00 | tVal; // extend sign bits
}
else {
tC = tVal;
}
return tC; // return threshold
}
return 0; // bad reg, return 0
}

// Read high resolution temperature
// -- returns temperature in 1/100ths degrees
// -- DS1620 must be in 1-shot mode

int getHrTemp()
{
startConversion(true); // initiate conversion
byte cfg = 0;
while (cfg < DONE) { // let it finish
cfg = getReg(ACCESS_CFG);
}

int tHR = getTemp(RD_TEMP); // get whole degrees reading
byte cRem = getReg(RD_CNTR); // get counts remaining
byte slope = getReg(RD_SLOPE); // get counts per degree

if (tHR >= 0)
tHR = (tHR * 100 - 25) + ((slope - cRem) * 100 / slope);
else {
tHR = -tHR;
tHR = (25 - tHR * 100) + ((slope - cRem) * 100 / slope);
}
return tHR;
}

I have listed the combined code here which seems to be full of bugs.

// DS1307 and DS1621
// -- based on work by others, which is combined into one here.
// -- 01 Feb 2009

// SDA pin is Analog4
// SCL pin is Analog5

#include <Wire.h>

#define DS1307 0xD0 >> 1 // shift required by Wire.h (silly...)

// DS1621 device ID and address

#define DEV_TYPE 0x90 >> 1 // shift required by wire.h
#define DEV_ADDR 0x00 // DS1621 address is 0
#define SLAVE_ID DEV_TYPE | DEV_ADDR

// DS1621 Registers & Commands

#define RD_TEMP 0xAA // read temperature register
#define ACCESS_TH 0xA1 // access high temperature register
#define ACCESS_TL 0xA2 // access low temperature register
#define ACCESS_CFG 0xAC // access configuration register
#define RD_CNTR 0xA8 // read counter register
#define RD_SLOPE 0xA9 // read slope register
#define START_CNV 0xEE // start temperature conversion
#define STOP_CNV 0X22 // stop temperature conversion

// DS1621 configuration bits

#define DONE B10000000 // conversion is done
#define THF B01000000 // high temp flag
#define TLF B00100000 // low temp flag
#define NVB B00010000 // non-volatile memory is busy
#define POL B00000010 // output polarity (1 = high, 0 = low)
#define ONE_SHOT B00000001 // 1 = one conversion; 0 = continuous conversion

// DS1307 clock registers

#define R_SECS 0
#define R_MINS 1
#define R_HRS 2
#define R_WKDAY 3
#define R_DATE 4
#define R_MONTH 5
#define R_YEAR 6
#define R_SQW 7

byte second = 0x00; // default to 01 JAN 2007, midnight
byte minute = 0x00;
byte hour = 0x00;
byte wkDay = 0x02;
byte day = 0x01;
byte month = 0x01;
byte year = 0x07;
byte ctrl = 0x00;

void setup()
{
Wire.begin();
Serial.begin(9600);

second = 0x45; // demo time
minute = 0x59;
hour = 0x23;
wkDay = 0x07;
day = 0x29;
month = 0x12;
year = 0x07;
ctrl = 0x00; // disable SQW output
setClock();

Wire.begin(); // connect I2C
startConversion(false); // stop if presently set to continuous
setConfig(POL | ONE_SHOT); // Tout = active high; 1-shot mode
setThresh(ACCESS_TH, 27); // high temp threshold = 80F
setThresh(ACCESS_TL, 24); // low temp threshold = 75F

delay(5);
Serial.println("DS1621 Demo");

int tHthresh = getTemp(ACCESS_TH);
Serial.print("High threshold = ");
Serial.println(tHthresh);

int tLthresh = getTemp(ACCESS_TL);
Serial.print("Low threshold = ");
Serial.println(tLthresh);
}

void loop()
{
getClock();

printHex2(hour);
Serial.print(":");
printHex2(minute);
Serial.print(":");
printHex2(second);

Serial.print(" ");
printDayName(bcd2Dec(wkDay));
Serial.print(" ");

printHex2(day);
Serial.print(" ");
printMonthName(bcd2Dec(month));
Serial.print(" 20");
printHex2(year);
Serial.println();

int tc, tfrac;

tc = getHrTemp();

if (tc < 0) {
tc = -tc;
Serial.print("-");
}
tFrac = tC % 100; // extract fractional part
tC /= 100; // extract whole part

Serial.print(tC);
Serial.print(".");
if (tFrac < 10)
Serial.print("0");
Serial.println(tFrac);

delay(1000);
}

void setClock()
{
Wire.beginTransmission(DS1307);
Wire.send(R_SECS);
Wire.send(second);
Wire.send(minute);
Wire.send(hour);
Wire.send(wkDay);
Wire.send(day);
Wire.send(month);
Wire.send(year);
Wire.send(ctrl);
Wire.endTransmission();
}

void getClock()
{
Wire.beginTransmission(DS1307);
Wire.send(R_SECS);
Wire.endTransmission();
Wire.requestFrom(DS1307, 8);
second = Wire.receive();
minute = Wire.receive();
hour = Wire.receive();
wkDay = Wire.receive();
day = Wire.receive();
month = Wire.receive();
year = Wire.receive();
ctrl = Wire.receive();
}

// Set configuration register

void setConfig(byte cfg)
{
Wire.beginTransmission(SLAVE_ID);
Wire.send(ACCESS_CFG);
Wire.send(cfg);
Wire.endTransmission();
delay(15); // allow EE write time to finish
}

// Read a DS1621 register

byte getReg(byte reg)
{
Wire.beginTransmission(SLAVE_ID);
Wire.send(reg); // set register to read
Wire.endTransmission();
Wire.requestFrom(SLAVE_ID, 1);
byte regVal = Wire.receive();
return regVal;
}

// Sets temperature threshold
// -- whole degrees C only
// -- works only with ACCESS_TL and ACCESS_TH

void setThresh(byte reg, int tC)
{
if (reg == ACCESS_TL || reg == ACCESS_TH) {
Wire.beginTransmission(SLAVE_ID);
Wire.send(reg); // select temperature reg
Wire.send(byte(tC)); // set threshold
Wire.send(0); // clear fractional bit
Wire.endTransmission();
delay(15);
}

byte bcd2Dec(byte bcdVal)
{
return bcdVal / 16 * 10 + bcdVal % 16;
}

void printHex2(byte hexVal)
{
if (hexVal < 0x10)
Serial.print("0");
Serial.print(hexVal, HEX);
}

void printDec2(byte decVal)
{
if (decVal < 10)
Serial.print("0");
Serial.print(decVal, DEC);
}

void printDayName(byte d)
{
switch (d) {
case 1:
Serial.print("SUN");
break;
case 2:
Serial.print("MON");
break;
case 3:
Serial.print("TUE");
break;
case 4:
Serial.print("WED");
break;
case 5:
Serial.print("THU");
break;
case 6:
Serial.print("FRI");
break;
case 7:
Serial.print("SAT");
break;
default:
Serial.print("???");
}
}

void printMonthName(byte m)
{
switch (m) {
case 1:
Serial.print("JAN");
break;
case 2:
Serial.print("FEB");
break;
case 3:
Serial.print("MAR");
break;
case 4:
Serial.print("APR");
break;
case 5:
Serial.print("MAY");
break;
case 6:
Serial.print("JUN");
break;
case 7:
Serial.print("JUL");
break;
case 8:
Serial.print("AUG");
break;
case 9:
Serial.print("SEP");
break;
case 10:
Serial.print("OCT");
break;
case 11:
Serial.print("NOV");
break;
case 12:
Serial.print("DEC");
break;
default:
Serial.print("???");
}

// Start/Stop DS1621 temperature conversion

void startConversion(boolean start)
{
Wire.beginTransmission(SLAVE_ID);
if (start == true)
Wire.send(START_CNV);
else
Wire.send(STOP_CNV);
Wire.endTransmission();
}

// Reads temperature or threshold
// -- whole degrees C only
// -- works only with RD_TEMP, ACCESS_TL, and ACCESS_TH

int getTemp(byte reg)
{
int tC;

if (reg == RD_TEMP || reg == ACCESS_TL || reg == ACCESS_TH) {
byte tVal = getReg(reg);
if (tVal >= B10000000) { // negative?
tC = 0xFF00 | tVal; // extend sign bits
}
else {
tC = tVal;
}
return tC; // return threshold
}
return 0; // bad reg, return 0
}

// Read high resolution temperature
// -- returns temperature in 1/100ths degrees
// -- DS1620 must be in 1-shot mode

int getHrTemp()
{
startConversion(true); // initiate conversion
byte cfg = 0;
while (cfg < DONE) { // let it finish
cfg = getReg(ACCESS_CFG);
}

int tHR = getTemp(RD_TEMP); // get whole degrees reading
byte cRem = getReg(RD_CNTR); // get counts remaining
byte slope = getReg(RD_SLOPE); // get counts per degree

if (tHR >= 0)
tHR = (tHR * 100 - 25) + ((slope - cRem) * 100 / slope);
else {
tHR = -tHR;
tHR = (25 - tHR * 100) + ((slope - cRem) * 100 / slope);
}
return tHR;
}

why do you need a shift in the address in

#define DS1307 0xD0 >> 1 // shift required by Wire.h (silly...)

.

I was just searching for wire.h examples because i'm stuck in my project and stubled upon this thread. Oh i think i know, its a 8 bit address, and the wire.h only accepts 7 bit addresses.

am i right?

There is confusion about I2C addresses, partly because they are only 7 bits, partly because of which 7 bits (the high 7) in the byte transmitted to the peripheral, and partly because of the habit of many people to incorrectly call the byte containing the 7 bit address + R/W bit the "address".

Evidently the author that wrote the "silly" comment in the code falls into that category, because the address of the DS1307 is 0x68 (see datasheet). If that address is shifted left 1 bit (where it would show up in the I2C packet), it works out to 0xD0.

Since the Wire library (correctly) expects the actual address when it refers to an address, this left-shifted 0xD0 "address" must be shifted right to get back to the actual address.

Clear as mud?

I've seen datasheets from vendors that made the same mistake in the "address" of an I2C device; it took me a while to talk to one device because of this...

-j