;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Sensirion SHT11 sensor interface ;; ;; ;; ;; Copyleft (L) P Pemberton ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; CBLOCK SHT_TEMP SHT_LOOP SHT_DEL_0, SHT_DEL_1 ENDC _SHT_SDA_SETIN MACRO BANK1 BSF SHT_SDA BANK0 ENDM _SHT_SDA_SETOUT MACRO BANK1 BCF SHT_SDA BANK0 ENDM ;; Init the SHT bus SHT_BUSINIT: BANK1 ; Data=output, Clk=output BCF SHT_SDA BCF SHT_SCL BANK0 BSF SHT_SDA ; Clock and data high BCF SHT_SCL MOVLW .9 ; 10x clock pulses MOVWF SHT_LOOP SHT_RS_LOOP: BSF SHT_SCL ; Pulse low GOTO $+1 GOTO $+1 BCF SHT_SCL ; Pulse high NOP DECFSZ SHT_LOOP, F ; Decrement loop GOTO SHT_RS_LOOP ; If not =0, keep going ; TRANSMISSION START BSF SHT_SDA BCF SHT_SCL NOP BSF SHT_SCL NOP BCF SHT_SDA NOP BCF SHT_SCL NOP GOTO $+1 BSF SHT_SCL NOP BSF SHT_SDA NOP BCF SHT_SCL _SHT_SDA_SETIN RETURN ;; Send a byte over the SHT bus SHT_SEND: _SHT_SDA_SETOUT MOVWF SHT_TEMP ; Save data byte MOVLW .8 ; 8 data bits MOVWF SHT_LOOP SHT_SEND_LOOP: RLF SHT_TEMP, F ; Rotate data bit into carry BSF SHT_SDA ; Set data pin BTFSS STATUS, W BCF SHT_SDA ; If databit clear, clear pin NOP ; Settling time BSF SHT_SCL ; Clock the data in NOP BCF SHT_SCL NOP DECFSZ SHT_LOOP, F ; Decrement loop GOTO SHT_SEND_LOOP ; If not done, keep looping _SHT_SDA_SETIN RETURN ;; Receive a byte from the SHT bus SHT_RECEIVE: _SHT_SDA_SETIN CLRF SHT_TEMP ; Clear data byte MOVLW .8 ; 8 data bits MOVWF SHT_LOOP SHT_RCV_LOOP: BSF SHT_SCL ; Clock the data out NOP BCF STATUS, C ; Clear carry BTFSC SHT_SDA ; Data bit set? BSF STATUS, C ; Yup - set carry. BCF SHT_SCL ; Clock low NOP RLF SHT_TEMP, F ; Store data bit DECFSZ SHT_LOOP, F ; Decrement loopvar GOTO SHT_RCV_LOOP ; If not done, keep looping MOVF SHT_TEMP, W RETURN ;; Wait for the SHT11 to ACK the transfer ;; Returns W=0 if SHT acked SHT_WAITACK: BSF SHT_SCL ; Clock high CLRF SHT_LOOP ; 512mS wait SHT_ACK_LOOP: BTFSS SHT_SDA ; SDA=low=ack GOTO SHT_ACKED ; SDA low, SHT has acked CALL SHT_ACK_DELAY ; 2mS delay DECFSZ SHT_LOOP, F ; Decrement loopvar GOTO SHT_ACK_LOOP ; If not done, keep looping BCF SHT_SCL ; Clock low RETLW -1 ; SHT didn't ack, return W=-1 SHT_ACKED: BCF SHT_SCL ; Clock low RETLW 0 ; Return, W=0 ;; Send an ACK to the SHT11 SHT_ACK: _SHT_SDA_SETOUT BCF SHT_SDA NOP BSF SHT_SCL NOP BCF SHT_SCL NOP _SHT_SDA_SETIN RETURN ;; Send a No-ACK to the SHT11 SHT_NACK: BSF SHT_SCL ; Clock high NOP BCF SHT_SCL ; Clock low NOP RETURN ;; Wait for the SHT11 to finish taking a measurement ;; Returns W=0 if SHT finished SHT_WAIT: CLRF SHT_LOOP ; 512mS wait SHT_WAIT_LOOP: BTFSS SHT_SDA ; SDA=low=measurement done RETLW 0 ; SDA low, SHT is finished CALL SHT_ACK_DELAY ; 2mS delay DECFSZ SHT_LOOP, F ; Decrement loopvar GOTO SHT_WAIT_LOOP ; If not done, keep looping RETLW -1 ; SHT failed to ACK SHT_ACK_DELAY: MOVLW 0x8E MOVWF SHT_DEL_0 MOVLW 0x02 MOVWF SHT_DEL_1 SHT_ACK_DELAY_0: DECFSZ SHT_DEL_0, F GOTO $+2 DECFSZ SHT_DEL_1, F GOTO SHT_ACK_DELAY_0 GOTO $+1 NOP RETURN END