Introduction
This discussion focuses on the Dallas Semiconductor DS1621 digital thermometer and thermostat.
A detailed data sheet in .PDF format is available from Dallas
Semiconductor
The interface is the 2-wire Philips I2C protocol and the reader is referred to a separate discussion of such low level I2C routines as HIGH_SDA, LOW_SDA, HIGH_SCL, LOW_SCL, START, STOP, CLOCK_PULSE, OUT_BYTE and IN_BYTE.
This discussion begins with program DS1621_1.ASM which shows how to perform measurements to one degree C resolution. DS1621_2.ASM expands this to include setting high and low thermostat trip points and determining when the temperature is outside these limits. A third routine expands on this to show how to make measurments with 0.5 degrees C resolution and to display the result on a serial LCD or similar device.
Note that although this discussion focuses on a single DS1621 displaying temperature on an LCD, it can be used as the foundation for a system using multiple devices and logging the temperature data to serial EEPROM using the same I2C 2-wire pair and sharing much of the code.
The manufacturer's assigned group address for this device is 1001 which is the same as many A/D converters. In these programs we strapped the A2, A1, A0 leads at ground, ground, and +5V, respectively. Thus the address byte sent at the beginning of each exchange is;
START 1001 001 R/W
Where R/W is a zero if writing to the device and a logic one if reading.
Program DS1621_1.ASM.
This program makes continuous temperature measurements at 30 second intervals. The eight bit natural binary result is stored in variable T_C. Nothing is done with each temperature reading result in this program. However, the program could be modified to either display each temperature reading or write each reading to serial EEPROM.
Routine CONFIG_1621 writes a value to the internal configuration / status register in the DS1621. Of particular note in this application, bit 0 is set to a logic one so as to operate in a single shot mode. That is, the device performs only a single measurment when directed to begin conversion. The advantage of this mode is power saving. For example, a temperature logger sitting in a refrigeration truck might make but a single measurement every ten minutes. Thus, the 1621 need not be performing thousands of readings and unnecessarily dissipating power over the entire 10 minutes, when in fact, only one reading is required.
The CONFIG_1621 routine consists of the START command followed by sending the ACH command , followed by a NACK followed by the data to be written to the configuration register, followed by a NACK. The sequence is terminated with the STOP command.
A 15 msec delay is provided to assure the data is written to the DS1621's internal EEPROM.
Each measurement sequence then consists of commanding the DS1621 to begin the conversion, which is implemented in routine BEGIN_CNVT. A measurement is then performed; subroutine MEASURE. Finally, the device is commanded to stop the conversion process so as to again place the device in the low power mode.
Routine BEGIN_CNVT consists of sending the EEH command followed by a short delay to allow the device to make one measurment. Routine STOP_CNVT consists of simply sending the 22H command.
Routine MEASURE consists of sending the START, the address byte (with the R/W bit = 0) followed by AAH command. Then without a STOP command, another START command followed by the the address byte with the R/W bit set to 1, followed by a NACK, followed by reading one byte from the DS1621.
Note that in this program, only one byte is received from the device.
In fact, the temperature reading consists of nine bits. This is sent as two bytes with the first byte being the most significant 8-bits. In the second byte, only the most significant bit is of value.
For example, assume the two bytes are;
0011 0111 1000 0000 or 37 80 Hex
The first byte is interpetted as 37H degrees C and the most significant bit of the second byte is interpretted as the half degree.
Thus, this would be interpetted as 37H or 55 degrees C plus 0.5 or 55.5 degrees C. As noted, the receipt of the second byte is not implemented in this routine. However, it is implemented in program DS1621_3.ASM
; DS1621_1.ASM ; ; Illustrates control of DS1621 Digital Thermometer. Continually makes ; temperature measurments which are stored in variable T_C. These ; measurments might be displayed on a serial LCD or similar or stored in ; in an I2C EEPROM such as the Microchip 24LC65. ; ; PIC16C84 DS1621 ; ; RB7 (term 13) ------------------- SCL (term 2) ----- To Other ; RB6 (term 12) ------------------- SDA (term 1) ----- I2C Devices ; ; Note that the slave address is determined by A2 (term 5), A1 ; (term 6) and A0 (term 7) on the DS1621. The above SCL and SDA leads ; may be multipled to eight group "1001" devices, each strapped for a ; unique A2 A1 A0 setting. ; ; 10K pullup resistors to +5VDC are required on both signal leads. ; ; copyright, Nicole Ambrose and H. Paul Roach, MSU, July 3, '97 LIST p=16c84 #include <c:\mplab\p16c84.inc> __CONFIG 11h CONSTANT SDA=6 CONSTANT SCL=7 CONSTANT VARS=0CH ; starting point for variables T_C EQU VARS+0 DEV_ADR EQU VARS+1 ; A2, A1, A0 _N EQU VARS+2 ; used for I2C routines O_BYTE EQU VARS+3 I_BYTE EQU VARS+4 LOOP1 EQU VARS+5 ; timing LOOP2 EQU VARS+6 ; timing LOOP3 EQU VARS+7 ; timing ORG 000H BSF STATUS, RP0 ; RP1 = 0, RP0 = 1, BANK1 CLRF TRISB ; make all PortB bits outputs BCF STATUS, RP0 ; bank 0 MAIN: MOVLW .1 ; A2 A1 A0 address MOVWF DEV_ADR CALL CONFG_1621 ; AC 01 - single shot mode MAIN1: CALL BEGIN_CNVT ; EE CALL MEASURE ; AA MOVF I_BYTE, W MOVWF T_C ; save result in T_C CALL STOP_CNVT ; 22 ; at this point T_C contains the temperature in degrees C ; this may be displayed on a serial LCD or similar or logged to ; EEPROM. MOVLW .120 ; 120 * 1/4 second delay MOVWF LOOP3 ; equals 30 second MAIN2: CALL DELAY_LONG DECFSZ LOOP3, F GOTO MAIN2 GOTO MAIN1 ; continue making measurements ;;;;;;; CONFG_1621: ; configures device for CPU operation - continuous operation CALL START BCF STATUS, C RLF DEV_ADR, W IORLW 90H MOVWF O_BYTE ; send address byte CALL OUT_BYTE CALL NACK MOVLW 0ACH ; send config information MOVWF O_BYTE CALL OUT_BYTE CALL NACK MOVLW 01H ; single shot mode MOVWF O_BYTE CALL OUT_BYTE CALL NACK CALL STOP MOVLW .15 ; 15 msec delay to assure EEPROM is prog MOVWF LOOP1 CALL DELAY_N_MS RETURN BEGIN_CNVT: ; turns on circuitry to begin conversions CALL START BCF STATUS, C RLF DEV_ADR, W IORLW 90H MOVWF O_BYTE ; send address byte CALL OUT_BYTE CALL NACK MOVLW 0EEH MOVWF O_BYTE CALL OUT_BYTE CALL NACK CALL STOP MOVLW .15 ; 15 msec delay to allow for conversion MOVWF LOOP1 CALL DELAY_N_MS RETURN MEASURE: ; performs a measurement, result returned in i_byte CALL START BCF STATUS, C RLF DEV_ADR, W IORLW 90H MOVWF O_BYTE CALL OUT_BYTE CALL NACK MOVLW 0AAH MOVWF O_BYTE CALL OUT_BYTE CALL NACK CALL START BCF STATUS, C RLF DEV_ADR, W IORLW 90H IORLW 01H ; a read operation MOVWF O_BYTE CALL OUT_BYTE CALL NACK CALL IN_BYTE CALL STOP RETURN STOP_CNVT: ; shut down device to save power CALL START BCF STATUS, C RLF DEV_ADR, W IORLW 90H MOVWF O_BYTE CALL OUT_BYTE CALL NACK MOVLW 22H MOVWF O_BYTE CALL OUT_BYTE CALL NACK CALL HIGH_SCL RETURN ; The following routines are low level I2C routines applicable to most ; interfaces with I2C devices. IN_BYTE ; read byte on i2c bus CLRF I_BYTE MOVLW .8 MOVWF _N ; set index to 8 CALL HIGH_SDA ; be sure SDA is configured as input IN_BIT CALL HIGH_SCL ; clock high BTFSS PORTB, SDA ; test SDA bit GOTO IN_ZERO GOTO IN_ONE IN_ZERO BCF STATUS, C ; clear any carry RLF I_BYTE, F ; i_byte = i_byte << 1 | 0 GOTO CONT_IN IN_ONE BCF STATUS, C ; clear any carry RLF I_BYTE, F INCF I_BYTE, F ; i_byte = (i_byte << 1) | 1 GOTO CONT_IN CONT_IN CALL LOW_SCL ; bring clock low DECFSZ _N, F ; decrement index GOTO IN_BIT RETURN ;;;;;; OUT_BYTE: ; send o_byte on I2C bus MOVLW .8 MOVWF _N OUT_BIT: BCF STATUS,C ; clear carry RLF O_BYTE, F ; left shift, most sig bit is now in carry BTFSS STATUS, C ; if one, send a one GOTO OUT_ZERO GOTO OUT_ONE OUT_ZERO: CALL LOW_SDA ; SDA at zero CALL CLOCK_PULSE CALL HIGH_SDA GOTO OUT_CONT OUT_ONE: CALL HIGH_SDA ; SDA at logic one CALL CLOCK_PULSE GOTO OUT_CONT OUT_CONT: DECFSZ _N, F ; decrement index GOTO OUT_BIT RETURN ;;;;;; NACK: ; bring SDA high and clock CALL HIGH_SDA CALL CLOCK_PULSE RETURN ACK: CALL LOW_SDA CALL CLOCK_PULSE RETURN START: CALL LOW_SCL CALL HIGH_SDA CALL HIGH_SCL CALL LOW_SDA ; bring SDA low while SCL is high CALL LOW_SCL RETURN STOP: CALL LOW_SCL CALL LOW_SDA CALL HIGH_SCL CALL HIGH_SDA ; bring SDA high while SCL is high CALL LOW_SCL RETURN CLOCK_PULSE: ; SCL momentarily to logic one CALL HIGH_SCL CALL LOW_SCL RETURN HIGH_SDA: ; high impedance by making SDA an input BSF STATUS, RP0 ; bank 1 BSF TRISB, SDA ; make SDA pin an input BCF STATUS, RP0 ; back to bank 0 CALL DELAY_SHORT RETURN LOW_SDA: BCF PORTB, SDA BSF STATUS, RP0 ; bank 1 BCF TRISB, SDA ; make SDA pin an output BCF STATUS, RP0 ; back to bank 0 CALL DELAY_SHORT RETURN HIGH_SCL: BSF STATUS, RP0 ; bank 1 BSF TRISB, SCL ; make SCL pin an input BCF STATUS, RP0 ; back to bank 0 CALL DELAY_SHORT RETURN LOW_SCL: BCF PORTB, SCL BSF STATUS, RP0 ; bank 1 BCF TRISB, SCL ; make SCL pin an output BCF STATUS, RP0 ; back to bank 0 CALL DELAY_SHORT RETURN DELAY_SHORT: ; provides nominal 25 usec delay MOVLW .5 MOVWF LOOP2 DELAY_SHORT_1: NOP DECFSZ LOOP2, F GOTO DELAY_SHORT_1 RETURN DELAY_LONG MOVLW .250 ; 250 msec delay MOVWF LOOP1 DELAY_N_MS: OUTTER MOVLW .110 ; close to 1.0 msec delay when set to .110 MOVWF LOOP2 INNER NOP NOP NOP NOP NOP NOP DECFSZ LOOP2, F ; decrement and leave result in LOOP2 GOTO INNER DECFSZ LOOP1, F GOTO OUTTER RETURN END
Program DS1621_2.ASM.
This program is intended to illustrate how to set the high and low temperature thresholds and how to determine whether a threshold has been exceeded.
The program sets high and low thresholds of 30.5 and 20.5 degrees C respectively. The program then loops, checking to see if either the high or low thresholds have been exceeded. If the temperature has gone higher than the high temperature threshold an LED on Port B, Bit 1 is operated indicating a high temperature condition. Similarly, if the temperature drops below the specified low temperature threshold, an LED on Port B, Bit 0 is operated.
Further, an output on the DS1621, T_OUT (terminal 3) may also be used for controlling a fan, heater or air conditioning unit. This bit assummes one state when the temperature goes above the high temperature threshold and does not assume the opposite state until the temperature has dropped below the low temperature threshold. The states may be selected by programming the POL (polarity bit) in the configuration / status register.
In addition, a temperature measurment is made during each 30 second loop. In this program. a dummy DISPLAY routine is called, but it is not implemented.
Configuration / Status Register.
As many of the bits in the configuration / status register are used in this routine, a few words are appropriate.
Bit 7 6 5 4 3 2 1 0 Function DONE THF TLF NVB 1 0 POL 1SHOT
DONE (Read Only) - Logic one when a temperature conversion is complete. This is not used in this routine. Rather, in 1621_1.ASM, a 25 msec timing delay was used after starting a conversion to allow for the time required for conversion.
THF - Normally logic zero. Logic one if the high temperature threshold was ever exceeded. In this routine, this bit is read and determines the state of the LED on Portb, Bit 1. The bit is then cleared.
TLF - Normally logic zero. Logic one if the low temperature threshold was ever exceeded. In this routine, this bit is treated in a manner similar to the THF bit.
NVB - Normally logic zero. Goes to logic one while the DS1621 is busy writing to it's internal EEPROM. This bit is not read in this program. Rather a 15 msec timing delay is used in routine CONFIG_1621.
POL - Ouput Polarity Bit. This determines the polarity of the signal on T_OUT. When POL is set to logic one, when the temperature goes above the high threshold, T_OUT goes to a logic one and remains at a logic one until the temperature drops below the low threshold. When POL is set to a logic zero, T_OUT is normally a logic one and goes to a logic zero when the temperature exceeds the high threshold. In this routine, this bit was set to a logic one.
1SHOT - When set to logic zero, continuous conversions are performed. When set to a logic one, only one conversion is performed in response to the Start Conversion command. In this routine, the continuous conversion mode is used. Note that in doing so, no Start Conversion command is required for each measurement.
Setting the Thresholds.
The high and low temperature thresholds are set in routines SETLIMIT_HI and SETLIMIT_LO. Note that the thresholds consist of nine bits which are sent as two bytes. The high byte is the number of degrees and the most significant bit of the second byte indicates whether the threshold is .0 or .5.
Reading the Configuration / Status Register.
This is performed in routine FETCH_CONFIG. Note that this routine is similar in concept to the MEASURE routine.
First, the Start command followed by the address byte with the R/W bit set to "write" (logic 0) followed by a NACK, followed by the Access Config command (AC H), followed by another NACK. This is followed by another Start command, with no intermediate Stop, the address byte with the R/W bit set to "read" (logic 1), followed by a NACK. The content of the register is then read using the IN_BYTE routine.
Detailed Program Description.
In the intialization, the high and low temperature condition LEDs on Port A are turned off and the configuration / status register is set to 0000 0010. This is logic 1 polarity of the T_OUT output on the DS1621 and continuous conversion.
The high and low temperature threshold limits are then set to 30.5 and 20.5 degrees C.
The program then loops with a 30 second delay. During each loop, a temperature measurement is performed and T_C is passed to a dummy display routine. The configuration register is also read and the THF and TLF bits are tested. If either is set, the appropriate LED on Port A is operated and the THF and TLF bits are cleared using the CONFIG_1621 routine.
; DS1621_2.ASM ; ; Illustrates various thermostat functions of DS1621. ; ; High and low temperature thresholds set to 30.5 and 20.5 degrees C. ; ; Program continually loops every 30 seconds and checks the DS1621 ; configuration word as to whether the temperature has exceeded T_HI ; or gone below T_LO and if so, operates the appropriate LED on Port B, ; bits 0 and 1. ; ; The program also performs an 8-bit temperature measurement. ; ; PIC16C84 DS1621 ; ; RB7 (term 13) ------------------- SCL (term 2) ----- To Other ; RB6 (term 12) ------------------- SDA (term 1) ----- I2C Devices ; ; RB1 (term 7) ---- LED ---- 330 ----- +5VDC (HI_TEMP_COND) ; RB0 (term 6) ---- LED ---- 330 ----- +5VDC (LO_TEMP_COND) ; ; Note that the slave address is determined by A2 (term 5), A1 ; (term 6) and A0 (term 7) on the DS1621. The above SCL and SDA leads ; may be multipled to eight group "1001" devices, each strapped for a ; unique A2 A1 A0 setting. ; ; 10K pullup resistors to +5VDC are required on both signal leads. ; ; copyright, Nicole Ambrose and H. Paul Roach, MSU, July 3, '97 LIST p=16c84 #include <c:\mplab\p16c84.inc> __CONFIG 11h CONSTANT SDA=6 ; PORTB terminals assigned CONSTANT SCL=7 CONSTANT HI_ALM=1 CONSTANT LO_ALM=0 CONSTANT THF=6 ; bit 6 in configuration register CONSTANT TLF=5 ; bit 5 CONSTANT VARS=0CH ; starting point for variables T_C EQU VARS+0 DEV_ADR EQU VARS+1 ; A2, A1, A0 _N EQU VARS+2 ; used for I2C routines O_BYTE EQU VARS+3 I_BYTE EQU VARS+4 LOOP1 EQU VARS+5 ; timing LOOP2 EQU VARS+6 ; timing LOOP3 EQU VARS+7 ; timing ORG 000H BSF STATUS, RP0 ; RP1 = 0, RP0 = 1, BANK1 CLRF TRISB ; make all PortB bits outputs BCF STATUS, RP0 ; bank 0 BSF PORTB, HI_ALM ; turn off alarm indicators BSF PORTB, LO_ALM ; same MAIN: MOVLW .1 ; A2 A1 A0 address MOVWF DEV_ADR CALL CONFIG_1621 ; AC 02 CALL SETLIMIT_HI ; A1 followed by hi threshold CALL SETLIMIT_LO ; A2 followed by lo threshold CALL BEGIN_CNVT ; not sure if this is necessary MAIN1: CALL MEASURE ; AA MOVF I_BYTE, W MOVWF T_C ; save result in T_C ; at this point T_C contains the temperature in degrees C ; this may be displayed on a serial LCD or similar or logged to ; EEPROM. CALL DISPLAY CALL FETCH_CONFIG ; AC BTFSC I_BYTE, THF ; test if hi temperature alarm GOTO HI_TEMP_COND BTFSC I_BYTE, TLF ; if low temperature alarm GOTO LO_TEMP_COND BSF PORTB, HI_ALM ; else turn off alarm indicators BSF PORTB, LO_ALM MAIN2: MOVLW .120 ; 120 * 1/4 second delay MOVWF LOOP3 ; equals 30 second MAIN3: CALL DELAY_LONG DECFSZ LOOP3, F GOTO MAIN3 GOTO MAIN1 ; continue making measurements HI_TEMP_COND: BCF PORTB, HI_ALM ; turn on HI_ALM LED CALL CONFIG_1621 ; to reset TH Flag GOTO MAIN2 LO_TEMP_COND: BCF PORTB, LO_ALM ; turn on LO_ALM_LED CALL CONFIG_1621 ; to reset TH Flag GOTO MAIN2 ;;;;;;; CONFIG_1621: ; configures device for CPU operation - continuous CALL START BCF STATUS, C RLF DEV_ADR, W IORLW 90H MOVWF O_BYTE ; send address byte CALL OUT_BYTE CALL NACK MOVLW 0ACH ; send config information MOVWF O_BYTE CALL OUT_BYTE CALL NACK MOVLW 02H MOVWF O_BYTE CALL OUT_BYTE CALL NACK CALL STOP MOVLW .15 ; delay 15 msecs for EEPROM MOVWF LOOP1 CALL DELAY_N_MS RETURN BEGIN_CNVT: ; turns on circuitry to begin conversions CALL START BCF STATUS, C RLF DEV_ADR, W IORLW 90H MOVWF O_BYTE ; send address byte CALL OUT_BYTE CALL NACK MOVLW 0EEH MOVWF O_BYTE CALL OUT_BYTE CALL NACK CALL STOP MOVLW .15 ; delay 15 msecs for conversion MOVWF LOOP1 CALL DELAY_N_MS RETURN MEASURE: ; performs a measurement, result returned in i_byte CALL START BCF STATUS, C RLF DEV_ADR, W IORLW 90H MOVWF O_BYTE CALL OUT_BYTE CALL NACK MOVLW 0AAH MOVWF O_BYTE CALL OUT_BYTE CALL NACK CALL START BCF STATUS, C RLF DEV_ADR, W IORLW 90H IORLW 01H ; a read operation MOVWF O_BYTE CALL OUT_BYTE CALL NACK CALL IN_BYTE CALL STOP RETURN SETLIMIT_HI: ; set high threshold to 30.5 degrees C CALL START BCF STATUS, C RLF DEV_ADR, W IORLW 90H MOVWF O_BYTE CALL OUT_BYTE CALL NACK MOVLW 0A1H MOVWF O_BYTE CALL OUT_BYTE CALL NACK MOVLW .30 ; 30 degrees C MOVWF O_BYTE CALL OUT_BYTE CALL NACK MOVLW 80H ; second byte of threshold - 0.5 MOVWF O_BYTE CALL OUT_BYTE CALL NACK CALL STOP RETURN SETLIMIT_LO: ; set low alarm threshold CALL START BCF STATUS, C RLF DEV_ADR, W IORLW 90H MOVWF O_BYTE CALL OUT_BYTE CALL NACK MOVLW 0A2H ; A2, set lo limit MOVWF O_BYTE CALL OUT_BYTE CALL NACK MOVLW .20 ; low limit 20.5 MOVWF O_BYTE CALL OUT_BYTE CALL NACK MOVLW 80H ; second byte MOVWF O_BYTE CALL OUT_BYTE CALL NACK CALL STOP RETURN FETCH_CONFIG: ; fetches configuration / status register ; result returned in i_byte CALL START BCF STATUS, C RLF DEV_ADR, W IORLW 90H MOVWF O_BYTE CALL OUT_BYTE CALL NACK MOVLW 0ACH MOVWF O_BYTE CALL OUT_BYTE CALL NACK CALL START BCF STATUS, C RLF DEV_ADR, W IORLW 90H IORLW 01H ; a read operation MOVWF O_BYTE CALL OUT_BYTE CALL NACK CALL IN_BYTE ; content of config register now in i_byte CALL STOP RETURN DISPLAY: ; this is a dummy function where T_C might be displayed ; in some manner RETURN ; The following routines are low level I2C routines applicable to most ; interfaces with I2C devices. IN_BYTE ; read byte on i2c bus CLRF I_BYTE MOVLW .8 MOVWF _N ; set index to 8 CALL HIGH_SDA ; be sure SDA is configured as input IN_BIT CALL HIGH_SCL ; clock high BTFSS PORTB, SDA ; test SDA bit GOTO IN_ZERO GOTO IN_ONE IN_ZERO BCF STATUS, C ; clear any carry RLF I_BYTE, F ; i_byte = i_byte << 1 | 0 GOTO CONT_IN IN_ONE BCF STATUS, C ; clear any carry RLF I_BYTE, F INCF I_BYTE, F ; i_byte = (i_byte << 1) | 1 GOTO CONT_IN CONT_IN CALL LOW_SCL ; bring clock low DECFSZ _N, F ; decrement index GOTO IN_BIT RETURN ;;;;;; OUT_BYTE: ; send o_byte on I2C bus MOVLW .8 MOVWF _N OUT_BIT: BCF STATUS,C ; clear carry RLF O_BYTE, F ; left shift, most sig bit is now in carry BTFSS STATUS, C ; if one, send a one GOTO OUT_ZERO GOTO OUT_ONE OUT_ZERO: CALL LOW_SDA ; SDA at zero CALL CLOCK_PULSE CALL HIGH_SDA GOTO OUT_CONT OUT_ONE: CALL HIGH_SDA ; SDA at logic one CALL CLOCK_PULSE GOTO OUT_CONT OUT_CONT: DECFSZ _N, F ; decrement index GOTO OUT_BIT RETURN ;;;;;; NACK: ; bring SDA high and clock CALL HIGH_SDA CALL CLOCK_PULSE RETURN ACK: CALL LOW_SDA CALL CLOCK_PULSE RETURN START: CALL LOW_SCL CALL HIGH_SDA CALL HIGH_SCL CALL LOW_SDA ; bring SDA low while SCL is high CALL LOW_SCL RETURN STOP: CALL LOW_SCL CALL LOW_SDA CALL HIGH_SCL CALL HIGH_SDA ; bring SDA high while SCL is high CALL LOW_SCL RETURN CLOCK_PULSE: ; SCL momentarily to logic one CALL HIGH_SCL CALL LOW_SCL RETURN HIGH_SDA: ; high impedance by making SDA an input BSF STATUS, RP0 ; bank 1 BSF TRISB, SDA ; make SDA pin an input BCF STATUS, RP0 ; back to bank 0 CALL DELAY_SHORT RETURN LOW_SDA: BCF PORTB, SDA BSF STATUS, RP0 ; bank 1 BCF TRISB, SDA ; make SDA pin an output BCF STATUS, RP0 ; back to bank 0 CALL DELAY_SHORT RETURN HIGH_SCL: BSF STATUS, RP0 ; bank 1 BSF TRISB, SCL ; make SCL pin an input BCF STATUS, RP0 ; back to bank 0 CALL DELAY_SHORT RETURN LOW_SCL: BCF PORTB, SCL BSF STATUS, RP0 ; bank 1 BCF TRISB, SCL ; make SCL pin an output BCF STATUS, RP0 ; back to bank 0 CALL DELAY_SHORT RETURN DELAY_SHORT: ; provides nominal 25 usec delay MOVLW .5 MOVWF LOOP2 DELAY_SHORT_1: NOP DECFSZ LOOP2, F GOTO DELAY_SHORT_1 RETURN DELAY_LONG MOVLW .250 ; 250 msec delay MOVWF LOOP1 DELAY_N_MS: OUTTER: MOVLW .110 ; close to 1.0 msec delay when set to .110 MOVWF LOOP2 INNER: NOP NOP NOP NOP NOP NOP DECFSZ LOOP2, F ; decrement and leave result in LOOP2 GOTO INNER DECFSZ LOOP1, F GOTO OUTTER RETURN END
Program DS1621_3.ASM.
This program is the same as DS1621_2.ASM except that routine MEASURE has been expanded to receive two bytes and a DISPLAY routine has been implemented.
Routine MEASURE.
In programs DS1621_1.ASM and DS1621_2.ASM, the MEASURE routine consisted of receiving one byte from the DS1621. This is the whole number of degrees. For example 23 degrees C. In this version of MEASURE, the first byte is received and copied to T_C_HI. An ACK is then sent to the DS1621 and then a second byte is read. The most significant bit indicates whether the fractional part of the temperature is 0.0 or 0.5.
Routine DISPLAY.
Note that a serial LCD or similar is connected to Port A, Bit 1.
The serial LCD is reset and a string, "Temperature = " is displayed on the LCD beginning at the beginning of the first line. Outputting strings to an LCD is discussed elsewhere.
The value of T_C_HI is then passed to routine BCD_1_BYTE which converts the one byte quantity to BCD and outputs it to the serial LCD. Routine BCD_1_BYTE and a similar routine to handle two bytes is discussed eleswhere.
A decimal point is then output to the serial LCD.
If the most significant bit of T_C_LO is a zero, a "0" is displayed after the decimal point. Otherwise a "5" is displayed.
Finally, a second string " Degrees C" is output to the serial LCD.
Note that LCD_CTRL.ASM must be included in this program.
; DS1621_3.ASM ; ; Illustrates various thermostat functions of DS1621. ; ; Same as DS1621_2.ASM except that the MEASURE routine has been improved ; to receive two bytes from the DS1621 providing a 9-bit temperature ; reading. ; ; A DISPLAY routine has been added to display; ; "Temperature is XX.X Degrees C" ; ; Note that LCD_CTRL.ASM is included at the bottom of the program. ; ; PIC16C84 DS1621 ; ; RB7 (term 13) ------------------- SCL (term 2) ----- To Other ; RB6 (term 12) ------------------- SDA (term 1) ----- I2C Devices ; ; RB1 (term 7) ---- LED ---- 330 ----- +5VDC (HI_TEMP_COND) ; RB0 (term 6) ---- LED ---- 330 ----- +5VDC (LO_TEMP_COND) ; ; PORTA, Bit 1 (terminal 18) ------ TX ----------> to RX on Serial LCD ; ; Note that the slave address is determined by A2 (term 5), A1 ; (term 6) and A0 (term 7) on the DS1621. The above SCL and SDA leads ; may be multipled to eight group "1001" devices, each strapped for a ; unique A2 A1 A0 setting. ; ; 10K pullup resistors to +5VDC are required on both signal leads. ; ; copyright, Nicole Ambrose and H. Paul Roach, MSU, July 3, '97 LIST p=16c84 #include <c:\mplab\p16c84.inc> __CONFIG 11h CONSTANT SDA=6 ; PORTB terminals assigned CONSTANT SCL=7 CONSTANT HI_ALM=1 CONSTANT LO_ALM=0 CONSTANT THF=6 ; bit 6 in configuration register CONSTANT TLF=5 ; bit 5 CONSTANT VARS=0CH ; starting point for variables T_C_HI EQU VARS+0 T_C_LO EQU VARS+1 STR_INDEX EQU VARS+2 LO_BYTE EQU VARS+3 DEC_COUNT EQU VARS+4 ; used by BCD_1_BYTE routine DEV_ADR EQU VARS+5 ; A2, A1, A0 _N EQU VARS+6 ; used for I2C routines O_BYTE EQU VARS+7 I_BYTE EQU VARS+8 LOOP1 EQU VARS+9 ; timing LOOP2 EQU VARS+0AH ; timing LOOP3 EQU VARS+0BH ; timing ORG 000H BSF STATUS, RP0 ; RP1 = 0, RP0 = 1, BANK1 CLRF TRISB ; make all PortB bits outputs BCF STATUS, RP0 ; bank 0 BSF PORTB, HI_ALM ; turn off alarm indicators BSF PORTB, LO_ALM ; same MAIN: MOVLW .1 ; A2 A1 A0 address MOVWF DEV_ADR CALL CONFIG_1621 ; AC 02 CALL SETLIMIT_HI ; A1 followed by hi threshold CALL SETLIMIT_LO ; A2 followed by lo threshold CALL BEGIN_CNVT ; EE. Not sure if necessary MAIN1: CALL MEASURE ; AA. Note, this is a two byte measurement ; at this point T_C_HI contains the temperature in degrees C ; The high bit in T_C_LO idicates whether it is .0 or .5 ; this may be displayed on a serial LCD or similar or logged to ; EEPROM. CALL DISPLAY CALL FETCH_CONFIG ; AC BTFSC I_BYTE, THF ; test if hi temperature alarm GOTO HI_TEMP_COND BTFSC I_BYTE, TLF ; if low temperature alarm GOTO LO_TEMP_COND BSF PORTB, HI_ALM ; else turn off alarm indicators BSF PORTB, LO_ALM MAIN2: MOVLW .120 ; 120 * 1/4 second delay MOVWF LOOP3 ; equals 30 second MAIN3: CALL DELAY_LONG DECFSZ LOOP3, F GOTO MAIN3 GOTO MAIN1 ; continue making measurements HI_TEMP_COND: BCF PORTB, HI_ALM ; turn on HI_ALM LED CALL CONFIG_1621 ; to reset TH Flag GOTO MAIN2 LO_TEMP_COND: BCF PORTB, LO_ALM ; turn on LO_ALM_LED CALL CONFIG_1621 ; to reset TH Flag GOTO MAIN2 ;;;;;;; CONFIG_1621: ; configures device for CPU operation - continuous CALL START BCF STATUS, C RLF DEV_ADR, W IORLW 90H MOVWF O_BYTE ; send address byte CALL OUT_BYTE CALL NACK MOVLW 0ACH ; send config information MOVWF O_BYTE CALL OUT_BYTE CALL NACK MOVLW 02H MOVWF O_BYTE CALL OUT_BYTE CALL NACK CALL STOP MOVLW .15 MOVWF LOOP1 CALL DELAY_N_MS ; 15 msec delay for EEPROM RETURN BEGIN_CNVT: ; turns on circuitry to begin conversions CALL START BCF STATUS, C RLF DEV_ADR, W IORLW 90H MOVWF O_BYTE ; send address byte CALL OUT_BYTE CALL NACK MOVLW 0EEH MOVWF O_BYTE CALL OUT_BYTE CALL NACK CALL STOP MOVLW .15 MOVWF LOOP1 CALL DELAY_N_MS ; to allow for conversion RETURN MEASURE: ; performs a two byte measurement ; result returned in T_C_HI and T_C_LO CALL START BCF STATUS, C RLF DEV_ADR, W IORLW 90H MOVWF O_BYTE CALL OUT_BYTE CALL NACK MOVLW 0AAH MOVWF O_BYTE CALL OUT_BYTE CALL NACK CALL START BCF STATUS, C RLF DEV_ADR, W IORLW 90H IORLW 01H ; a read operation MOVWF O_BYTE CALL OUT_BYTE CALL NACK CALL IN_BYTE ; fetch the high byte MOVF I_BYTE, W MOVWF T_C_HI ; and put in T_C_HI CALL ACK CALL IN_BYTE ; fetch the low byte MOVF I_BYTE, W MOVWF T_C_LO ; and put in T_C_LO CALL NACK CALL STOP RETURN SETLIMIT_HI: ; set high threshold to 30.5 degrees C CALL START BCF STATUS, C RLF DEV_ADR, W IORLW 90H MOVWF O_BYTE CALL OUT_BYTE CALL NACK MOVLW 0A1H MOVWF O_BYTE CALL OUT_BYTE CALL NACK MOVLW .30 ; 30 degrees C MOVWF O_BYTE CALL OUT_BYTE CALL NACK MOVLW 80H ; second byte of threshold MOVWF O_BYTE CALL OUT_BYTE CALL NACK CALL STOP RETURN SETLIMIT_LO: ; set low alarm threshold CALL START BCF STATUS, C RLF DEV_ADR, W IORLW 90H MOVWF O_BYTE CALL OUT_BYTE CALL NACK MOVLW 0A2H ; A2, set lo limit MOVWF O_BYTE CALL OUT_BYTE CALL NACK MOVLW .20 ; low limit 20.5 MOVWF O_BYTE CALL OUT_BYTE CALL NACK MOVLW 80H ; second byte MOVWF O_BYTE CALL OUT_BYTE CALL NACK CALL STOP RETURN FETCH_CONFIG: ; fetches configuration / status register ; result returned in i_byte CALL START BCF STATUS, C RLF DEV_ADR, W IORLW 90H MOVWF O_BYTE CALL OUT_BYTE CALL NACK MOVLW 0ACH MOVWF O_BYTE CALL OUT_BYTE CALL NACK CALL START BCF STATUS, C RLF DEV_ADR, W IORLW 90H IORLW 01H ; a read operation MOVWF O_BYTE CALL OUT_BYTE CALL NACK CALL IN_BYTE CALL STOP RETURN DISPLAY: CALL OUT_STR_1 ; "Temperature = " MOVF T_C_HI, W CALL BCD_1_BYTE ; Display whole number MOVLW "." CALL LCD_CHAR ; followed by a decimal point BTFSS T_C_LO, 7 MOVLW "0" ; and then either a zero or one BTFSC T_C_LO, 7 MOVLW "1" CALL LCD_CHAR CALL OUT_STR_2 ; "degrees C" RETURN OUT_STR_1: CLRF STR_INDEX OUT_STR_11: MOVF STR_INDEX, W CALL STR_1_LOOKUP ; fetch the character ADDLW 0 ; be sure zero flag is valid BTFSC STATUS, Z GOTO OUT_STR_12 ; done if null CALL LCD_CHAR INCF STR_INDEX, F GOTO OUT_STR_11 ; keep going OUT_STR_12: RETURN STR_1_LOOKUP: ADDWF PCL, F DT "Temperature = ", 0 OUT_STR_2: CLRF STR_INDEX OUT_STR_21: MOVF STR_INDEX, W CALL STR_2_LOOKUP ; fetch the character ADDLW 0 ; be sure zero flag is valid BTFSC STATUS, Z GOTO OUT_STR_22 ; done if null CALL LCD_CHAR INCF STR_INDEX, F GOTO OUT_STR_21 ; keep going OUT_STR_22: RETURN STR_2_LOOKUP: ADDWF PCL, F DT " Degrees C", 0 BCD_1_BYTE: BCD_1_HUNDS: CLRF DEC_COUNT BCD_1_HUNDS1: MOVLW .100 SUBWF LO_BYTE, F ; LO_BYTE=LO_BYTE-100 BTFSS STATUS, C ; no borrow GOTO BCD_1_HUNDS2 CALL INC_DEC_COUNT ; if no borrow GOTO BCD_1_HUNDS1 ; keep going BCD_1_HUNDS2: MOVF DEC_COUNT, W ; get the count BTFSC STATUS, Z ; if not zero MOVLW " " ; otherwise put in a space CALL LCD_CHAR ; and display it MOVLW .100 ADDWF LO_BYTE, F ; add back any falsely subtracted 100 BCD_1_UNITS: CLRF DEC_COUNT ; now for the units BCD_1_UNITS1: MOVLW .1 SUBWF LO_BYTE, F BTFSS STATUS, C ; did not go from 00 to FF GOTO BCD_1_UNITS2 ; done with units CALL INC_DEC_COUNT ; else increment and keep going GOTO BCD_1_UNITS1 BCD_1_UNITS2: MOVF DEC_COUNT, W ; get the number of units CALL LCD_VAL ; and display RETURN INC_DEC_COUNT: ; increments counter in BCD fashion INCF DEC_COUNT, F MOVF DEC_COUNT, W ANDLW 0FH SUBLW .9 ; W = low nibble - 9 BTFSC STATUS, C ; low nibble is in range of A - F GOTO INC_DEC_COUNT_DONE MOVF DEC_COUNT, W ADDLW .6 MOVWF DEC_COUNT INC_DEC_COUNT_DONE: RETURN ; The following routines are low level I2C routines applicable to most ; interfaces with I2C devices. IN_BYTE ; read byte on i2c bus CLRF I_BYTE MOVLW .8 MOVWF _N ; set index to 8 CALL HIGH_SDA ; be sure SDA is configured as input IN_BIT CALL HIGH_SCL ; clock high BTFSS PORTB, SDA ; test SDA bit GOTO IN_ZERO GOTO IN_ONE IN_ZERO BCF STATUS, C ; clear any carry RLF I_BYTE, F ; i_byte = i_byte << 1 | 0 GOTO CONT_IN IN_ONE BCF STATUS, C ; clear any carry RLF I_BYTE, F INCF I_BYTE, F ; i_byte = (i_byte << 1) | 1 GOTO CONT_IN CONT_IN CALL LOW_SCL ; bring clock low DECFSZ _N, F ; decrement index GOTO IN_BIT RETURN ;;;;;; OUT_BYTE: ; send o_byte on I2C bus MOVLW .8 MOVWF _N OUT_BIT: BCF STATUS,C ; clear carry RLF O_BYTE, F ; left shift, most sig bit is now in carry BTFSS STATUS, C ; if one, send a one GOTO OUT_ZERO GOTO OUT_ONE OUT_ZERO: CALL LOW_SDA ; SDA at zero CALL CLOCK_PULSE CALL HIGH_SDA GOTO OUT_CONT OUT_ONE: CALL HIGH_SDA ; SDA at logic one CALL CLOCK_PULSE GOTO OUT_CONT OUT_CONT: DECFSZ _N, F ; decrement index GOTO OUT_BIT RETURN ;;;;;; NACK: ; bring SDA high and clock CALL HIGH_SDA CALL CLOCK_PULSE RETURN ACK: CALL LOW_SDA CALL CLOCK_PULSE RETURN START: CALL LOW_SCL CALL HIGH_SDA CALL HIGH_SCL CALL LOW_SDA ; bring SDA low while SCL is high CALL LOW_SCL RETURN STOP: CALL LOW_SCL CALL LOW_SDA CALL HIGH_SCL CALL HIGH_SDA ; bring SDA high while SCL is high CALL LOW_SCL RETURN CLOCK_PULSE: ; SCL momentarily to logic one CALL HIGH_SCL CALL LOW_SCL RETURN HIGH_SDA: ; high impedance by making SDA an input BSF STATUS, RP0 ; bank 1 BSF TRISB, SDA ; make SDA pin an input BCF STATUS, RP0 ; back to bank 0 CALL DELAY_SHORT RETURN LOW_SDA: BCF PORTB, SDA BSF STATUS, RP0 ; bank 1 BCF TRISB, SDA ; make SDA pin an output BCF STATUS, RP0 ; back to bank 0 CALL DELAY_SHORT RETURN HIGH_SCL: BSF STATUS, RP0 ; bank 1 BSF TRISB, SCL ; make SCL pin an input BCF STATUS, RP0 ; back to bank 0 CALL DELAY_SHORT RETURN LOW_SCL: BCF PORTB, SCL BSF STATUS, RP0 ; bank 1 BCF TRISB, SCL ; make SCL pin an output BCF STATUS, RP0 ; back to bank 0 CALL DELAY_SHORT RETURN DELAY_SHORT: ; provides nominal 25 usec delay MOVLW .5 MOVWF LOOP2 DELAY_SHORT_1: NOP DECFSZ LOOP2, F GOTO DELAY_SHORT_1 RETURN DELAY_LONG: MOVLW .250 ; 250 msec delay MOVWF LOOP1 DELAY_N_MS: OUTTER: MOVLW .110 ; close to 1.0 msec delay when set to .110 MOVWF LOOP2 INNER: NOP NOP NOP NOP NOP NOP DECFSZ LOOP2, F ; decrement and leave result in LOOP2 ; skip next statement if zero GOTO INNER DECFSZ LOOP1, F GOTO OUTTER RETURN #include <a:\lcd\lcd_ctrl.asm> END