Read out of DS1621

Dear all,

I try to read out the DS1621 temperature senor using the wire library but it doesn´t work. I use the following code:

#include <Wire.h>

byte ReadAdress = 0x9F;
byte WriteAdress = 0x9E;
byte LowTemp, HighTemp;
byte DS_Adress = 0x7;
void setup()
{
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(9600); // start serial for output
SetupDevice();
}

void loop()
{
ReadTemperature();

delay(500);
}

void SetupDevice()
{
Wire.beginTransmission(DS_Adress); // transmit to DS1621 in write mode
Wire.send(WriteAdress);
Wire.send(0xEE); // start conversation
Wire.endTransmission(); // stop transmitting
Serial.print(0xA);
delay(100);
}

void ReadTemperature()
{
Wire.beginTransmission(DS_Adress);
Wire.send(WriteAdress);
Wire.send(0xAA);
Wire.send(ReadAdress);

Wire.endTransmission(); // stop transmitting
int i = 0;

while(Wire.available())
{
if (i == 0) LowTemp = Wire.receive(); // receive a byte as character
else HighTemp = Wire.receive();
Serial.print(0xAA);
}

SendResult();

delay(100);
}

void SendResult()
{
Serial.print(LowTemp);
Serial.print(HighTemp);
}

Can anybody help me or has anybody written a function to read out the DS1621?

Thanks in advance
Lodo2609

If I understand correctly, the DS1621 is not I2C, it's one of many custom "serial" interfaces. Looks like you are trying to use the I2C library to talk to it? I'm not that familiar with Wire.h, so I could be off base.

IIRC, the DS1621 uses a single pin for data in and data out, you you have to change an Arduino pin from output to input to accomplish a full temperature conversion cycle.

Here is a lab assignment for making the DS1621 work with an FPGA. No code, but it does include some waveforms and helpful hints.

I do have working code for a DS1722 (SPI interface) temp sensor, and there are examples available for the DS1821 1-Wire temp sensor.

-j

The DS1621 is I2C. You probably want to set it up for continuous conversion mode -- you don't seem to be doing that in your code. The data sheet shows how. When continuous conversion is used you can read the temperature at any time (though I believe the first conversion takes about one second to complete).

I stand corrected - I never realized it was I2C. Re-reading the datasheet keeping an eye out for clues, things "SDA" SCL", "100kHz", "400kHz", and "slave address" jump out at me now. :slight_smile:

I may have to see if there are any of those still around to play with.

Looks like the 1631 is the 1621's new big brother.

-j

After struggling through understanding the wire.h library (which, IMHO, makes I2C harder than it actually is...), I created this simple program for the DS1621 -- it works. I keep it simple by reading just one byte back; this is the whole degrees (C) value. And as it's on my desk and won't go below zero C I'm not checking to see if the temperature is negative. Again, just an easy demo to get connected to the DS1621.

#include <Wire.h>

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

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

#define DEV_ID 0x90 >> 1 // shift required by wire.h

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

Wire.begin();
Wire.beginTransmission(DEV_ID); // connect to DS1621 (#0)
Wire.send(0xAC); // Access Config
Wire.send(0x02); // set for continuous conversion
Wire.beginTransmission(DEV_ID); // restart
Wire.send(0xEE); // start conversions
Wire.endTransmission();
}

void loop()
{
int tempC = 0;
int tempF = 0;

delay(1000); // give time for measurement
Wire.beginTransmission(DEV_ID);
Wire.send(0xAA); // read temperature
Wire.endTransmission();
Wire.requestFrom(DEV_ID, 1); // request one byte from DS1621
tempC = Wire.receive(); // get whole degrees reading
tempF = tempC * 9 / 5 + 32; // convert to Fahrenheit

Serial.print(tempC);
Serial.print(" / ");
Serial.println(tempF);
}

Thanks, it works.

Lodo2609

I fleshed out my program to enable access to all DS1621 features, including high-resolution temperature measurement (in 1/100ths C). It's too long to post, however, and I can't fins a way to attach it. You may contact me at jon.mcphalen at gmail dot com if you'd like the source.

I'm just learning C, so this one is probably better (it's certainly trimmer than what I had yesterday....):

#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;
}

Is it possible for anyone to explain the difference between DS1620 & DS1621 ?

The DS1620 is a (half-duplex) SPI device; it requires three pins to communicate versus two (using I2C) of the DS1621. I have used both with the SX28 and find the DS1621 a bit easier. Since the Arduino has the 1-Wire library and I've written a full-blown program (see above), I'd suggest using the DS1621. Note that both the DS1620 and DS1621 have the same standard resolution (0.5 C).

The other attractive feature of the I2C version (DS1621) is that you could connect up to eight of them to the Arduino with just two pins; to connect eight DS1620s to the Arduino you'd need five pins and a 74x138 3-to-8 decoder to handle the chip select (called RST) on the DS1620.

Stick with the DS1621.

I've been trying to get my DS1631 to read using the code above and all I get is nonsense -- negative numbers that don't change. Can you give me a clue as to how your hardware is wired? Just SDA and SLC to the DS1631? I don't think the DS1631 vs the DS1621 should matter as I've made that switch before and they're supposed to be pin compatible. In the past I've always also put 5V on the temperature chip before it would work (this was using some desktop computer software that bit-banged the serial port). My DS1631 is jumpered to address 2 (010) and I can't seem to figure out which define makes that happen either). Maybe it's just too many differences, but any help would be greatly appreciated!

I've also be totally unsuccessful compiling this anywhere but in the arduino IDE. I'm new at the microcontroller stuff and would rather it worked at the command line if I can get it to do so. Any clues there? It just fails to include Wiring.h and if I tell it where that is it complains about undefined TwoWire objects.

A quick glance at data sheets (hint, hint) suggests that thought DS1621 and DS1631 are similar devices, they're miles apart as far as interface goes. There seems to be no counter and slop registers in the DS1631, but it does have variable resolution -- up to 12 bits -- which lets you get hi-res temperatures back. You change the resolution via bits in the configuration registers. Also, the Start Conversion command value is different. I'm not surprised that the DS1621 program didn't run at all on a DS1631.

You should download and study the DS1631 data sheet; it gives you all the information you need to adapt the program above

Thanks for the reply!
Well, I have read the data sheets. Not that that does me much good since I'm just not that good at the electronic stuff -- more a programmer, unfortunately.

The slope method is still supported as an undocumented command. I've already used the DS1631 in an application treating it as if it were a DS1621 and it worked fine. I'm just REALLY struggling with getting the microcontroller to do the same thing my PC did.

http://www.maxim-ic.com/appnotes.cfm/an_pk/176

INTRODUCTION
The DS1631 was designed to be reverse-compatible with the DS1621 in most applications, which makes it a simple matter to switch from the DS1621 to the DS1631. This application note describes the differences and similarities between the two parts including DS1631 functions that allow compatibility with the DS1621 but which are not documented in the DS1631 data sheet. All subjects not covered in this application note (e.g., 2-wire communication) are the same for both devices.

Using the DS1631 in DS1621 applications:
Start Convert T command causes the DS1631 to operate in
DS1621 mode.

My original question was, "Can you tell me how you have it wired? "

Gerry

Hmmm.... sorry you're having difficulties, and thanks for sharing the app note regarding compatibility mode (that may come in handy).

My connections are standard, like this:

JM, thanks for your help with this... i seem to be only able to read the same values over and over again:

170 / 338

which don't make sense... especially considering how chilly it is in here!..

even when disconnecting everything from the board, the same values are displayed... i followed your simple schematic in another thread for the ds1621, and everything appears okay... i have all three address pins grounded, pull up resistors on the clock and data pins, +5 on 8 and ground on 4... any ideas to help a newbie?..

i've tried two different chips and am seeing the same results...

however, after typing all of that, i now have noticed that both chips have a "+" sign on the 2 pin... could it be that i have some odd chip? here are the markings:

DS1621
072484 (or 0724B4)
065AG

thanks again for your help,
isaac

Those are the same numbers I got the first time I tried it! :-?
Then I changed it a little and got some negative number that never changed.

What a relief that someone else is at the same place. I was pretty frustrated.

I've sorta put it aside to work on PWM and servos (I have had much success there). Now I have to get back to the temperature stuff.

Please post if you manage to figure out why you got those numbers and what you did to solve it.

i finally spent a few minutes going through the atmega168 document (available from their site)... my problem was very simple - i was using the wrong pins... i was using 4 and 5, rather than the analog 4 and 5... i had assumed that the analog inputs could only do that - read... it seems that i have a LOT more to learn about this stuff!...

i was also baffled by how JMs code doesn't mention the pins (outside of comments)... a glance at the wiring library reveals this:

#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__)
    // activate internal pull-ups for twi
    // as per note from atmega8 manual pg167
    sbi(PORTC, 4);
    sbi(PORTC, 5);
  #else

so, is it correct to state that all pins can be utilized for digital read/write, but the PORTC (analog input) pins are the only pins available with ADC?...

also, i discovered that the library code seems to utilize internal pull-up resistors, which eliminates the external 4.7K resistors...

and a last question - does the IDE allow the user to set preprocessor directives outside of code?... i'm accustomed to having that available to me for different build types... but here it seems that the value may be set somewhere else?...

thanks,
isaac

Many of the ATmega pins have multiple functions; the assumption is that you will not need all of those functions at the same time, but the device is flexible so that you can use it to meet the needs of various designs. This is good for the design engineer, as it means one can learn a single device but use it in many applications (instead of learning a new device for each application); this also makes it useful for us to play with, as it can do lots of different stuff, depending on what we're interested in at the moment.

Yes, the I2C pins are also analog inputs and can be used as standard digital I/Os, depending on your needs. The UART and SPI pins are the same way (well, they're not ADC inputs) and the PWM outputs are also used as standard digital I/Os. If you run off the internal RC oscillator, you can configure the crystal pins as digital I/Os. If you really want to you can even configure the RESET pin as a digital I/O, but that's a one-shot deal as you can never program the ATmega again after setting that fuse.

If you take a look at the pin mapping you'll see multiple notations by each pin. For example, pin 28 has the label PC5 (ADC5/SCL/PCINT13). So, it's pin 5 of PORTC, it's ADC input #5, it's the SCL line for I2C, or it's PCINT13 (I don't know what that one means, but INT makes me think interrupt). There's an incredible amount of information packed onto that little diagram.

-j

thanks kg, it's responses from seasoned people like you and JM that keep newcomers like me coming back!... though, i can't claim that i understand all that you were talking about :D...

but about the bit shift that JM says is required... i can't understand why it's required and want to make sure that my bit math is correct here...

0x90 = 10010000
0x90 >> 1 = 01001000

but because the ds621 address only depends on the 3 least significant bits, the address is still "0"?... if i shift by 2:

0x90 >> 2 = 00100100

the address would actually be "4"?... if my bit shifting is correct, then i guess the source of my confusion is why the shift is required and how would a complete newbie know that it's indeed required?... i tried using an integer address, but only to find that the ds1621 doesn't recognize it...

thanks,
isaac

okay, now i'm more confused concerning the bit shift... according to the ds1621 spec, the first four bits should be 1001 for R/W operations... the next three bits are the address, and the last is a 1 for read, 0 for write... so (again):

0x90 = 10010000
0x90 >> 1 = 01001000

by the 3 address bits according to the spec, the address should be "100"?... and how would the device even know the operation type if the shift results in 0100?... if this is the case, i don't understand how the TWI library knows that the first four bits have any specific value for the device, especially considering that the value is defined well before anything is actually executed...

this emoticon is the closest expression i'm feeling: :-? though, this one comes in a close second: :cry:

thanks a bunch, again,
isaac