LIST P=PIC16F628A
INCLUDE P16F628A.INC
__CONFIG _CP_OFF & _CPD_OFF & _LVP_OFF & _BOREN_OFF & _MCLRE_OFF & _PWRTE_ON & _WDTE_OFF & _INTOSC_OSC_NOCLKOUT
ERRORLEVEL -302 ;Eliminate bank warning
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; PIC16F628A Microcontroller ;
; ____ ____ ;
; LCD ENABLE VREF/AN2/RA2 -| 1 - 18 |- RA1/AN1 LCD READ/WRITE ;
; LED Indicator CPM1/AN3/RA3 -| 2 17 |- RA0/AN0 LCD REGISTER SELECT ;
; 1-Wire Devices CMP2/T0CKI/RA4 -| 3 16 |- RA7/OSC1/CLKIN ;
; Power Down Detect VPP/MCLR/RA5 -| 4 15 |- RA6/OSC2/CLKOUT ;
; VSS -| 5 14 |- VDD ;
; LCD Data 4 INT/RB0 -| 6 13 |- RB7/T1OSC1/PGD TMR1 32.768KHz Xtal ;
; LCD Data 5 DT/RX/RB1 -| 7 12 |- RB6/T1OSCO/T1CLKI/PGC TMR1 32.768KHz Xtal ;
; LCD Data 6 CK/TX/RB2 -| 8 11 |- RB5 Push Button #2 ;
; LCD Data 7, LCD Busy Status CCP1/RB3 -|_9____10_|- RB4/PGM Push Button #1 ;
; ;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Notes
; If writing to LCD in main program loop, interrupts should be disabled as communication routines will be interrupted.
; RW RS
; L L Write Command Mode
; L H Write Character Data
; H L Read Busy Flag and Current Cursor Address
; H H Read Current Cursor Address Character Data
CBLOCK 0x20 ; Commence defining following constant block at RAM address 0x20 (LIMIT OF 80 BYTES IN BANK 1)
DELAYGPR1 ; Delay general purpose register
DELAYGPR2 ; Delay general purpose register
DELAYGPR3 ; Delay general purpose register
COUNT ; Loop counter
COUNT_ISR ; Loop counter within ISR
FLAGS ; -------0 LCD_RS_FLAG
; ------0- LCD_RW_FLAG
; -----0-- Temperature Negative Flag (0 = False 1 = True)
; ----0---
; ---0---- LCD display line 1 write flag
; --0----- LCD display line 2 write flag
; -0------ LCD display line 3 write flag
; 0------- LCD display line 4 write flag
BIN_2_BCD_LSB ; Binary to BCD conversion
HUNS ; BCD result register
TENS ; BCD result register
ONES ; BCD result register
DECI ; Jump pointer for Decimal digit
SECONDS ; Clock (Hour/Minute/Second Counter)
MINUTES ; Clock (Hour/Minute/Second Counter)
HOURS ; Clock (Hour/Minute/Second Counter)
SHIFT ; For storing data to shift into and out of the DS18B20
TEMPLO ; BS18B20 Celsius Temperature Result Low Byte
TEMPHI ; BS18B20 Celsius Temperature Result High Byte
LCD_DATA_TEMP ; Temporary storage for data to write to LCD
LCD_DISP_BUFFER_C1 ; LCD display buffer register
LCD_DISP_BUFFER_C2 ; LCD display buffer register
LCD_DISP_BUFFER_C3 ; LCD display buffer register
LCD_DISP_BUFFER_C4 ; LCD display buffer register
LCD_DISP_BUFFER_C5 ; LCD display buffer register
LCD_DISP_BUFFER_C6 ; LCD display buffer register
LCD_DISP_BUFFER_C7 ; LCD display buffer register
LCD_DISP_BUFFER_C8 ; LCD display buffer register
LCD_DISP_BUFFER_C9 ; LCD display buffer register
LCD_DISP_BUFFER_C10 ; LCD display buffer register
LCD_DISP_BUFFER_C11 ; LCD display buffer register
LCD_DISP_BUFFER_C12 ; LCD display buffer register
LCD_DISP_BUFFER_C13 ; LCD display buffer register
LCD_DISP_BUFFER_C14 ; LCD display buffer register
LCD_DISP_BUFFER_C15 ; LCD display buffer register
LCD_DISP_BUFFER_C16 ; LCD display buffer register
ENDC
CBLOCK 0x70 ; Ensures GPR is accessible from any Bank. See Memory Map of 628A. (LIMIT OF 16 BYTES)
W_ISR ; For context saving
S_ISR ; For context saving
P_ISR ; For context saving
F_ISR ; For context saving
EEPROM_ADDRESS ; Temporary storage for EEPROM Address
EEPROM_DATA ; Temporary storage for EEPROM Data
ENDC
LCD_DATA EQU PORTB ;
#DEFINE LCD_RS PORTA, 0 ;
#DEFINE LCD_RW PORTA, 1 ;
#DEFINE LCD_E PORTA, 2 ;
#DEFINE LCD_BUSY PORTB, 3 ; LCD busy flag is read on LCD DB7.
#DEFINE LCD_RS_FLAG FLAGS, 0 ;
#DEFINE LCD_RW_FLAG FLAGS, 1 ;
#DEFINE LCD_LINE_1 FLAGS, 4 ;
#DEFINE LCD_LINE_2 FLAGS, 5 ;
#DEFINE LCD_LINE_3 FLAGS, 6 ;
#DEFINE LCD_LINE_4 FLAGS, 7 ;
#DEFINE LED PORTA, 3 ;
#DEFINE PUSHBUTTON1 PORTB, 4 ;
#DEFINE PUSHBUTTON2 PORTB, 5 ;
ORG H'000' ; Processor reset vector location. On power up, the program jumps here
GOTO SETUP ;
ORG H'004' ; Interrupt vector location. When an Interrupt occurs, the program jumps here
; 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
TIMER1_ISR
FLASH_INDICATION_LED ; Place this code snippet in code to give led indication of code execution
BSF LED
CALL DELAY_50MS
BCF LED
; Timer 1 interrupt used for incrementing the real time clock registers
MOVLW B'10000000' ; Load number into upper byte of TMR1H:TMR1L so Timer 1 overflows once per second
MOVWF TMR1H ;
; Clock maths
; Increment Seconds
INCF SECONDS, F ; At 1 second intervals increment SECONDS register
; Check if seconds reached 60. Yes; Reset and increment Minutes. No; Done
MOVF SECONDS, W ;
SUBLW D'60' ;
BTFSS STATUS, Z ;
GOTO UPDATE_TIME_BUFFER ;
CLRF SECONDS ;
; Increment Minutes
INCF MINUTES, F ; At 60 second intervals increment MINUTES register
; Check if minutes reached 60. Yes; Reset and increment hours No; Done
MOVF MINUTES, W ;
SUBLW D'60' ;
BTFSS STATUS, Z ;
GOTO UPDATE_TIME_BUFFER ;
CLRF MINUTES ;
; Increment Hours
INCF HOURS, F ; At 60 minute intervals increment HOURS register
UPDATE_TIME_BUFFER
; Clear LCD buffer to clear address locations that aren't altered below
CALL LCD_CLEAR_BUFFER
; Update LCD buffer with seconds data
MOVF SECONDS, W
CALL BIN_2_BCD
MOVF ONES, W
CALL ASCII_DIGIT
MOVWF LCD_DISP_BUFFER_C12
MOVF TENS, W
CALL ASCII_DIGIT
MOVWF LCD_DISP_BUFFER_C11
; Update LCD buffer with minutes data
MOVF MINUTES, W
CALL BIN_2_BCD
MOVF ONES, W
CALL ASCII_DIGIT
MOVWF LCD_DISP_BUFFER_C9
MOVF TENS, W
CALL ASCII_DIGIT
MOVWF LCD_DISP_BUFFER_C8
; Update LCD buffer with hours data
MOVF HOURS, W
CALL BIN_2_BCD
MOVF ONES, W
CALL ASCII_DIGIT
MOVWF LCD_DISP_BUFFER_C6
MOVF TENS, W
CALL ASCII_DIGIT
MOVWF LCD_DISP_BUFFER_C5
; Update LCD buffer with other data
MOVLW A':' ; Load ASCII character of : to W
MOVWF LCD_DISP_BUFFER_C7 ; Store in Display general purpose registers and the display will be refreshed every time timer 2 triggers an interruts.
MOVWF LCD_DISP_BUFFER_C10 ;
BSF LCD_LINE_1 ; Tell program to write buffer contents to line 1 of the LCD display
CALL LCD_PRINT
TIMER1_ISR_DONE
BCF PIR1, TMR1IF ; Clear TMR1 interrupt flag
GOTO ISR_END
ISR_END
; RESTORE
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
; 7 Segment Display Arrangement Lookup
ASCII_DIGIT ; This table return the ASCII equivalent for a number
ADDWF PCL, F
RETLW A'0' ; B'00110000'
RETLW A'1' ; B'00110001'
RETLW A'2' ; B'00110010'
RETLW A'3' ; B'00110011'
RETLW A'4' ; B'00110100'
RETLW A'5' ; B'00110101'
RETLW A'6' ; B'00110110'
RETLW A'7' ; B'00110111'
RETLW A'8' ; B'00111000'
RETLW A'9' ; B'00111001'
RETLW A' ' ; B'00100000'
RETLW A'-' ; B'00101101'
RETURN
; Program Originates Here
SETUP ; This routine sets up the chips Inputs and Outputs
CLRF PORTA ; Initialise PORT A by setting output data latches
MOVLW H'07' ; Turn Comparators off and enable pins for I/O functions
MOVWF CMCON ;
BCF STATUS, RP1 ; Bank 1
BSF STATUS, RP0 ; Bank 1
MOVLW B'00110000' ; PORTA Inputs and Outputs
MOVWF TRISA ;
MOVLW B'11110000' ;
MOVWF TRISB ; PORTB Inputs and Outputs
BCF STATUS, RP1 ; Bank 0
BCF STATUS, RP0 ; Bank 0
ONE_OFF_INITIALISE
; Clear ALL Bank 0 RAM from 0X20 - 0X7F (96 bytes)
BCF STATUS, IRP ; Indirect addressing Bank 0/1
MOVLW H'20' ; Initialise pointer to RAM
MOVWF FSR ; (File Select Register)
CLRF INDF ; Clear Register indirectly
INCF FSR, F ; Increment pointer
BTFSS FSR, 7 ; All done?
GOTO $-D'3' ; No, Clear next byte
INITIALISE_LCD ;; START OF RECOMMENDED INITIALISATION FOR 4 BIT MODE (as per datasheet:)
CALL DELAY_5mS ;; Wait time > 15 ms after VDD > 4.5V
CALL DELAY_5mS ;;
CALL DELAY_5mS ;;
MOVLW b'00000011' ;; BF cannot be checked before this instruction. Function set (Interface is 8 bits length.)
MOVWF LCD_DATA ;;
CALL LCD_ENABLE ;;
CALL DELAY_5mS ;; Wait time > 4.1 ms
MOVLW B'00000011' ;; BF cannot be checked before this instruction. Function set (Interface is 8 bits length.)
MOVWF LCD_DATA ;;
CALL LCD_ENABLE ;;
CALL DELAY_5mS ;; Wait time > 100 us
MOVLW B'00000011' ;; BF cannot be checked before this instruction. Function set (Interface is 8 bits length.)
MOVWF LCD_DATA ;;
CALL LCD_ENABLE ;;
CALL LCD_CHECK_BUSY ;;
MOVLW B'00000010' ;; Function set ( Set interface to be 4 bits length) Interface is 8 bits length . BF can be checked after the following instructions.
MOVWF LCD_DATA ;;
CALL LCD_ENABLE ;;
CALL LCD_CHECK_BUSY ;;
MOVLW B'00101000' ;; Function set ( Interface is 4 bits length .Specify the number of the display lines and character font . )
CALL LCD_WRITE ;;
MOVLW B'00001100' ;; Display On/Off & Cursor
CALL LCD_WRITE ;;
MOVLW B'00000001' ;; Display clear
CALL LCD_WRITE ;; END OF RECOMMENDED INITIALISATION
MOVLW B'00000010' ;; Display & Cursor home
CALL LCD_WRITE ;;
INTERRUPT_CONFIG
; Setup TMR1 for 1s interrupt (32.768KHz crystal on RB6:7)
MOVLW B'00001110' ; R/W-POR State Bit Name: Bit Description - Setting
MOVWF T1CON ; -------0 R/W-0 TMR1ON: Timer1 On bit (0 = Stops Timer1)
; ------1- R/W-0 TMR1CS: Timer1 Clock Source Select bit (1 = External clock from pin RB6/T1OSO/T1CKI/PGC (on the rising edge))
; -----1-- R/W-0 T1SYNC: Timer1 External Clock Input Synchronization Control bit (1 = Do not synchronize external clock input)
; ----1--- R/W-0 T1OSCEN: Timer1 Oscillator Enable Control bit (1 = Oscillator is enabled)
; --00---- R/W-0 T1CKPS<1:0>: Timer1 Input Clock Prescale Select bits (00 = 1:1 Prescale value)
; 00------ R/W-0 Unimplemented: Read as ‘0’
BSF T1CON, TMR1ON ; Start TMR1
; Finalise interrupt configuration
BSF STATUS, RP0 ; Bank 1
BSF PIE1, TMR1IE ; -------1 Enable TMR1IE - TMR1 Overflow Interrupt Enable bit
BCF STATUS, RP0 ; Bank 0
CLRF PIR1 ; Clear all Peripheral Interrupt Flags
BSF INTCON, PEIE ; Enable Peripheral Interrupts
BSF INTCON, GIE ; Enable Global Interrupts
MAIN
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 Celsius TEMPLO GPR
CALL DS18B20_READ_BYTE ; Move Scrachpad Byte 1 to W
MOVWF TEMPHI ; Store in Celsius TEMPHI GPR
GOTO PROCESS_TEMPERATURE_DATA;
CALL DELAY_50mS
GOTO MAIN
BIN_2_BCD ; This routine converts the 8-bit number held in BCD_2_DEC_LSB to Decimal and stores it in 3 GPR's; HUNS, TENS & ONES
; These registers are then used as jump pointers for use with the display
MOVWF BIN_2_BCD_LSB
INCF BIN_2_BCD_LSB ; Pre-load low byte register + 1
CLRF HUNS ; HUNS = 0000 0000
MOVLW D'246' ; Move decimal '246' to W
RESET_TENS
MOVWF TENS ; TENS GPR = 1111 0101
RESET_ONES
MOVWF ONES ; ONES GPR = 1111 0101
DEC_ORIGINAL
DECFSZ BIN_2_BCD_LSB, F ; Decrement BIN_TO_BCD_LO register
GOTO INC_RESULT ; Not 0, GOTO INC_RESULT
GOTO ADJUST_RESULT ; Is 0, done, GOTO ADJUST_RESULT
INC_RESULT
INCFSZ ONES, F ; Increment ONES register, skip if 0 (overflow)
GOTO DEC_ORIGINAL ; Not 0, repeat decrement of original number
INCFSZ TENS, F ; Is 0, Increment TENS register skip if 0
GOTO RESET_ONES ; Not 0, repeat decrement of original number & reset the ONES register to D'246'
INCF HUNS, F ; TENS overflowed, Increment HUNS skip if 0
GOTO RESET_TENS ; Not 0, repeat decrement of original number & reset the ONES and TENS registers to D'246'
ADJUST_RESULT
SUBWF TENS, F ; W still holds D'246 so subtract it from TENS register to determine how many 'TENS' (0-9)
SUBWF ONES, F ; W still holds D'246 so subtract it from ONES register to determine how many 'ONES' (0-9)
RETURN
LCD_PRINT
BCF INTCON, GIE ; Prevent LCD communication from being interrupted
CALL LCD_CURSOR_SHIFT
BTFSS PIR1, TMR1IF ; Sneaky trick to check if currently in ISR or not as this routine is called in normal program as well as inside the ISR.
BSF INTCON, GIE ; Re-enable Global Interrupts if not already in ISR
RETURN
LCD_CURSOR_SHIFT
; Test which line of the LCD to write to by checking flags
MOVLW B'10000000' ; Line 1 address
BTFSC LCD_LINE_2 ; Flag
MOVLW B'11000000' ; Line 2 address
BTFSC LCD_LINE_3 ; Flag
MOVLW B'10010000' ; Line 3 address
BTFSC LCD_LINE_4 ; Flag
MOVLW B'11010000' ; Line 4 address
BCF LCD_RS ; Place LCD in command entry mode
CALL LCD_WRITE ; Send data to LCD
MOVLW B'00001111' ; Clear LCD line pointer flags
ANDWF FLAGS, F ;
LCD_WRITE_BUFFER
; Write 16 character buffer to LCD
MOVLW LCD_DISP_BUFFER_C1 ; Initialise pointer to RAM address
MOVWF FSR ; (File Select Register)
BSF LCD_RS ; Place LCD in character entry mode
CLRF COUNT ; Reset counter
MOVF INDF, W ; Move indirectly addressed registers contents to W
CALL LCD_WRITE ; Send data to LCD
INCF FSR, F ; Increment indirectly addressed register pointer
INCF COUNT, F ; Increment count
BTFSS COUNT, 4 ; Count 32?
GOTO $-D'5' ; No? Do again. Yes? Skip..
RETURN
LCD_CLEAR_BUFFER
; Initialise all 16x LCD_DISP_BUFFER_xx RAM with blank character
MOVLW LCD_DISP_BUFFER_C1 ; Initialise pointer to RAM
MOVWF FSR ; (File Select Register)
CLRF COUNT ; Reset counter
MOVLW A' '
MOVWF INDF ; Move indirectly addressed registers contents to W
INCF FSR, F ; Increment indirectly addressed register pointer
INCF COUNT, F ; Increment count
BTFSS COUNT, 4 ; Count 16?
GOTO $-D'5' ; No? Do again. Yes? Skip..
RETURN
LCD_WRITE
; 4 bit mode data write while maintaining state of upper 4 bits of PORTB
MOVWF LCD_DATA_TEMP ; Store data in temporary register for manipulation.
MOVLW B'11110000' ; Used to clear lower bits of PORTB (LCD Data lines)
ANDWF LCD_DATA, F ; Clear LCD Data lines leaving upper nibble unchanged
SWAPF LCD_DATA_TEMP, W ; Upper nibble of data to be sent first, so swap nibbles to upper is in lower
ANDLW B'00001111' ; Clear upper nibble
IORWF LCD_DATA, F ; Sent to PORTB0-3 (LCD Data lines) without changing upper half of PORTB
CALL LCD_ENABLE ; Latch data into LCD.
MOVLW B'11110000' ; Used to clear lower bits of PORTB (LCD Data lines)
ANDWF LCD_DATA, F ; Clear LCD Data lines leaving upper nibble unchanged
MOVF LCD_DATA_TEMP, W ; Lower nibble of data sent second, so first move data to W
ANDLW B'00001111' ; Mask upper nibble
IORWF LCD_DATA, F ; Sent to PORTB0-3 (LCD Data lines) without changing upper half of PORTB
CALL LCD_ENABLE ; Latch data into LCD.
CALL LCD_CHECK_BUSY ; Wait for LCD to
RETURN ;
LCD_ENABLE
BSF LCD_E ;
NOP ; Wait for tDA (320ns)
BCF LCD_E ;
RETURN
LCD_CHECK_BUSY
; PORTB, 3 / LCD DB7 to input
BSF STATUS, RP0 ; Bank 1
BSF LCD_BUSY ; TRISB, 7 make input
BCF STATUS, RP0 ; Bank 0
; Save RS & RW state
BTFSS LCD_RS ;
GOTO $+3 ;
BSF LCD_RS_FLAG ;
GOTO $+2 ;
BCF LCD_RS_FLAG ;
BTFSS LCD_RW ;
GOTO $+3 ;
BSF LCD_RW_FLAG ;
GOTO $+2 ;
BCF LCD_RW_FLAG ;
; Configure LCD to 'Read Status' mode and read busy flag
BCF LCD_RS ;
BSF LCD_RW ;
NOP ; Wait for tAS (140ns)
BSF LCD_E ;
NOP ; Wait for tDA (320ns)
BTFSC LCD_BUSY ;
GOTO $-1 ;
BCF LCD_E ;
; Restore RS & RW state
BTFSS LCD_RS_FLAG ;
GOTO $+3 ;
BSF LCD_RS ;
GOTO $+2 ;
BCF LCD_RS ;
BTFSS LCD_RW_FLAG ;
GOTO $+3 ;
BSF LCD_RW ;
GOTO $+2 ;
BCF LCD_RW ;
; PORTB, 3 / LCD DB7 back to output
BSF STATUS, RP0 ;
BCF LCD_BUSY ;
BCF STATUS, RP0 ;
RETURN
; 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'-D'5')/D'5' ; Reset pulse must be held a minimum of 480uS.
CALL DELAY ; For delays from 10uS to 1285uS. Example, MOVLW D'10' for 10uS, MOVLW D'500' for 500uS. (D'n'-D'5')/D'5'; n must be divisible by 5
CALL DQ_HIZ ; Release DQ Line
MOVLW (D'60'-D'5')/D'5' ; Wait for recovery
CALL DELAY ;
BTFSC PORTA, 4 ; Test for 'Presence Pulse'
GOTO DS18B20_RESET ; If not present, Reset
MOVLW (D'420'-D'5')/D'5' ; Must wait a minimum 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
BCF INTCON, GIE ; Disable Global Interrupts
CALL DQ_LL ; Force the DQ Line to Logic Low
CALL DQ_HIZ ; Release DQ Line
BSF STATUS, C ; Pre-set Carry Flag
BTFSS PORTA, 4 ; Test DQ Line
BCF STATUS, C ; If zero, Clear Carry Flag
BSF INTCON, GIE ; Enable Global Interrupts
MOVLW (D'60'-D'5')/D'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
BCF INTCON, GIE ; Disable Global Interrupts
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'-D'5')/D'5' ; Hold Logic Low, write 0
CALL DELAY ;
CALL DQ_HIZ ; If not zero, release DQ Line to Logic High, write 1
BSF INTCON, GIE ; Enable Global Interrupts
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, Pull-up 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
PROCESS_TEMPERATURE_DATA
BCF FLAGS, 2 ; Clear Negative Flag
BTFSS TEMPHI, 7 ; Test if Temperature is negative (2's complement format)
GOTO REARRANGE_DATA ; NOT Negative, skip 'Undo 2's Complement'
BSF FLAGS, 2 ; Set Negative Flag; used later
; Undo 2's Complement. When the Temperature is Negative, the DS18B20 outputs the 2's Complement. This routine converts the negative data into its positive equivalent
; Example Negative Temperature TEMPHI = 1111 1110 TEMPLO = 0110 1110 = -25.1250 (see datasheet)
COMF TEMPLO, F ; Invert TEMPLO
COMF TEMPHI, F ; Invert TEMPHI
INCFSZ TEMPLO, F ; Increment TEMPLO once; After inverting the data, add one to achieve equivalent positive number (see 2's complement)
GOTO $+D'2' ; No overflow skip next instruction
INCF TEMPHI, F ; Overflow occurred, increment upper byte
; Example Negative Temperature AFTER undo TEMPHI = 0000 0001 TEMPLO = 1001 0010 = +25.1250
REARRANGE_DATA ; This routine rearranges the 2 Temperature result bytes into usable data.
; EXPLANATION:
; * After the DS18B20 finishes a Temperature Conversion, the 12-bit result is stored in two 8-bit
; registers as a 16-bit sign-extended two?s complement number.
; * The 5 MSb's of the MSB (TEMPHI_C) indicate a negative or positive temperature.
; * The output data follows this format (12-bit resolution; 0.0625 degrees Celsius increments);
;
; SSSS SNNN : NNNN FFFF Where S = Sign (0 = Positive 1 = Negative)
; N = Number, &
; F = Fraction (16 X 0.0625 increments = 1)
;
; After communication with the DS18B20 the output data is held in two 8 bit registers called
; TEMPHI_C & TEMPLO_C in the following format TEMPHI_C = SSSS SNNN : TEMPLO_C = NNNN FFFF
;
; Example; 0000 0011 1001 0001 = (D'913' X 0.0625) = 57.0625 Degrees Celsius
;
; * This 6 instruction routine below rearranges the 4 nibbles of TEMPHI_C & TEMPLO_C so the data
; is easy to work with.
; * The MSB (TEMPHI_C) will be used for the 'whole' number i.e. 1's, 10's & 100's digits (57);
; and the LSB (TEMPLO_C) will be used for the decimal digit (.1's) with the upper nibble of the
; LSB masked. (These are in fact the sign bits, but we have already handled negative data and
; created a Flag (FLAGS, 2) for negative temperatures.
;
; Example above, after rearrangement 0011 1001 0000 0001 (see below)
;
; Example before; TEMPHI_C = 0000 0011 TEMPLO_C = 1001 0001 = 57.0625 Degrees Celsius
MOVLW B'11110000' ; W = 1111 0000
ANDWF TEMPLO, W ; F = 1001 0001 W = 1001 0000
IORWF TEMPHI, F ; F = 0000 0011 F = 1001 0011
SWAPF TEMPHI, F ; F = 1001 0011 F = 0011 1001 (New TEMPHI_C)
MOVLW B'00001111' ; W = 0000 1111
ANDWF TEMPLO, F ; F = 1001 0001 F = 0000 0001 (New TEMPLO_C)
; Example after; TEMPHI_C = 0011 1001 TEMPLO_C = 0000 0001
; = D'57' (X 1.0) = 57 = D'1' (X 0.0625) = 0.0625 = 57.0625 Degrees Celsius
REARRANGED_DATA_2_BCD
BCF INTCON, GIE ; Disable Interrupts
MOVF TEMPHI, W
MOVWF BIN_2_BCD_LSB
CALL BIN_2_BCD
FRACTION_ROUND ; This routine rounds the fraction portion of the Temperature data to the nearest .1
; Provided by & used with his permission from 'Pommy'. Contact via Electro-Tech-Online.com
; Examples
; TENTHS = Fraction * 10 / 16
; TENTHS = 00000100 ( D'4' * 0.0625 = 0.2500 Degrees C) * 10 / 16 = 3
; TENTHS = 00001001 ( D'9' * 0.0625 = 0.5625 Degrees C) * 10 / 16 = 6
; TENTHS = 00001101 (D'13' * 0.0625 = 0.8125 Degrees C) * 10 / 16 = 8
MOVLW B'00001111' ;
ANDWF TEMPLO, F ;
MOVF TEMPLO, W ;
ADDWF TEMPLO, F ; *2, C=0
RLF TEMPLO, F ; *4, C=0
ADDWF TEMPLO, F ; *5, C=0
RLF TEMPLO, F ; *10
MOVLW B'00001000' ;
ADDWF TEMPLO, F ; Rounding
SWAPF TEMPLO, W ; Pseudo divide by 16
ANDLW B'00001111' ;
MOVWF DECI ;
ZERO_SUPPRESS_AND_NEG_SIGN
; Leading zero suppression & minus (-) sign if Temperature Negative
MOVF HUNS, W ; MOVF instruction affects Z bit of STATUS register
BTFSC STATUS, Z ; Does HUNS = 0?
MOVLW D'10' ; Yes, jump Pointer for blank arrangement
BTFSC FLAGS, 2 ; Is Temperature Negative?
MOVLW D'11' ; Yes, jump Pointer for '-' arrangement
MOVWF HUNS ;
BTFSS STATUS, Z ; Does HUNS = not 0?
GOTO $+D'5' ; Yes, do not blank TENS
MOVF TENS, W ; MOVF instruction affects Z bit of STATUS register
BTFSC STATUS, Z ; Does TENS = 0?
MOVLW D'10' ; Yes, jump Pointer for blank arrangement
MOVWF TENS ;
CALL LCD_CLEAR_BUFFER
MOVF HUNS, W
CALL ASCII_DIGIT
MOVWF LCD_DISP_BUFFER_C1 ; LCD_DISP_ADDR_40
MOVF TENS, W
CALL ASCII_DIGIT
MOVWF LCD_DISP_BUFFER_C2 ; LCD_DISP_ADDR_41
MOVF ONES, W
CALL ASCII_DIGIT
MOVWF LCD_DISP_BUFFER_C3 ; LCD_DISP_ADDR_42
MOVF DECI, W
CALL ASCII_DIGIT
MOVWF LCD_DISP_BUFFER_C5 ; LCD_DISP_ADDR_44
; Write temperature to LCD
MOVLW A'.' ;
MOVWF LCD_DISP_BUFFER_C4 ;
MOVWF LCD_DISP_BUFFER_C12 ;
MOVLW H'DF' ;
MOVWF LCD_DISP_BUFFER_C6 ;
MOVWF LCD_DISP_BUFFER_C14 ;
MOVLW A'C' ;
MOVWF LCD_DISP_BUFFER_C7 ;
MOVWF LCD_DISP_BUFFER_C15 ;
BSF LCD_LINE_3 ; Set flag to print on line 1 of display
CALL LCD_PRINT
BSF INTCON, GIE ; Enable Interrupts
GOTO MAIN
DELAY_1S ; Actual delay = 1 seconds = 1000000 cycles 1/1 Second
MOVLW 0X07 ;
MOVWF DELAYGPR1 ;
MOVLW 0X2F ;
MOVWF DELAYGPR2 ;
MOVLW 0X03 ;
MOVWF DELAYGPR3 ;
DELAY_1S_0
DECFSZ DELAYGPR1, F ;
GOTO $+2 ;
DECFSZ DELAYGPR2, F ;
GOTO $+2 ;
DECFSZ DELAYGPR3, F ;
GOTO DELAY_1S_0 ; 999990 cycles
GOTO $+1 ;
GOTO $+1 ;
GOTO $+1 ; 6 cycles
RETURN ; 4 cycles (including call)
DELAY_50mS ; Actual delay = 0.05 seconds = 50,000 cycles 1/20 Second
MOVLW 0X0E ;
MOVWF DELAYGPR1 ;
MOVLW 0X28 ;
MOVWF DELAYGPR2 ;
DELAY_50mS_0 ;
DECFSZ DELAYGPR1, F ;
GOTO $+2 ;
DECFSZ DELAYGPR2, F ;
GOTO DELAY_50MS_0 ; 49993 cycles
GOTO $+1 ;
NOP ; 3 cycles
RETURN ; 4 cycles (including call)
DELAY_5mS ; Actual delay = 0.005 seconds = 5000 cycles 1/200 Second
MOVLW 0XE6 ;
MOVWF DELAYGPR1 ;
MOVLW 0X04 ;
MOVWF DELAYGPR2 ;
DELAY_5mS_0 ;
DECFSZ DELAYGPR1, F ;
GOTO $+2 ;
DECFSZ DELAYGPR2, F ;
GOTO DELAY_5mS_0 ; 4993 cycles
GOTO $+1 ;
NOP ; 3 cycles
RETURN ; 4 cycles (including call)
STOP GOTO STOP
END