PIC18f1320 and DS18B20 temperature sensor

Due to personal reasons, it has been a long time since I’ve done something with electronics. Time to start again and have some fun 🙂

Like you can see on the picture below, I’m experimenting with a pic18f1320, a DS18B20 temperature sensor (1-wire connection) and HD44780 display on a breadboard.

DS18B20_BB

Because of the 1-wire connection the electronic schematic is not very complex.

pic18f1320_DS18B20

I’ve written the pic-program in assembly (gputils/gpasm):

; ---------------------------------------------------------------------------
; µC = PIC18F1320 
; ---------------------------------------------------------------------------
	LIST P=18F1320
	#include <p18f1320.inc>

; ---------------------------------------------------------------------------
; Configuration
; ---------------------------------------------------------------------------
    	CONFIG OSC 	= INTIO2	; Internal RC, OSC1 as RA7, OSC2 as RA6
	CONFIG WDT 	= OFF		; Watchdog Timer
	CONFIG BOR 	= OFF		; Brown-Out Reset
	CONFIG MCLRE 	= OFF		; MCLR Enable
	CONFIG LVP 	= OFF		; Low Voltage ICSP
	CONFIG DEBUG 	= OFF		; Background Debugger Enable

; ---------------------------------------------------------------------------
; Define LCD pins
; ---------------------------------------------------------------------------
	#DEFINE RS 	PORTA, 4    	; RS line of LCD
        #DEFINE E  	PORTA, 6    	; E line of LCD
	#DEFINE D4 	PORTA, 0	;
	#DEFINE D5 	PORTA, 1        ; D4-D7 of LCD
	#DEFINE D6 	PORTA, 2	;
	#DEFINE D7 	PORTA, 3	;

; ---------------------------------------------------------------------------
; DEFINE DS18B20 pin
; ---------------------------------------------------------------------------
	#DEFINE DQ 	1		; PORTB PIN 1

; ---------------------------------------------------------------------------
; MACRO's DS18B20
; ---------------
; 	See <http://www.maximintegrated.com/en/app-notes/index.mvp/id/2420>
; ---------------------------------------------------------------------------
OW_HIZ: MACRO  	; Force the DQ line into a high impedance state.
         	BSF    TRISB, DQ        ; Make DQ pin High Z
        ENDM

OW_LO:  MACRO  	; Force the DQ line to a logic low.
         	BCF    PORTB, DQ        ; Clear the DQ bit
         	BCF    TRISB, DQ        ; Make DQ pin an output
        ENDM

WAIT:   MACRO 	TIME
         	; Delay for TIME µs.
         	; Variable time must be in multiples of 5µs.
         	MOVLW  (TIME/5) - 1      ; 1µs to process
         	MOVWF  TMP0              ; 1µs to process
         	CALL   WAIT5U            ; 2µs to process
        ENDM

; ---------------------------------------------------------------------------
; MACRO wait ms
; ---------------------------------------------------------------------------
WAITms	MACRO 	TIME
		; Delay for TIME ms
		movlw  TIME
		call   Wachtms
	ENDM

; ---------------------------------------------------------------------------
; MACRO's LCD
; ---------------------------------------------------------------------------
EStrobe MACRO                  		; Strobe the "E" Bit
         	bsf    E
         	bcf    E
        ENDM

PRINT   MACRO  	var          		; load TBLPTR with string address
         	movlw  upper(var)   	; for LCD display
         	movwf  TBLPTRU
         	movlw  high(var)
         	movwf  TBLPTRH
         	movlw  low(var)
         	movwf  TBLPTRL
         	tblrd*+
         	call   printstr
        ENDM

; ---------------------------------------------------------------------------
; Variables
; ---------------------------------------------------------------------------
	cblock	0x00
		delay
		Temp
		dummy
		; conv numbers --> char
		hundreds
                bin
                tens_and_ones
		; temp.display
		MEM
		fraction
		; DS18B20
		TMP0
                PDBYTE
                IOBYTE
                COUNT
	endc

; ---------------------------------------------------------------------------
; START
; ---------------------------------------------------------------------------
start
	movlw 	B'01100000'		; FREQ = 4Mhz
    	movwf 	OSCCON

	CLRF 	PORTA			; Initialize PORTA by clearing output
	CLRF 	PORTB 			; Initialize PORTB by clearing output
					; data latches
	MOVLW 	0x7F 			; Set RB's & RA's as
	MOVWF 	ADCON1 			; digital I/O pins

	clrw
	movwf 	TRISA			; PORTA = OUTPUT
        movwf 	TRISB                   ; PORTB = OUTPUT

	WAITms	10			; Wait a few ms

	call	initlcd			; setup LCD display

lus
        call 	cls			; clear LCD display
        movlw 	H'80'			; goto line 1
        call 	SendINS
	PRINT 	jan			; PRINT jan
RETRY
	CALL 	OW_RESET
        BTFSS   PDBYTE,0
        BRA     RETRY			; Retry when there is no pulse of DS18B20
        MOVLW   H'CC'			; DS18B20 : Skip ROM
        CALL    DSTXBYTE
        MOVLW   H'44'			; DS18B20 : Convert Temp
        CALL    DSTXBYTE

	WAIT 	D'800'			; Wait 800 µs 

	CALL 	OW_RESET
        BTFSS   PDBYTE,0
        BRA     RETRY			; Retry when there is no pulse of DS18B20
        MOVLW   H'CC'			; DS18B20 : Skip ROM
        CALL    DSTXBYTE
        MOVLW   H'BE'			; DS18B20 : Read ScratchPad
        CALL    DSTXBYTE

        movlw 	H'94'			; goto line 3
        call 	SendINS

        CALL 	DSRXBYTE		; Read LTEMP (in IOBYTE)
        movff 	IOBYTE, MEM		; MEM = LTEMP
        CALL 	DSRXBYTE		; READ HTEMP (in IOBYTE)

	;==============================================================;
        ; IOBYTE = HTEMP					       ;
   	; MEM    = LTEMP					       ;
	; BTW, we assume that we never meassure negative temperatures  ;
	;==============================================================;
	clrf 	fraction           	; fraction = 0
        bcf 	STATUS, C           	; clear carry flag
        rrcf 	MEM, f
        rrcf 	fraction, f
        rrcf 	MEM, f
        rrcf 	fraction, f         	; MEM = MEM/16 , fraction
        rrcf 	MEM, f
        rrcf 	fraction, f
        rrcf 	MEM, f
        rrcf 	fraction, f
        swapf 	fraction, f
        swapf 	IOBYTE, w         	; W = IOBYTE * 16
        iorwf 	MEM, w            	; W = HTEMP+LTEMP
        call 	DispDec			; PRINT XX
	movlw   "."
        call    SendCHAR		; PRINT .

	;==============================================================;
	; Calculate .X                                                 ;
	; ------------                                                 ;
	; 	See DS18B20.gnumeric 				       ;
	;==============================================================;
	clrw				; XX.0
	btfsc   fraction, 3		; If bit 3 = 1 then
	ADDLW	D'5'			; W = W + 5
	btfsc	fraction, 2		; If bit 2 = 1 then
	ADDLW	D'3'			; W = W + 3
	btfsc	fraction, 1		; If bit 1 = 1 then
	ADDLW	D'1'			; W = W + 1
	btfss 	fraction, 0		; If bit 0 = 1 
	bra	ready			; and bit 2 <> 1 then
	btfss	fraction, 2 		; W = W + 1
	ADDLW	D'1'
ready:
	call 	SendASCII		; PRINT after .

	call 	Wacht1s

	goto 	lus

; ---------------------------------------------------------------------------
; LCD subroutine init/cls
; ---------------------------------------------------------------------------
initlcd:
	WAITms	D'40'
        bcf    	RS         		; send an 8 bit instruction
        movlw  	0x03             	; Reset Command
        call   	NybbleOut       	; Send the Nybble
        WAITms	D'5'            	; Wait 5 msecs before Sending Again
       	EStrobe
        WAIT	D'160'			; Wait 160 usecs before Sending 2nd Time
       	EStrobe
        WAIT	D'160'          	; Wait 160 usecs before Sending 3rd Time
        bcf    	RS               	; send an 8 bit instruction
        movlw  	0x02             	; Set 4 Bit Mode
        call   	NybbleOut
        WAIT	D'160'
        movlw  	0x028            	; 4 bit, 2 Line, 5x7 font
        call   	SendINS
        movlw  	0x010            	; display shift off
        call   	SendINS
        movlw  	0x006            	; increment cursor
        call   	SendINS
        movlw  	0x00C            	; display on cursor off
        call   	SendINS
cls:
        movlw  	0x001            	; Clear the Display RAM
        call   	SendINS
        WAITms	D'5'            	; Note, Can take up to 4.1 msecs
        return

; ---------------------------------------------------------------------------
; LCD subroutine print string
; ---------------------------------------------------------------------------
printstr:
	movf   	TABLAT, w       	; get characters 
        btfsc  	STATUS, Z       	; if character = 0 then ...
        return				;                       ... exit
	call	SendCHAR      		; display character 
        tblrd*+				; TABLAT = next character
        bra    	printstr		; repeat

; ---------------------------------------------------------------------------
;                  Change binary nbr in bin to BCD                     
; ---------------------------------------------------------------------------
binary_to_bcd:                  	; by Scott Dattalo
         clrf 	hundreds
         swapf 	bin, W
         addwf 	bin, W
         andlw 	B'00001111'
         skpndc
         addlw 	0x16
         skpndc
         addlw 	0x06
         addlw 	0x06
         skpdc
         addlw 	-0x06
         btfsc 	bin,4
         addlw 	0x16 - 1 + 0x6
         skpdc
         addlw 	-0x06
         btfsc 	bin,5
         addlw 	0x30
         btfsc 	bin, 6
         addlw 	0x60
         btfsc 	bin,7
         addlw 	0x20
         addlw 	0x60
         rlcf 	hundreds, f
         btfss 	hundreds, 0
         addlw 	-0x60
         movwf 	tens_and_ones
         btfsc 	bin,7
         incf 	hundreds, f
         return

; ---------------------------------------------------------------------------
;                Display binary value in W in decimal  
; ---------------------------------------------------------------------------
DispDec:
         movwf 	bin
         call 	binary_to_bcd
         ; movf hundreds, W      	; Hondertallen zijn niet nodig 
         ; call SendASCII
         swapf 	tens_and_ones, W
         andlw 	H'F'
         call 	SendASCII
         movf 	tens_and_ones, W
         andlw 	H'F'
         call 	SendASCII
         return

; ---------------------------------------------------------------------------
;              Send the character in W out to the LCD                  
; ---------------------------------------------------------------------------
SendASCII
         addlw '0'              	; Send nbr as ASCII character
SendCHAR                        	; Send the Character to the LCD
         movwf  Temp            	; Save the Temporary Value
         swapf  Temp, w         	; Send the High Nybble
         bsf    RS              	; RS = 1
         call   NybbleOut
         movf   Temp, w         	; Send the Low Nybble
         bsf    RS
         call   NybbleOut
         return

;----------------------------------------------------------------------------
;              Send an instruction in W out to the LCD                 
;----------------------------------------------------------------------------
SendINS                        		; Send the Instruction to the LCD
        movwf  Temp            		; Save the Temporary Value
        swapf  Temp, w         		; Send the High Nybble
        bcf    RS              		; RS = 0
        call   NybbleOut
        movf   Temp, w         		; Send the Low Nybble
        bcf    RS
        call   NybbleOut
        return

;----------------------------------------------------------------------------
;              Send the nibble in W out to the LCD                     
;----------------------------------------------------------------------------
NybbleOut                       	; Send a Nybble to the LCD
        movwf   dummy           	; dummy = W
        bcf     D7        		; D7....D4 = dummy[3:0] 
        bcf     D6
        bcf     D5
        bcf     D4
        btfsc   dummy, 3
        bsf     D7
        btfsc   dummy, 2
        bsf     D6
        btfsc   dummy, 1
        bsf     D5
        btfsc   dummy, 0
        bsf     D4
	EStrobe                		; Strobe out the LCD Data
        WAIT	D'160'       		; delay for 160 usec
        return

;----------------------------------------------------------------------------
; Delay routines                                                       
;----------------------------------------------------------------------------
Wacht1s:
	WAITms	D'250'
	WAITms	D'250'
	WAITms	D'250'
	WAITms	D'250'
        return

Wachtms:
        movwf   delay
w2:
	WAIT 	D'1000'			; WAIT 1000µs = 1ms
        decfsz  delay, F
        goto    w2
        return

; ---------------------------------------------------------------------------
; Subroutines DS18B20
;	see <http://www.maximintegrated.com/en/app-notes/index.mvp/id/2420>
; ---------------------------------------------------------------------------
WAIT5U:
        ;This takes 5µs to complete
        NOP                             ; 1µs to process
        NOP                             ; 1µs to process
        DECFSZ 	TMP0,F          	; 1µs if not zero or 2µs if zero
        GOTO 	WAIT5U                  ; 2µs to process
        RETLW 0                         ; 2µs to process

OW_RESET:
        OW_HIZ                          ; Start with the line high
        CLRF    PDBYTE                  ; Clear the PD byte
        OW_LO
        WAIT    .500                    ; Drive Low for 500µs
        OW_HIZ
        WAIT    .70                     ; Release line and wait 70µs for PD Pulse
        BTFSS   PORTB,DQ                ; Read for a PD Pulse
        INCF    PDBYTE,F                ; Set PDBYTE to 1 if get a PD Pulse
        WAIT    .430                    ; Wait 430µs after PD Pulse
        RETLW   0

DSTXBYTE:                               ; Byte to send starts in W
        MOVWF	IOBYTE           	; We send it from IOBYTE
        MOVLW   .8
        MOVWF   COUNT            	; Set COUNT equal to 8 to count the bits
DSTXLP:
        OW_LO
        NOP
        NOP
        NOP                             ; Drive the line low for 3µs
        RRCF	IOBYTE,F
        BTFSC   STATUS,C                ; Check the LSB of IOBYTE for 1 or 0
        BSF     TRISB,DQ                ; HiZ the line  if LSB is 1
        WAIT    .60                     ; Continue driving line for 60µs
        OW_HIZ                          ; Release the line for pullup
        NOP
        NOP                             ; Recovery time of 2µs
        DECFSZ  COUNT,F                 ; Decrement the bit counter
        GOTO    DSTXLP
        RETLW   0

DSRXBYTE:                               ; Byte read is stored in IOBYTE
        MOVLW   .8
        MOVWF   COUNT                   ; Set COUNT equal to 8 to count the bits
DSRXLP:
        OW_LO
        NOP
        NOP
        NOP
        NOP
        NOP
        NOP                            	; Bring DQ low for 6µs
        OW_HIZ
        NOP
        NOP
        NOP
        NOP                             ; Change to HiZ and Wait 4µs
        MOVF	PORTB,W                 ; Read DQ
        ANDLW   1<<DQ                   ; Mask off the DQ bit
        ADDLW   .255                    ; C = 1 if DQ = 1: C = 0 if DQ = 0
        RRCF    IOBYTE,F                ; Shift C into IOBYTE
        WAIT    .50                     ; Wait 50µs to end of time slot
        DECFSZ  COUNT,F                 ; Decrement the bit counter
        GOTO    DSRXLP
        RETLW   0

; ---------------------------------------------------------------------------
; Strings used in the program
; ---------------------------------------------------------------------------
jan	 db " - Jan Wagemakers - ",0

; ---------------------------------------------------------------------------
; END
; ---------------------------------------------------------------------------
	END

Leave a Reply

Your email address will not be published. Required fields are marked *