
        LIST            P=PIC16F628A
        INCLUDE         P16F628A.INC
__CONFIG (0x3F38);

CBLOCK  H'20'
HUNS                                    ; BCD number pointer for HUNDREDS digit
TENS                                    ; BCD number pointer for TENS digit
ONES                                    ; BCD number pointer for ONES digit
TENTHS                                  ; BCD number pointer for TENTHS digit
HUNS_ISR                                ; BCD number pointer for HUNDREDS digit, used within ISR
TENS_ISR                                ; BCD number pointer for TENS digit, used within ISR
ONES_ISR                                ; BCD number pointer for ONES digit, used within ISR
TENTHS_ISR                              ; BCD number pointer for TENTHS digit, used within ISR
TEMPLO                                  ; BS18B20 Temperature Result Low Byte
TEMPHI                                  ; BS18B20 Temperature Result High Byte
COUNT                                   ; For counting execution times in various routines
SHIFT                                   ; For storing data to shift into and out of the DS18B20
COLSEL                                  ; Stores Column Select information 
DIGIT                                   ; Used for Indirect Addressing in Interrupt
DELAYGPR1                               ; Used in delay subroutines
FLAGS                                   ;   -------0  Unused
INDEX                                      ;   ------1-  Temperature Negative Flag (1 = True 0 = False)
COLUMN                                       ;   -----0--  Unused
                                       ;   ----0---  Unused
                                        ;   ---0----  Unused
                                        ;   --0-----  Unused
                                        ;   -0------  Unused
                                        ;   0-------  Unused
ENDC
W_ISR   EQU     H'70'                   ; For context saving. Ensures GPR is accesible from any Bank. See Memory Map of 628A
S_ISR   EQU     H'71'                   ; For context saving. Ensures GPR is accesible from any Bank. See Memory Map of 628A
P_ISR   EQU     H'72'                   ; For context saving. Ensures GPR is accesible from any Bank. See Memory Map of 628A
F_ISR   EQU     H'73'                   ; For context saving. Ensures GPR is accesible from any Bank. See Memory Map of 628A

 ORG     H'000'                  ; Processor reset vector location. On power up, the program jumps here
 GOTO    SETUP                   ; 
 
;--------------------------------------------------------------------------------------------------------------
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
        MOVLW   B'00010000'             ; RA<7:5><3:0> Output, RA<4> Input
        MOVWF   TRISA                   ;
        CLRF    TRISB                   ; RB<7:0> Outputs
        BCF     STATUS, RP0             ; Bank 0
 
        CLRF    PORTA
        CLRF    PORTB
        MOVLW .12
        MOVWF COLUMN
        CLRF DIGIT
        CLRF INDEX


GOTO GET_TEMP

  ; Dallas DS18B20 Temperature Sensor 'One Wire' Communication Routines
DS18B20_RESET  ; This routine Resets the DS18B20
        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_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
        
        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
       
        MOVLW   (D'60'-5)/5             ; Wait for Time Slot to end
        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
      
        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
     
        RETURN                          ; 
 
DQ_HIZ  ; This routine forces the DQ Line to an Input / High Impedance state
        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

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

;-------------------------------------------------------------------------------------------------------------------
GET_TEMP
        CALL    DS18B20_RESET           ; 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'                  ; Transmitting 0 therefore NOT done
 
        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

DISPLAY
        BSF PORTA,0
        BSF PORTA,1
        BSF PORTA,2

        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
   
        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
   
GOTO DISPLAY
;--------------------------------------------------------------------------------------
END