; ds1629.asm ; Program to demonstrate various operations on the DS1629 device. For more info, see ; the data sheet LIST P=16F877, R=DEC INCLUDE "P16F877.inc" ; Definitions for the DS1629 DEVADD_1629 EQU 0x9E ; I2C device address for DS 1629 ; Commands that the DS 1629 supports ACCESS_CONFIG EQU 0xAC ; Access the config register for read or write START_CONVERT EQU 0xEE ; Start a temperature conversion STOP_CONVERT EQU 0xEE ; Stop a temperature conversion TEMP_READ_CMD EQU 0xAA ; Read the temp, 1 or 2 bytes READ_COUNTER EQU 0xA8 ; Read the count_remain register READ_SLOPE EQU 0xA8 ; Read the count_per_c register ACCESS_CLOCK EQU 0xC0 ; Access the clock/calendar register ACCESS_ALARM EQU 0xC7 ; Access the alarm register ACCESS_THERM_H EQU 0xA1 ; Access the thermostat register high register ACCESS_THERM_L EQU 0xA2 ; Access the thermostat register high register ACCESS_RAM EQU 0x17 ; Access the onboard RAM ; Definitions for the PIC SDA EQU 4 ; PORT C bit for SDA SCL EQU 3 ; PORT C bit for SCL I2CRW EQU 2 ; R/_W bit in SSPSTAT RAM EQU 0x20 Temp EQU RAM+6 Counter EQU RAM+7 DTemp1 EQU RAM+8 DTemp2 EQU RAM+9 Temper1 EQU RAM+10 Temper2 EQU RAM+11 Status EQU RAM+12 RamAddress EQU RAM+13 RamValue EQU RAM+14 DTemp3 EQU RAM+15 ; Start of the Program ORG 3 goto Start ORG 0x20 Start ; Initialize the TRIS registers. Importantly, SDA and SCL must be inputs bsf STATUS, RP0 clrf TRISA ; for led bar clrf TRISD ; for led bar bsf TRISC,SDA bsf TRISC,SCL bcf STATUS, RP0 ; Initialize the I2C control call I2CConfig ; This tests three things - read the status, read and write memory and read the temperature ; You should see the default status 0xC0, then 0xA3 and finally the two bytes of the ; temperature with one second displays before starting over. The temperature at 70 degrees F ; displays as 0x17 and then 0x80 mainloop call TestStatus movlw 1 call Delay_sec call TestMem movlw 1 call Delay_sec call TestTemp movlw 1 call Delay_sec goto mainloop TestMem movlw 0xA3 movwf RamValue movlw 0x10 movwf RamAddress call WriteRam movwf 100 call Delay_ms call ReadRam movf RamValue,W call DispLedBar return ; Get and display the status byte TestStatus call ReadStatus movf Status,W call DispLedBar return ; Now read the temperature. TestTemp call TempRead call TempDisplay return ; Reading the temperature is a two byte operation (if accuracy is desired) ; The sequence is: ; Start, Send Address, Send Command, Restart, Send Address, Read MSB, ; Send Ack, Read LSB, Send Nack, Stop TempRead call I2CStart ; Send the control byte movlw DEVADD_1629 andlw 0xFE ; make it a write call I2CSend ; Send the read temperature command movlw TEMP_READ_CMD call I2CSend ; Restart for read of data call I2CRestart ; Send the address again movlw DEVADD_1629 iorlw 0x01 ; make it a read call I2CSend ; and read the data with an ACK between the bytes call I2CReceive movwf Temper1 call I2CAck call I2CReceive movwf Temper2 call I2CNack ; Bring a merciful end to this call I2CStop return TempDisplay movf Temper1,W call DispLedBar movlw 1 call Delay_sec movf Temper2,W call DispLedBar movlw 1 call Delay_sec return ; Reading that status can be either one or two bytes. Here, do only 1 byte ; Start, Send devaddr (write), send command, restart, send devaddr (read), read MSB ; send Nack, stop ReadStatus call I2CStart ; Send the control byte movlw DEVADD_1629 andlw 0xFE ; make it a write call I2CSend ; Send the read status command movlw ACCESS_CONFIG call I2CSend ; Restart for read of data call I2CRestart ; Send the address again movlw DEVADD_1629 iorlw 0x01 ; make it a read call I2CSend ; and read the MSB call I2CReceive movwf Status call I2CNack call I2CStop return ; --------------------------------------------------------- ; Write to RAM has the following sequence ; Start, send control (write), send address, send data, stop WriteRam call I2CStart ; Send the control byte movlw DEVADD_1629 andlw 0xFE ; make it a write call I2CSend ; Send the command movlw ACCESS_RAM call I2CSend ; Send the address movf RamAddress,W call I2CSend ; Send the data movf RamValue,W call I2CSend ; Stop call I2CStop return ; --------------------------------------------------------- ; Reading RAM has the following sequence ; Start, send control (write), send address, Restart, send control (read), read data, ; send Nack, stop ReadRam call I2CStart ; Send the control byte movlw DEVADD_1629 andlw 0xFE ; make it a write call I2CSend ; Send the command movlw ACCESS_RAM call I2CSend ; Send the address movf RamAddress,W call I2CSend ; Restart call I2CRestart ; Send the control byte movlw DEVADD_1629 iorlw 0x01 ; make it a read call I2CSend ; Read the data call I2CReceive movwf RamValue ; Ack the data call I2CNack ; Stop call I2CStop return ;---------------------------------------------------------------------------------- ; I2C control routines I2CConfig ; movlw b'00111011' ; enable SSP and set mode to Master/Slave Idle movlw b'00111000' ; to be used when SPADD is used to set the speed movwf SSPCON bsf STATUS, RP0 ; the following three or do none of these and accept the defaults. ; clrf SSPCON2 ; bcf SSPSTAT, SMP ; bcf SSPSTAT, CKE ; If using SPADD, calculate SPADD = (Fosc/(i2c_clock_speed * 4)) - 1 ; e.g. the DS1629 has a maximum clock rate of 400 kHz, so ; SPADD = 20x10^6/(4x10^5 * 4) - 1 = 11.5 movlw 12 movwf SSPADD bcf STATUS, RP0 return ; Issue a start I2CStart bsf STATUS, RP0 bsf SSPCON2, SEN ; initiate a start condition bcf STATUS, RP0 call I2CWait return ; Issue a restart I2CRestart bsf STATUS, RP0 bsf SSPCON2, RSEN ; initiate a restart condition bcf STATUS, RP0 call I2CWait return ; Issue a stop I2CStop bsf STATUS, RP0 bsf SSPCON2, PEN ; initiate a stop condition bcf STATUS, RP0 call I2CWait return ; Send a byte I2CSend movwf SSPBUF ; Start a write op call I2CWait return ; Receive a byte I2CReceive bsf STATUS, RP0 bsf SSPCON2, RCEN ; Start receive bcf STATUS, RP0 call I2CWait movf SSPBUF, W ; return in W return ; Initiate an Ack response from the master I2CAck bsf STATUS, RP0 bcf SSPCON2, ACKDT ; setup ACK bsf SSPCON2, ACKEN ; send ACK bcf STATUS, RP0 call I2CWait return ; Initiate a Nack response from the master I2CNack bsf STATUS, RP0 bsf SSPCON2, ACKDT ; setup NACK bsf SSPCON2, ACKEN ; send NACK bcf STATUS, RP0 call I2CWait return ; ----------------------------------------------------------------- ; Various I2C wait operations ; Wait for an operation end by waiting for the BF bit in SSPSTAT I2CBFWait bsf STATUS, RP0 btfsc SSPSTAT, BF goto $-1 bcf STATUS, RP0 return ; Wait for an operation end by waiting for the R/W bit I2CRWWait bsf STATUS, RP0 btfsc SSPSTAT, I2CRW goto I2CRWWait bcf STATUS, RP0 return ; Wait for an operation end by waiting for the BF bit in SSPSTAT I2CAckWait bsf STATUS, RP0 btfsc SSPSTAT, ACKSTAT goto $-1 bcf STATUS, RP0 return ; Wait for end of I2C operation by watching the SSPIF flag I2CWait btfss PIR1, SSPIF goto I2CWait bcf PIR1, SSPIF ; clear for next operation return ; ---------------------------------------------------------- ; Display routines ; Routine to display something on the LED bank DispLedBar ; Enable the led bar and put the value in W there. movwf Temp ; save W movlw 0x12 movwf PORTA comf Temp,W movwf PORTD return ; Display something on the Led Bar and wait for one second - ; handy for debugging DisplayDebug call DispLedBar movlw 1 call Delay_sec ; ------------------------- ; Delay routines ; Delay microseconds (usec) Delay_us movwf DTemp1 dloop_u1 ; one loop = about 1 usec fill (nop), 3 decfsz DTemp1,F goto dloop_u1 return; ; Delay milliseconds Delay_ms movwf DTemp1 dloop_0 ; number of ms to delay movlw 250 movwf DTemp2 dloop_1 ; 1 ms delay (approximately) fill (nop), 17 decfsz DTemp2,F goto dloop_1 decfsz DTemp1,F goto dloop_0 return ; Delay seconds Delay_sec movwf DTemp1 ; number of seconds to delay dloop_s0 movlw 250 ; 1 second delay movwf DTemp2 dloop_s1 movlw 250 ; 4 ms delay movwf DTemp3 dloop_s2 fill (nop), 78 decfsz DTemp3,F goto dloop_s2 decfsz DTemp2,F goto dloop_s1 decfsz DTemp1,F goto dloop_s0 return END