This tutorial focuses on the Dallas 1624 Digital Thermometer and EEPROM. The DS1624 provides a direct 13 bit reading (0.03125 degrees C) and also includes a 256 byte EEPROM. Among other applications, the DS1624 might be a part of a data logger where some 120 temperatures are stored over time and the user transports the data from the remote data logger by simply recovering this device and reading it to a PC for analysis.
This device uses the two wire inter IC protocol (IIC or I2C) developed by Philips and it is hoped that this tutorial will also aid you in interfacing with such other I2C devices as;
Dallas DS1803 Dual Potentiometer Microchip 24LC65 8K X 8 EEPROM Philips PCF8574 8-bit I/O Philips PCF8591 4-channel A/D and 1-channel D/AThese devices are powerful and yet inexpensive ($3.00 to $5.00). Many devices can be placed on the same 2-wire bus and with only two leads plus power and ground, breadboarding could't be simpler.
Hopefully, this opens up many avenues for you and saves you a bit of money. For example, Parallax offers a Stamp stretcher for a sizeable chunk of change. You can do the same thing with a pair of PCF8574s for $3.00 each. I just purchased a $30.00 RAM Pack from Solutions Cubed to examine. You can do the job better and simpler with a $3.00 24LC65 8K byte EEPROM.
The tutorial begins with a discussion of the I2C bus protocol and illustrates the implementation of the low level I2C routines which may be used with any I2C device.
The low level routines are then put together into command sequences.
Finally, the command structure specific to the DS1624 is discussed. Note that a data sheet for the DS1624 in PDF format is available at http://www.dalsemi.com.
The I2C Bus - Low Level Routines.
See Figure #1.
The processor, in this case, the Stamp is referred to as the "master" and the devices on the 2-wire bus as the "slaves".
Two leads are used; SCL (serial clock) and SDA (serial data).
The logic states exerted on the bus are a logic zero (near ground) and an open (high impedance). Thus, four low level subroutines;
LO_SDA: SDA_OUT=0 SDA_DIR=OUT RETURN LO_SCL: SCL_OUT=0 SCL_DIR=OUT RETURN HI_SDA: SDA_DIR=IN RETURN HI_SCL: SCL_DIR=IN RETURNNote that the high impedance logic one is achieved by making the lead an input. The external pullup resistor provides the slave devices with +5V through a high impedance.
A data interchange is initiated with a "start" sequence which is defined as bringing SDA low while SCL is high. The interchange is terminated with a "stop" sequence which is bringing SDA high while SCL is high. Thus two subroutines;
START: GOSUB LO_SCL ' Line 1 - see text GOSUB HI_SDA ' Line 2 - see text GOSUB HI_SCL ' Line 3 - see text GOSUB LO_SDA ' SDA transition to low when SCL high GOSUB LO_SCL RETURNNote the "start" is the transition of SDA from high to low while SCL is high . Thus, in line 2, SDA is brought high. However, bringing SDA high while SCL is high is defined as a "stop". Thus, in line 1, SCL is set to zero prior to bringing SDA high.
SSTOP: GOSUB LO_SCL GOSUB LO_SDA 'be sure SDA is in low state GOSUB HI_SCL GOSUB HI_SDA 'SDA transition to high when SCL is high RETURNHere again, the actual "stop" is the transition of SDA from low to high while SCL is high. Note that in SSTOP, both SDA and SCL are left high which is defined as a "bus idle" condition.
Data is sent by the master as bytes. Each bit is sent by bringing SDA to the appropriate state with SCL low and then momentarily bringing SCL high, beginning with the most significant bit. Thus, two additional subroutines, CLK and OUT_BYTE;
CLK: ' brings SCL momentarily high GOSUB HI_SCL GOSUB LO_SCL RETURN OUT_BYTE: ' sends O_BYTE to slave, most sig bit first FOR N=7 to 0 BRANCH (O_BYTE>>N)&$01, [OUT_0, OUT_1] ' set SDA to the appropriate state and CLK OUT_0: GOSUB LO_SDA 'DEBUG "0" GOTO OUT_BYTE_1 OUT_1: GOSUB HI_SDA 'DEBUG "1" GOTO OUT_BYTE_1 OUT_BYTE_1: GOSUB CLK GOSUB HI_SDA NEXT 'DEBUG CR RETURNAfter the master sends a byte, the master sends an additional clock to allow the slave to acknowledge the byte. Thus, subroutine NACK;
NACK: GOSUB HI_SDA GOSUB CLK RETURNData is received from the slave in bytes. The master brings the SCL lead high and reads the data bit and then brings the SCL lead low. This is repeated for each of the eight bits, beginning with the most significant bit. Thus, subroutine IN_BYTE;
IN_BYTE: ' return result in I_BYTE GOSUB HI_SDA I_BYTE=0 FOR N=0 TO 7 GOSUB HI_SCL I_BYTE= (I_BYTE<<1) | SDA_IN DEBUG DEC SDA_IN GOSUB LO_SCL NEXT DEBUG CR RETURNAfter receipt of the byte, the master is expected to acknowledge by bringing SDA low and sending a clock pulse.
ACK: GOSUB LO_SDA GOSUB CLK GOSUB HI_SDA RETURNNote that these low level subroutines may be used for all I2C devices.
I2C - Command Structure.
First, a START command is issued. This calls all devices on the I2C bus to attention.
This is followed by an address byte which consists of the manufacturer's assigned "group code" (4-bits), the specific three bit address assigned by the user using the A2, A1 and A0 terminals on the device and whether the operation that follows is a Read or a Write (one bit).
For example, the manufacturer's assigned group code for the DS1624 is 1001. Assume the user has strapped the A2, A1 and A0 terminals at 010, respectively. Assume a command is to be written to the DS1624; that is, R/W bit is logic zero.
Thus, the address byte is;
device a2 a1 a0 R/W code 1001 0 1 0 0 ' $94On receipt of this, all slave devices on the bus other than the addressed are inactive. All subsequent data, until another START command, is assumed to be for the addressed device.
[This all reminds me of the Army style of instruction. The drill sergeant asks the question which gets everyone's attention, much like the START command. All the students panic. I doubt the I2C devices do, but you get the point.
After a torturing pause, the sergeant then looks at his roll sheet and calls on Lt Anderson, much like the address byte. Everyone else breathes a sigh of relief as for the next few minutes the dialog is with Anderson and they can go back to sleep.]
This is followed by a NACK to permit the addressed device to acknowledge receipt of the byte.
This is than followed by sending various commands to the addressed device with a NACK clock pulse being sent after each byte to permit the device to acknowledge.
The session closes with the STOP command.
CONFIG: GOSUB START O_BYTE=$94 ' the address byte %1001 0 1 0 0 ' device a2 a1 a0 R/W GOSUB OUT_BYTE GOSUB NACK O_BYTE=$AC ' Access Config GOSUB OUT_BYTE GOSUB NACK O_BYTE=$01 '1 SHOT mode GOSUB OUT_BYTE GOSUB NACK GOSUB SSTOP PAUSE 30 ' wait for EEPROM to program RETURNNote that the sequence is initiated with the start sequence, followed by the address of the desired device with the "write" bit set to a zero, followed by a NACK. The remainder of the dialog is specific to the DS1624. The $AC command indicates to the DS1624 that it is to program its internal configuration byte and the $01 is the value to write to the configuration byte. The $01 places the DS1624 in a single shot mode. (More on this appears below).
The configuration byte on the DS1624 might be read as follows;
READ_CONFIG: GOSUB START O_BYTE=$95 ' the address byte %1001 0 1 0 1 ' device a2 a1 a0 R/W GOSUB OUT_BYTE ' code GOSUB NACK GOSUB IN_BYTE ' fetch the byte from the addressed DS1624 GOSUB ACK GOSUB SSTOP RETURNDS1624 Temperature Commands.
Access Config [$AC] - The temperature aspect of the DS1624 includes a configuration byte which defines how the device is to operate. This is limited to one option; 1SHOT. When at zero, the device continually performs a temperature conversion. When at one, a conversion is only initiated in response to a Start Conversion Command.
Note that the idle standby current for the DS1624 is less than 3 uA. The current required when performing a temperature conversion is 1000 uA. In the following program, I opted for the 1SHOT mode to save a battery that would probably power the unit in a data logging application. The down side of the 1SHOT mode is that each time a measurement is required, the "Start Conversion" Command must be issued and the program must pause for 1000 ms to allow the temperature conversion to take place.
Note that the $AC command may be used in the context of a write where the configuration data is sent or in a read where the current content of the configuration byte is read as noted in the example above.
Stop Temperature Conversion [$22]. This is a write only command which is really only applicable to the continuous conversion mode. Conversion halts until the Start Conversion command is issued.
Start Temperature Conversion [$EE]. Write only command. If the DS1624 is configured in the 1SHOT mode, this causes a single temperature conversion to be made. If the device is in the continuous mode and the conversion was stopped, this command again causes a continuous conversion.
Read Temperature [$AA]. Causes the DS1624 to send the results of the most recent temperature conversion.
This can be confusing as the $AA command is actually written to the device. Another "start" sequence is initiated with the address byte set to read. Note there is no intermediate "stop" sequence.
MEAS: GOSUB START O_BYTE=$94 ' Note that this is a write (R/W bit = 0) GOSUB OUT_BYTE GOSUB NACK O_BYTE=$AA ' Fetch Temperature GOSUB OUT_BYTE GOSUB NACK GOSUB START ' Note there is no intermediate SSTOP O_BYTE=$91 GOSUB OUT_BYTE GOSUB NACK GOSUB IN_BYTE ' two bytes GOSUB ACK T.BYTE1 = I_BYTE ' whole part in high byte GOSUB IN_BYTE GOSUB ACK T.BYTE0 = I_BYTE ' fractional part in low byte GOSUB SSTOP RETURNAn analogy with the Army instruction is offered. The sergeant calls everyone to attention and then calls on Lt Anderson, in the "write" mode. "When I again address you, I want the full 16 digit serial number of your weapon". He again calls everyone to attention, addresses Lt Anderson in the "read" mode.
That second call of everyone to attention seems a bit odd, but that's the way it works.
Note that the temperature is sent as two bytes. This is discussed in greater detail below.
DS1624 EEPROM Commands.
Note that the EEPROM is entirely separate from the temperature measurement. That is, it may be used for the general storage of calibration constants associated with another entirely separate device associated with the Basic Stamp. The obvious application is to log temperature data.
Access Memory [$17].
This is best shown with examples.
EE_WRITE: GOSUB START O_BYTE=$94 GOSUB OUT_BYTE GOSUB NACK O_BYTE=$17 'Access Memory GOSUB OUT_BYTE GOSUB NACK O_BYTE=ADR GOSUB OUT_BYTE GOSUB NACK O_BYTE=DAT GOSUB OUT_BYTE GOSUB NACK GOSUB SSTOP PAUSE 50 ' wait for EEPROM to program RETURNIn the above, the device is addressed in the write mode. The $17 command is sent, followed by the 8-bit address of where to store the data, followed by the data to be stored.
EE_READ: GOSUB START O_BYTE=$94 ' write GOSUB OUT_BYTE GOSUB NACK O_BYTE=$17 ' access memory GOSUB OUT_BYTE GOSUB NACK O_BYTE=ADR ' address GOSUB OUT_BYTE GOSUB NACK GOSUB START ' no intermediate STOP O_BYTE=$95 ' read GOSUB OUT_BYTE GOSUB NACK GOSUB IN_BYTE DAT = I_BYTE GOSUB SSTOP RETURNIn reading a byte, the device is addressed as a write followed by the $17 command followed by the address to be read. Another "start" sequence is initiated, with no intermediate "stop". The device is again addressed, but now as a read, and the data is then read by the Stamp.
This program configures the DS1624 for 1SHOT operation. It then performs ten temperature measurements and writes the high byte of the results to sequential locations in EEPROM. It then reads back these values and displays them on the terminal using the DEBUG command.
' DS1624.BS2 ' ' Performs 10 temperature measurements. High bytes are written to ' the first 10 locations in EEPROM. The data is then read from ' EEPROM and displayed using the DEBUG command. ' ' H. Paul Roach, Dec, '97 OUT CON 1 IN CON 0 SDA_OUT VAR OUT8 SCL_OUT VAR OUT9 SDA_IN VAR IN8 SDA_DIR VAR DIR8 SCL_DIR VAR DIR9 T VAR WORD ADR VAR BYTE DAT VAR BYTE O_BYTE VAR BYTE I_BYTE VAR BYTE N VAR BYTE MAIN: DIRS=$0000 ' start with DIR8 and DIR9 as inputs GOSUB CONFIG ' configure DS1624 for 1SHOT operation FOR ADR=0 TO 9 ' make ten measurements GOSUB INIT ' initiate a conversion GOSUB MEAS ' fetch the result DEBUG ?T.BYTE1 DEBUG ?T.BYTE0 DAT = T.BYTE1 GOSUB EE_WRITE ' save high byte to the DS1624 EEPROM PAUSE 1000 NEXT FOR ADR=0 TO 9 ' now fetch each from EEPROM and display GOSUB EE_READ DAT=I_BYTE DEBUG ?DAT NEXT DONE: GOTO DONE CONFIG: ' configures DS1624 in 1SHOT temperature conversion mode GOSUB START O_BYTE=$94 GOSUB OUT_BYTE GOSUB NACK O_BYTE=$AC 'Access Config GOSUB OUT_BYTE GOSUB NACK O_BYTE=$01 '1 SHOT mode GOSUB OUT_BYTE GOSUB NACK GOSUB SSTOP PAUSE 30 ' wait for EEPROM to program RETURN INIT: ' causes DS1624 to initiate a conversion GOSUB START O_BYTE=$94 ' write GOSUB OUT_BYTE GOSUB NACK O_BYTE=$EE ' Start Conversion GOSUB OUT_BYTE GOSUB NACK GOSUB SSTOP PAUSE 1000 ' wait 1000 ms for conversion to complete RETURN MEAS: ' fetches temperature result. Value returned in T_HI and T_LO GOSUB START O_BYTE=$94 ' write GOSUB OUT_BYTE GOSUB NACK O_BYTE=$AA ' Fetch Temperature GOSUB OUT_BYTE GOSUB NACK GOSUB START ' read O_BYTE=$95 GOSUB OUT_BYTE GOSUB NACK GOSUB IN_BYTE ' fetch the two byte reading GOSUB ACK ' acknowledge each byte T.BYTE1 = I_BYTE ' high byte GOSUB IN_BYTE GOSUB ACK T.BYTE0 = I_BYTE GOSUB SSTOP RETURN EE_READ: ' fetches content location ADR in DS1624 EEPROM ' result returned in DAT GOSUB START O_BYTE=$94 ' write GOSUB OUT_BYTE GOSUB NACK O_BYTE=$17 ' access EEPROM GOSUB OUT_BYTE GOSUB NACK O_BYTE=ADR ' specify address to read DEBUG ?ADR GOSUB OUT_BYTE GOSUB NACK GOSUB START ' now read O_BYTE=$95 GOSUB OUT_BYTE GOSUB NACK GOSUB IN_BYTE DAT = I_BYTE GOSUB SSTOP RETURN EE_WRITE: ' writes content of DAT to specified address ADR GOSUB START O_BYTE=$94 ' write GOSUB OUT_BYTE GOSUB NACK O_BYTE=$17 ' Access Memory GOSUB OUT_BYTE GOSUB NACK O_BYTE=ADR ' address 'DEBUG ?ADR GOSUB OUT_BYTE GOSUB NACK O_BYTE=DAT ' data to write 'DEBUG HEX2 ?DAT GOSUB OUT_BYTE GOSUB NACK GOSUB SSTOP PAUSE 15 ' wait for EEPROM to program RETURN OUT_BYTE: ' sends content of O_BYTE, most sig byte first FOR N=7 to 0 BRANCH (O_BYTE>>N)&$01, [OUT_0, OUT_1] OUT_0: GOSUB LO_SDA 'DEBUG "0" GOTO OUT_BYTE_1 OUT_1: GOSUB HI_SDA 'DEBUG "1" GOTO OUT_BYTE_1 OUT_BYTE_1: GOSUB CLK GOSUB HI_SDA NEXT 'DEBUG CR RETURN IN_BYTE: ' receives a byte, most sig byte first. ' result returned in I_BYTE GOSUB HI_SDA I_BYTE=0 FOR N=0 TO 7 GOSUB HI_SCL I_BYTE= (I_BYTE<<1) | SDA_IN DEBUG DEC SDA_IN GOSUB LO_SCL NEXT DEBUG CR RETURN NACK: ' clock pulse while SDA in high impdeance to allow ' slave to acknowledge by bringing SDA low GOSUB HI_SDA GOSUB CLK RETURN ACK: ' clock pulse while SDA low to acknowledge receipt of ' a byte from the slave GOSUB LO_SDA GOSUB CLK GOSUB HI_SDA RETURN CLK: ' momentarily bring SCL high GOSUB HI_SCL GOSUB LO_SCL RETURN START: ' bring SDA from high to low while SCL is high GOSUB LO_SCL GOSUB HI_SDA GOSUB HI_SCL GOSUB LO_SDA 'SDA transition to low when SCL high GOSUB LO_SCL RETURN SSTOP: ' bring SDA from low to high while SCL is high GOSUB LO_SCL GOSUB LO_SDA 'be sure SDA is in low state GOSUB HI_SCL GOSUB HI_SDA 'SDA transition to high when SCL is high RETURN 'both SDA and SCL left in high-Z LO_SDA: SDA_OUT=0 SDA_DIR=OUT RETURN LO_SCL: SCL_OUT=0 SCL_DIR=OUT RETURN HI_SDA: SDA_DIR=IN RETURN HI_SCL: SCL_DIR=IN RETURNDiscussion.
This routine simply brings together all of the subroutines which were previously discussed and I am hopeful it is straight forward.
Format of Temperature Data.
The temperature data is returned as two bytes. The first byte, T.BYTE1 contains the whole part in degrees C. The highest five bits of the second byte, T.BYTE0 consists of the fractional part. This is the number of 0.03125 degrees C.
For example, consider;
0001 1001 0001 0000 whole part fract part in upper 5 bits = 16 + 8 + 1 = 2 * 0.03125Thus the temperature is 25.0625 or 25.06.
Thus the fractional portion may be calculated;
T_FRACT_100 = ((T.BYTE0 >> 3) * 312) / 10Thus, the temperature could be then displayed as;
DEBUG DEC T.BYTE1, ".", DEC T_FRACT_100, CRNote that the most significant bit of T.BYTE1, is a sign bit; 0 indicates positive and 1 indicates negative. Thus, if negative, the two's compliment of the result must be taken.
1110 0110 1100 1000 Ones Comp 0001 1001 0011 0111 Twos Comp 0001 1001 0011 1000Thus the whole part is 16+8+1 or 25. The fractional part is 0.03125 * (4+2+1) or 0.22 degrees C. Thus, the result is -25.22 degrees C.
This may be implemented;
IF (T.BIT15 <> 0) THEN MINUS T_FRACT_100 = ((T.BYTE0 >> 3) * 312) / 10 DEBUG DEC T.BYTE1, ".", DEC T_FRACT_100, CR GOTO CONTINUE MINUS: T = ~T + 1 ' perform two's complement T_FRACT_100 = ((T.BYTE0 >> 3) * 312) / 10 DEBUG "-", DEC T.BYTE1, ".", DEC T_FRACT_100, CR GOTO CONTINUE CONTINUE:Summary.
This tutorial has presented the I2C bus. The same low level routines may be used with numerous other interesting and inexpensive devices. Many are discussed on my Web page.
The tutorial specifically discussed the DS1624 which may be used as both a temperature measurement device and a general purpose EEPROM for saving constants or for logging data.