;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;                                                                                                  ;
;                        Program: DS18B20 Digital Thermometer with .1 Degree Increments            ;
;                        Author:  Jake Sutherland                                                  ;
;                        Start Date: Sunday 16th May 2010                                          ;
;                        Finish Date: Wednesday 20th October 2010                                  ;
;                                                                                                  ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
        LIST            P=PIC16F628A
        INCLUDE         P16F628A.INC
__CONFIG (0x3F38);
 cblock      20h
TEMPHI
TEMPLO
HUNS_ISR
TENS_ISR
ONES_ISR
HUNS
ONES
TENS
DIGIT
DELAYGPR1
W_ISR
S_ISR
P_ISR
F_ISR
FLAGS
SHIFT
COUNT
INDEX
COLUMN
TEMP
N
ENDC       
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;                                                                                                  ;
;                                   PIC16F628A Microcontroller                                     ;
;                                            ____ ____                                             ;
; LED 7 Segment 10's CC       VREF/AN2/RA2 -| 1  - 18 |- RA1/AN1              LED 7 Segment 1's CC ;
; LED 7 Segment 100's CC      CPM1/AN3/RA3 -| 2    17 |- RA0/AN0             LED 7 Segment .1's CC ;
; DS18B20 I/O               CMP2/T0CKI/RA4 -| 3    16 |- RA7/OSC1/CLKIN                            ;
;                             VPP/MCLR/RA5 -| 4    15 |- RA6/OSC2/CLKOUT                           ;
;                                      VSS -| 5    14 |- VDD                                       ;
; Segment DP                       INT/RB0 -| 6    13 |- RB7/T1OSC1/ICSPDAT              Segment B ;
; Segment C                      DT/RX/RB1 -| 7    12 |- RB6/T1OSCO/T1CLKI/ICSPCLK       Segment A ;
; Segment D                      CK/TX/RB2 -| 8    11 |- RB5                             Segment F ;
; Segment E                       CCP1/RB3 -|_9____10_|- RB4/PGM                         Segment G ;
;                                                                                                  ;
;                                                                                                  ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;::;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
        ORG     H'000'                  ; Processor reset vector location. On power up, the program jumps here
GOTO    SETUP                   ; 
ORG     H'004'                  ; Interrupt vector location. When an Interupt occurs, the program jumps here
  ; (Thanks Mike, K8LH for this ISR routine. Contact via Electro-Tech-Online.com)
  ; SAVE
        MOVWF   W_ISR                   ; Save W to W_ISR
        SWAPF   STATUS, W               ; Use SWAPF instruction so status bits don't change
        MOVWF   S_ISR                   ; Save Status to S_ISR
        CLRF    STATUS                  ; Switch to Bank 0
        MOVF    PCLATH, W               ; MOVE PCLATH to W register
        MOVWF   P_ISR                   ; Save PCLATH to P_ISR
        CLRF    PCLATH                  ; Force page 0
        MOVF    FSR, W                  ; MOVE FSR to W register
        MOVWF   F_ISR                   ; Save FSR to F_ISR

 TRIGER  BSF PORTA,0
        BSF PORTA,1
        BSF PORTA,2
DANIE_B
        CLRF    PORTB                   ; Blank the display
        MOVFW DIGIT
        ADDLW   HUNS_ISR                ; Add 'Digit' to 'HUNS' GPR address
        MOVWF   FSR                     ; FSR = HUNS + (0forHUNS, 1forTENS, 2forONES & 3forTENTHS) as they are in sequencial order in RAM
        MOVF    INDF, W                 ; W register now holds BCD Number Pointer for corresponding digit to be
        CALL    TABLE
        MOVWF PORTB
        INCF    DIGIT, F                ; Increment digit jump pointer (used when indirect addressing above)
        BCF STATUS,Z
        MOVFW DIGIT
        SUBLW .3
        BTFSC STATUS,Z
        CLRF DIGIT
DANIE_A    
        MOVFW INDEX
        ADDWF COLUMN,W
        CALL TABLE
        ANDWF   PORTA,F
        INCF INDEX,F
        BCF STATUS,Z
        MOVFW INDEX
        ADDWF COLUMN,W
        SUBLW .15
        BTFSC STATUS,Z
        CLRF INDEX 
; RESTORE
        BCF     PIR1, TMR2IF            ; Clear TMR2 interrupt flag while still in Bank 0        
        MOVF    F_ISR, W                ; MOVE F_ISR to W
        MOVWF   FSR                     ; Restore FSR
        MOVF    P_ISR, W                ; MOVE P_ISR to W
        MOVWF   PCLATH                  ; Restore PCLATH
        SWAPF   S_ISR, W                ; Undo previous SWAPF, place result in W
        MOVWF   STATUS                  ; Restore STATUS
        SWAPF   W_ISR, F                ; Use SWAPF instruction so status bits don't change
        SWAPF   W_ISR, W                ; Undo previous SWAPF and restore W register
        RETFIE                          ; Return From Interrupt
 

TABLE  ; This routine assigns on/off arrangement to the 7 Segment Display
       addwf PCL,F ; Содержимое счетчика команд PC увеличивается
retlw b'00111111' ; ..FEDCBA = 0 Происходит скачек по таблице
retlw b'00000110' ; .....CB. = 1 на строку со значением,
retlw b'01011011' ; .G.ED.BA = 2 записанным в аккумуляторе,
retlw b'01001111' ; .G..DCBA = 3 и далее - возврат по стеку.
retlw b'01100110' ; .GF..CB. = 4
retlw b'01101101' ; .GF.DC.A = 5
retlw b'01111101' ; .GFEDC.A = 6
retlw b'00000111' ; .....CBA = 7
retlw b'01111111' ; .GFEDCBA = 8
retlw b'01101111' ; .GF.DCBA = 9
RETLW   B'00000000' ;  10    -|-|-|-|-|-|-|-    BLANK
RETLW   B'01000000' ;  11    -|-|-|G|-|-|-|-      -
RETLW   B'11111011'; 12
RETLW   B'11111101'; 13
RETLW   B'11111110'; 14
RETURN

SETUP  ; This rountine sets up the Microcontroller's Inputs and Outputs
        MOVLW   H'07'                   ; Turn Comparators off and enable pins for I/O functions
        MOVWF   CMCON                   ;
        BSF     STATUS, RP0             ; Bank 1
        CLRF   TRISA                   ;
        CLRF    TRISB                   ; RB<7:0> Outputs
        BCF     STATUS, RP0             ; Bank 0
 
        CLRF    PORTA
        CLRF    PORTB

        MOVLW .12
        MOVWF COLUMN
        CLRF DIGIT
        CLRF INDEX
        CLRF    TMR2                    ; Clear TMR2 register
        BSF     STATUS, RP0             ; Bank 1
        MOVLW   B'00000010'             ;   00000010
        MOVWF   PIE1                    ;   -------0  Disable TMR1IE - TMR1 Overflow Interrupt Enable bit
                                        ;   ------1-  Enable  TMR2IE - TMR2 to PR2 Match Interrupt Enable bit
                                        ;   -----0--  Disable CCP1IE - CCP1 Interrupt Enable bit
                                        ;   ----X---  Unused
                                        ;   ---0----  Disable TXIE - USART Transmit Interrupt Enable bit
                                        ;   --0-----  Disable RCIE - USART Receive Interrupt Enable bit
                                        ;   -0------  Disable CMIE - Comparator Interrupt Enable bit
                                        ;   0-------  Disable EEIE - EE Write Complete Interrupt Enable bit
        BCF     STATUS, RP0             ; Bank 0
        CLRF    PIR1                    ; Clear Peripheral Interrupt Flags
        MOVLW   B'00000000'             ;   00000001
        MOVWF   T2CON                   ;   ------01  Prescale 1:4
                                        ;   -----0--  TMR2 OFF
                                        ;   -0000---  Postscale 1:1
                                        ;   0-------  Unused
        BSF     STATUS, RP0             ; Bank 1
        MOVLW   D'250'                  ; 
        MOVWF   PR2                     ; Interrupt every 0.001s or 1mS
        BCF     STATUS, RP0             ; Bank 0
        BSF     INTCON, GIE             ; Enable Global Interrupts
        BSF     INTCON, PEIE            ; Enable Peripheral Interrupts
        BSF     T2CON, TMR2ON           ; Start TMR2
 

GET_TEMP 
        CALL    DS18B20_RESET
        MOVLW   H'CC'                   ; Skiprom
        CALL    DS18B20_WRITE_BYTE      ; Skiprom
        MOVLW   H'44'                   ; Convert T
        CALL    DS18B20_WRITE_BYTE      ; Convert T
       
        CALL    DS18B20_READ_BIT        ; Initiate Read Time Slots
        BTFSS   STATUS, C               ; DS18B20 transmits a 0 while the temperature conversion is in progress and a 1 when the conversion is done.
        GOTO    $-D'2' 
        CALL    DS18B20_RESET           ; Reset
        MOVLW   H'CC'                   ; Skiprom
        CALL    DS18B20_WRITE_BYTE      ; Skiprom
        MOVLW   H'BE'                   ; Read Scratchpad
        CALL    DS18B20_WRITE_BYTE      ; Read Scratchpad
        CALL    DS18B20_READ_BYTE       ; Move Scrachpad Byte 0 to W
        MOVWF   TEMPLO                  ; Store in TEMPLO GPR
        CALL    DS18B20_READ_BYTE       ; Move Scrachpad Byte 1 to W
        MOVWF   TEMPHI                  ; Store in TEMPHI GPR

TEST_IF_NEGATIVE 		
        BCF     FLAGS, 1                ; Clear Negative Flag
        BTFSS   TEMPHI, 7               ; Test Negative Flag. If 1, Temperature is Negative
        GOTO    REARRANGE_NIBBLES       ; NOT Negative, skip over next 6 instructions (Don't Invert & + 1 (2's Complement))
 
  ; Invert & + 1                        ; EXAMPLE Negative Temperature                      TEMPHI = 1111 1110  TEMPLO = 0110 1110 = -25.1250 (see datasheet)
        BSF     FLAGS, 1                ; Set Negative Flag
        COMF    TEMPLO, F               ; Invert TEMPLO (when in Negative Temperature, the DS18B20 inverts the output so this inverts the register back so its positive)
        COMF    TEMPHI, F               ; Invert TEMPHI
        BCF     STATUS, Z               ; Clear Zero bit of STATUS register 
        INCF    TEMPLO, F               ; Increment TEMPLO to add .0625 (after inverting the register, the positive equivelent is .0625 more so this rectifies the negative value being .0625 short)
        BTFSC   STATUS, Z               ; Test Z bit of STATUS register to see if last instruction = 0000 0000
        INCF    TEMPHI, F               ; IS 0 (if TEMPLO overflowed to 0, increment TEMPHI once, if not, skip)
                                        ; EXAMPLE Negative Temperature AFTER Invert & + 1   TEMPHI = 0000 0001  TEMPLO = 1001 0010 = +25.1250
REARRANGE_NIBBLES
                                        ; EXAMPLE,   TEMPHI = 0000 0001  TEMPLO = 1001 0010
        MOVLW   B'11110000'             ; W = 1111 0000
        ANDWF   TEMPLO, W               ; F = 1001 0010   W = 1001 0000
        IORWF   TEMPHI, F               ; F = 0000 0001   F = 1001 0001
        SWAPF   TEMPHI, F               ; F = 1001 0001   F = 0001 1001 = New TEMPHI
        MOVLW   B'00001111'             ; W = 0000 1111
        ANDWF   TEMPLO, F               ; F = 1001 0010                       F = 0000 0010 = New TEMPLO
 
 
BIN_TO_DEC  ; This routine converts an 8-bit number to Decimal and stores the answer in 3 GPR's; HUNS, TENS & ONES
  ; HUNS holds amount of hundreds (i.e. 0000 0010 = 2x100), TENS holds amount of tens (i.e. 0000 0010 = 2x10) & ONES holds amount of ones (i.e. 0000 0101 = 5x1)
        INCF    TEMPHI                  ; Preload TEMPHI + 1
        CLRF    HUNS                    ; HUNS = 0000 0000
 
        MOVLW   D'246'                  ; MOVE Decimal'246' to W
        MOVWF   TENS                    ; TENS GPR = 1111 0101
        MOVWF   ONES                    ; ONES GPR = 1111 0101
        DECFSZ  TEMPHI, F               ; Decement TEMPHI register
        GOTO    $+D'2'                  ; NOT 0, skip next instruction
        GOTO    $+D'7'                  ; IS 0, TEMPHI = 0000 0000, skip next 6 instructions and calculate how many tens and hundreds
        INCFSZ  ONES, F                 ; Increment ONES register, skip if 0
        GOTO    $-D'4'                  ; NOT 0, GOTO here - 4 instructions
        INCFSZ  TENS, F                 ; IS 0, Increment TENS register skip if 0
        GOTO    $-D'7'                  ; GOTO here - 7 instructions & reset the ONES register to D'246'
        INCF    HUNS, F                 ; TENS overflowed, Increment HUNS
        GOTO    $-D'10'                 ; GOTO here - 10 instructions & reset the ONES and TENS registers to D'246'
 
        SUBWF   TENS, F                 ; W still holds D'246 so subract it from TENS register to determine how many 'TENS'
        SUBWF   ONES, F                 ; W still holds D'246 so subract it from ONES register to determine how many 'ONES'
 ; Leading zero suppression & minus (-) sign if Temperature Negative
        MOVF    HUNS, W                 ; Does HUNS equal 1 or 2? MOVF instruction affects Z bit of STATUS register 
        BTFSC   STATUS, Z               ; Test Z bit of STATUS register to see if HUNS = 0000 0000
        MOVLW   B'00001010'             ; Jump Pointer for blank arrangement
 
        BTFSC   FLAGS, 1                ; Is Temperature Negative?
        MOVLW   B'00001011'             ; YES, Jump Pointer for - arrangement
        MOVWF   HUNS                    ; 
 
        BTFSS   STATUS, Z               ; Test Z bit of STATUS register to see if HUNS = 0000 0000
        GOTO    $+D'5'                  ; HUNS is not, therefore do not blank TENS
        MOVF    TENS, W                 ; Does TENS equal 0?
        BTFSC   STATUS, Z               ; Test Z bit of STATUS register to see if last instruction = 0000 0000
        MOVLW   B'00001010'             ; Jump Pointer for blank arrangement
        MOVWF   TENS                    ; 
        
        BCF     INTCON, GIE
        MOVF    HUNS, W
        MOVWF   HUNS_ISR
        MOVF    TENS, W
        MOVWF   TENS_ISR
        MOVF    ONES, W
        MOVWF   ONES_ISR
        BSF     INTCON, GIE
GOTO GET_TEMP


DS18B20_RESET  ; This routine Resets the DS18B20
        CALL    DQ_HIZ
        CALL    DQ_LL                   ; Force the DQ Line to Logic Low
        MOVLW   (D'480'-5)/5            ; Reset pulse must be held a minimum of 480uS
        CALL    DELAY                   ; 
        CALL    DQ_HIZ                  ; Release DQ Line
        MOVLW   (D'60'-5)/5             ; Wait for recovery
        CALL    DELAY                   ;
        BTFSC   PORTA, 4                ; Test for 'Presence Pulse'
        GOTO    DS18B20_RESET           ; If not present, Reset
        MOVLW   (D'420'-5)/5            ; Must wait a minmum of 480uS from when DQ line is released before moving on
        CALL    DELAY                   ; 
        RETURN                          ;
DS18B20_WRITE_BYTE  ; This routine writes a byte of data to the DS18B20
        MOVWF   SHIFT                   ; MOVE data to shift into DS18B20 to SHIFT GPR
        MOVLW   D'08'                   ; Amount of bits to shift in
        MOVWF   COUNT                   ; Store in COUNT GPR
        RRF     SHIFT, F                ; Rotate valid data into Carry Flag
        CALL    DS18B20_WRITE_BIT       ; Write bit
        DECFSZ  COUNT, F                ; Decrement COUNT
        GOTO    $-D'3'                  ; If not zero, read next bit
        RETURN                          ; If zero, RETURN
 
DS18B20_WRITE_BIT  ; This routine writes one bit of data to the DS18B20
        BCF     INTCON, GIE
        CALL    DQ_LL                   ; Force the DQ Line to Logic Low
        BTFSS   STATUS, C               ; Test Carry Flag
        GOTO    $+D'2'                  ; If zero, leave DQ Line Logic Low
        CALL    DQ_HIZ                  ; If not zero, release DQ Line to Logic High
        MOVLW   (D'60'-5)/5             ; For delays from 10uS to 1285uS. Example, MOVLW D'10' for 10uS, MOVLW D'500' for 500uS 
        CALL    DELAY                   ; (D'n'-5)/5; n must be divisable by 5
        CALL    DQ_HIZ                  ; If not zero, release DQ Line to Logic High
        BSF     INTCON, GIE
        RETURN   

DS18B20_READ_BYTE  ; This routine reads a byte of data from the DS18B20
        MOVLW   H'08'                   ; Amount of bits to shift out
        MOVWF   COUNT                   ; Store in COUNT GPR
        CALL    DS18B20_READ_BIT        ; Read bit
        RRF     SHIFT, F                ; Rotate bit out of carry into SHIFT GPR
        DECFSZ  COUNT, F                ; Decrement COUNT
        GOTO    $-D'3'                  ; If not zero, read next bit
        MOVF    SHIFT, W                ; If zero, MOVE SHIFT GPR to W
        RETURN 
DS18B20_READ_BIT  ; This routine reads one bit of data from the DS18B20
        BCF     INTCON, GIE
        CALL    DQ_LL                   ; Force the DQ Line to Logic Low
        CALL    DQ_HIZ                  ; Release DQ Line
        BSF     STATUS, C               ; Preset Carry Flag
        BTFSS   PORTA, 4                ; Test DQ Line
        BCF     STATUS, C               ; If zero, Clear Carry Flag
        BSF     INTCON, GIE
        MOVLW   (D'60'-5)/5             ; Wait for Time Slot to end
        CALL    DELAY                   ; 
        RETURN                      
 
DQ_HIZ  ; This routine forces the DQ Line to an Input / High Impedance state
        BSF    PORTA,4
        BSF     STATUS, RP0             ; Bank 1
        BSF     TRISA, 4                ; Make Pin 3 an input, Pullup resistor forces line to logic 1, unless DS18B20 pulls it low
        BCF     STATUS, RP0             ; Bank 0
        
        RETURN
 
DQ_LL  ; This routine forces the DQ Line to Logic Low
        BCF     PORTA, 4                ; Clear output latch
        BSF     STATUS, RP0             ; Bank 1
        BCF     TRISA, 4                ; Make Pin 3 an output
        BCF     STATUS, RP0             ; Bank 0
        RETURN
 
DELAY  ; This routine can provide delays from 10uS to 1285uS depending on the number moved to the Working register prior to calling the delay
        MOVWF   DELAYGPR1               ; Move integer to GPR
        NOP                             ; No Operation
        NOP                             ; No Operation
        DECFSZ  DELAYGPR1, F            ; Decrement GPR and place back in itself
        GOTO    $-D'3'                  ; Not finished, GOTO here - 3 instructions
        RETURN                          ; Finished, Return




END
      