;;;;;;; Thermocouple Calibrator ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This Program uses the Maxim MAX6674 MAX6675 Thermocouple-to-Digital Converters ; to display the temperature. It also allows for one or two point calibrations. ; ;;;;;;; Program hierarchy ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Mainline ; Initial ; InitLCD ; LoopTime ; DisplayC ; T40 ; ReadEEPROM ; WriteEEPROM ; BlinkAlive ; Pbutton ; Screens ; DisplayC ; T40 ; WriteEEPROM ; GetTemperature ; DisplayC ; T40 ; AdjustTemperatureVal ; ShiftRight ; FXM1608U ; FXD2416U ; FXM0808U ; FXD1608U ; FXD2408U ; DisplayTemperature ; FXD1608U ; DisplayV ; T40 ; DisplayUnit ; DisplayC ; T40 ; ChipSelect ; DisplayC ; T40 ; DisplayYesNo ; DisplayC ; T40 ; DisplayPoint ; DisplayC ; T40 ; Wait10Sec ; DisplayC ; T40 ; Average ; FXD1608U ; WriteEEPROM ; Calibrate ; GetTemperature ; DisplayC ; T40 ; AdjustTemperatureVal ; ShiftRight ; FXM1608U ; FXD2416U ; FXM0808U ; FXD1608U ; FXD2408U ; LoadFIFO ; LoopTime ; ; ; Pbutton ; Screens (etc.) ; LoopTime ; ;;;;;;; Assembler directives ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; list P=PIC18F452, F=INHX32, C=160, N=0, ST=OFF, MM=OFF, R=DEC, X=ON #include P18F452.inc __CONFIG _CONFIG1L, 0xFF ;Code protect off __CONFIG _CONFIG1H, _HS_OSC_1H & _OSCS_OFF_1H ;HS osc.; osc. switch disabled __CONFIG _CONFIG2L, _BOR_OFF_2L & _PWRT_ON_2L ;BOR disabled; PWRT enabled __CONFIG _CONFIG2H, _WDT_OFF_2H ;Watchdog timer disabled __CONFIG _CONFIG3H, _CCP2MX_ON_3H ;CCP2 to RC1 __CONFIG _CONFIG4L, 0x01;_LVP_OFF_4L ;Stack full/underflow reset enabled errorlevel -314, -315 ;Ignore lfsr messages ;;;;;;; Variables ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; cblock 0x000 ;Beginning of Access RAM TMR0LCOPY ;Copy of sixteen-bit Timer0 used by LoopTime TMR0HCOPY COUNT ;Counter available as local to subroutines TEMPLOCAL ;Temporary local variable ALIVECNT ;Counter for blinking "Alive" LED OLDPORTD ;Holds previous value of inputs DELRPG ;Generated by RPG RPGCNT ;Used to display RPG changes PBSTATE ;Control/status byte for pushbutton PBCOUNT ;Counter for measuring duration of press SCREEN ;State of LCD subroutine CALIBRATE ; bit 0: 0, Do not do calibration ; 1, Do calibration ; bit 1: 0, 1 point calibration ; 1, 2 point calibration ; bit 2: 0, ; 1, Calibrate freeze ; bit 3: 0, ; 1, Calibrate boil ; bit 4: 0, ; 1, Calibration in progress ; bit 5: 0, ; 1, Conversion done ; bit 6: 0, Farenheit units ; 1, Celcius units ; bit 7: 0, MAX6674 ; 1, MAX6675 CONVERSIONCOUNTER ; Count loop times for temperature conversion LOOPCOUNTER ; Cout looptimes to help with the 10 sec wait WAITCOUNTER ; Counts 10 1 sec waits CALIBRATIONOFFSET ; Calibration used from the freeze calibration CALIBRATIONRANGE ; Calibration used from the boil calibration TEMPERATUREL ; Low byte of the temperature TEMPERATUREH ; High byte of the temperature TEMPERATUREU ; Upper byte of the temperature DECSTR:8 ; Decimal display array of the temperature SHIFTVALUE ; Amount to shift the temperature variables FIFO:10 ; Array of the 5 most recent 2 byte temperature values CALIBRATEAVERAGEH ; High byte of the calibrate temperature value CALIBRATEAVERAGEL ; Low byte of the calibrate temperature value OLDTBLPTRH ; High byte of table pointer to return to OLDTBLPTRL ; Low byte of table pointer to return to endc #include ;;;;;;; Equates ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ISC equ 0 ;Initiate screen change for slow press ISA equ 1 ;Initiate secondary action for fast press PDONE equ 2 ;Pushbutton action has been taken OLDPB equ 3 ;Old state of pushbutton NEWPB equ 4 ;New state of pushbutton PBthres equ 30 ;Pushbutton threshold for a long press LoopCounterThr equ 100 ; 100 loop times is 1 second WaitTime equ 10 ; Total wait time is 10 seconds ConversionTime equ 20 FIFOSize equ 10 ;Number of bytes in the FIFO NumberOfScreens equ 6 ;Change this value if new screens are added ;;;;;;; Macro definitions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MOVLF macro literal,dest movlw literal movwf dest endm POINT macro stringname MOVLF high stringname, TBLPTRH MOVLF low stringname, TBLPTRL endm DISPLAY macro register movff register,BYTE call ByteDisplay endm TESTSCREEN macro literal movf SCREEN,W sublw literal endm DISPLAYONCE macro stringname btfss PBSTATE,ISC bra $+14 MOVLF high stringname, TBLPTRH MOVLF low stringname, TBLPTRL call DisplayC endm ;;;;;;; Vectors ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; org 0x0000 ;Reset vector nop goto Mainline org 0x0008 ;High priority interrupt vector bra $ ;Trap org 0x0018 ;Low priority interrupt vector bra $ ;Trap ;;;;;;; Mainline program ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Mainline rcall Initial ;Initialize everything LOOP_ btg PORTC,RC2 ;Toggle pin, to support measuring loop time rcall BlinkAlive ;Blink "Alive" LED rcall Pbutton ;Check pushbutton rcall Screens ;Deal with SCREEN state rcall LoopTime ;Make looptime be ten milliseconds decf LOOPCOUNTER, F ;This will be used in the 10 sec calibration routine decf CONVERSIONCOUNTER, F ;The 667x takes up to 180 ms to convert a temperature IF_ .B. ;If rolled over bsf CALIBRATE, 5 ; Set the conversion done bit after 200 ms ENDIF_ ENDLOOP_ ;;;;;;; Initial subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine performs all initializations of variables and registers. Initial MOVLF B'10001110',ADCON1 ;Enable PORTA & PORTE digital I/O pins MOVLF B'11100001',TRISA ;Set I/O for PORTA MOVLF B'11001100',TRISB ;Set I/O for PORTB MOVLF B'11110000',TRISC ;Set I/0 for PORTC MOVLF B'00001111',TRISD ;Set I/O for PORTD MOVLF B'00000000',TRISE ;Set I/O for PORTE MOVLF B'10001000',T0CON ;Set up Timer0 for a looptime of 10 ms MOVLF B'00010000',PORTA ;Turn off all four LEDs driven from PORTA rcall InitLCD ;Initialize LCD movff PORTD,OLDPORTD ;Initialize "old" value clrf RPGCNT ;Clear counter to be displayed MOVLF B'00001000',PBSTATE ;Initialize pushbutton state clrf PBCOUNT ;and pushbutton count MOVLF 1, SCREEN ;Initialize LCD's SCREEN variable POINT Block1 ; Set up the status bar characters rcall DisplayC POINT Block2 rcall DisplayC POINT Block3 rcall DisplayC POINT Block4 rcall DisplayC POINT Block5 rcall DisplayC POINT TemperatureStr ; Start on the temperature display rcall DisplayC MOVLF ConversionTime, CONVERSIONCOUNTER ; Initialize the conversion counter bsf PORTB, RB1 ; Set up the serial interface bsf PIR1, SSPIF MOVLF B'00100000', SSPCON1 MOVLF B'01000000', SSPSTAT clrf EECON1 ; Intialize data from EEPROM bsf PIR2, EEIF MOVLF B'11000000', INTCON1 MOVLF B'10000000', RCON rcall ReadEEPROM return ;;;;;;; InitLCD subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Initialize the Optrex 8x2 character LCD. ; First wait for 0.1 second, to get past display's power-on reset time. InitLCD MOVLF 10,COUNT ;Wait 0.1 second REPEAT_ rcall LoopTime ;Call LoopTime 10 times decf COUNT,F UNTIL_ .Z. bcf PORTE,0 ;RS=0 for command POINT LCDstr ;Set up table pointer to initialization string tblrd* ;Get first byte from string into TABLAT REPEAT_ bsf PORTE,1 ;Drive E high movff TABLAT,PORTD ;Send upper nibble bcf PORTE,1 ;Drive E low so LCD will process input rcall LoopTime ;Wait ten milliseconds bsf PORTE,1 ;Drive E high swapf TABLAT,W ;Swap nibbles movwf PORTD ;Send lower nibble bcf PORTE,1 ;Drive E low so LCD will process input rcall LoopTime ;Wait ten milliseconds tblrd+* ;Increment pointer and get next byte movf TABLAT,F ;Is it zero? UNTIL_ .Z. return ;;;;;;; T40 subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Pause for 40 microseconds or 40/0.4 = 100 clock cycles. ; Assumes 10/4 = 2.5 MHz internal clock rate. T40 movlw 100/3 ;Each REPEAT loop takes 3 cycles movwf COUNT REPEAT_ decf COUNT,F UNTIL_ .Z. return ;;;;;;;;DisplayC subroutine;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine is called with TBLPTR containing the address of a constant ; display string. It sends the bytes of the string to the LCD. The first ; byte sets the cursor position. The remaining bytes are displayed, beginning ; at that position. ; This subroutine expects a normal one-byte cursor-positioning code, 0xhh, or ; an occasionally used two-byte cursor-positioning code of the form 0x00hh. DisplayC bcf PORTE,0 ;Drive RS pin low for cursor-positioning code tblrd* ;Get byte from string into TABLAT movf TABLAT,F ;Check for leading zero byte IF_ .Z. tblrd+* ;If zero, get next byte ENDIF_ REPEAT_ bsf PORTE,1 ;Drive E pin high movff TABLAT,PORTD ;Send upper nibble bcf PORTE,1 ;Drive E pin low so LCD will accept nibble bsf PORTE,1 ;Drive E pin high again swapf TABLAT,W ;Swap nibbles movwf PORTD ;Write lower nibble bcf PORTE,1 ;Drive E pin low so LCD will process byte rcall T40 ;Wait 40 usec bsf PORTE,0 ;Drive RS pin high for displayable characters tblrd+* ;Increment pointer, then get next byte movf TABLAT,F ;Is it zero? UNTIL_ .Z. return ;;;;;;; DisplayV subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine is called with FSR0 containing the address of a variable ; display string. It sends the bytes of the string to the LCD. The first ; byte sets the cursor position. The remaining bytes are displayed, beginning ; at that position. DisplayV bcf PORTE,0 ;Drive RS pin low for cursor positioning code REPEAT_ bsf PORTE,1 ;Drive E pin high movff INDF0,PORTD ;Send upper nibble bcf PORTE,1 ;Drive E pin low so LCD will accept nibble bsf PORTE,1 ;Drive E pin high again swapf INDF0,W ;Swap nibbles movwf PORTD ;Write lower nibble bcf PORTE,1 ;Drive E pin low so LCD will process byte rcall T40 ;Wait 40 usec bsf PORTE,0 ;Drive RS pin high for displayable characters movf PREINC0,W ;Increment pointer, then get next byte UNTIL_ .Z. ;Is it zero? return ;;;;;;; BlinkAlive subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine briefly blinks the LED next to the PIC every two-and-a-half ; seconds. BlinkAlive bsf PORTA,RA4 ;Turn off LED decf ALIVECNT,F ;Decrement loop counter and return if not zero IF_ .Z. MOVLF 250,ALIVECNT ;Reinitialize BLNKCNT bcf PORTA,RA4 ;Turn on LED for ten milliseconds every 2.5 sec ENDIF_ return ;;;;;;; LoopTime subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine waits for Timer0 to complete its ten millisecond count ; sequence. It does so by waiting for sixteen-bit Timer0 to roll over. To obtain ; a period of precisely 10000/0.4 = 25000 clock periods, it needs to remove ; 65536-25000 or 40536 counts from the sixteen-bit count sequence. The ; algorithm below first copies Timer0 to RAM, adds "Bignum" to the copy ,and ; then writes the result back to Timer0. It actually needs to add somewhat more ; counts to Timer0 than 40536. The extra number of 12+2 counts added into ; "Bignum" makes the precise correction. Bignum equ 65536-25000+12+2 LoopTime REPEAT_ UNTIL_ INTCON,TMR0IF == 1 ;Wait until ten milliseconds are up bcf INTCON,GIE ;Disable all interrupts from CPU movff TMR0L,TMR0LCOPY ;Read 16-bit counter at this moment movff TMR0H,TMR0HCOPY movlw low Bignum addwf TMR0LCOPY,F movlw high Bignum addwfc TMR0HCOPY,F movff TMR0HCOPY,TMR0H movff TMR0LCOPY,TMR0L ;Write 16-bit counter at this moment bcf INTCON,TMR0IF ;Clear Timer0 flag bsf INTCON,GIE ;Reenable interrupts to CPU return ;;;;;;; RPG subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine decyphers RPG changes into values of DELRPG of 0, +1, or -1. ; DELRPG = +1 for CW change, 0 for no change, and -1 for CCW change. RPG clrf DELRPG ;Clear for "no change" return value movf PORTD,W ;Copy PORTD into W movwf TEMPLOCAL ; and TEMPLOCAL xorwf OLDPORTD,W ;Any change? andlw B'00000011' ;If not, set Z flag IF_ .NZ. ;If the two bits have changed then... rrcf OLDPORTD,W ;Form what a CCW change would produce IF_ .C. ;Make new bit 1 = complement of old bit 0 bcf WREG,1 ELSE_ bsf WREG,1 ENDIF_ xorwf TEMPLOCAL,W ;Did the RPG actually change to this output? andlw B'00000011' IF_ .Z. ;If so, then change DELRPG to -1 for CCW decf DELRPG,F ELSE_ ;Otherwise, change DELRPG to +1 for CW incf DELRPG,F ENDIF_ ENDIF_ movff TEMPLOCAL,OLDPORTD ;Save PORTD as OLDPORTD for ten ms from now return ;;;;;;; Pbutton subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine sorts out long and short pushbutton presses into two outputs: ; ISC=1: Initiate screen change for slow press ; ISA=1: Initiate secondary action for fast press ; PDONE=1 One of the above actions has occurred for this press Pbutton bcf PBSTATE,ISC ;Clear Initiate Screen Change bit (if set) bcf PBSTATE,ISA ;Clear Initiate Secondary Action bit (if set) IF_ PORTD,RD3 == 1 ;Copy pushbutton state to NEWPB bsf PBSTATE,NEWPB ELSE_ bcf PBSTATE,NEWPB ENDIF_ IF_ PBSTATE,OLDPB == 1 ;Look for leading edge (OLDPB=1, NEWPB=0) IF_ PBSTATE,NEWPB == 0 MOVLF PBthres,PBCOUNT ;Start counter ENDIF_ ENDIF_ IF_ PBSTATE,NEWPB == 0 ;Pushbutton is still pressed movf PBCOUNT,F IF_ .Z. ;and counter has passed threshold IF_ PBSTATE,PDONE == 0 ;and no action has yet been taken bsf PBSTATE,ISC ;Initiate screen change bsf PBSTATE,PDONE ;Done with pulse ENDIF_ ENDIF_ ELSE_ ;Pushbutton has been released bcf PBSTATE,PDONE ;so clear PDONE ENDIF_ IF_ PBSTATE,OLDPB == 0 ;Look for trailing edge (OLDPB=0, NEWPB=1) IF_ PBSTATE,NEWPB == 1 movf PBCOUNT,F IF_ .NZ. ;Fast pulse bsf PBSTATE,ISA ;Initiate secondary action ENDIF_ bcf PBSTATE,PDONE ;Done with pulse clrf PBCOUNT ;Finish counting ENDIF_ ENDIF_ movf PBCOUNT,F ;Has counter reached zero? IF_ .NZ. ;If not, then decrement it decf PBCOUNT,F ENDIF_ IF_ PBSTATE,NEWPB == 1 ;Copy NEWPB to OLDPB bsf PBSTATE,OLDPB ELSE_ bcf PBSTATE,OLDPB ENDIF_ return ;;;;;;; Screens subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine uses the ISC bit from the Pbutton subroutine to cycle the ; state of SCREEN and to take action based upon its value. ; Initially SCREEN=1. Subsequent PB switch ; presses cycle through SCREEN=2, 3, etc., recycling back to SCREEN=1. Screens IF_ PBSTATE,ISC == 1 incf SCREEN,F movlw NumberOfScreens+1 ;Check if past last screen subwf SCREEN,W IF_ .Z. ;Cycle back to SCREEN=1 MOVLF 1,SCREEN ENDIF_ POINT Clear1 ;Clear the display when switching screens rcall DisplayC POINT Clear2 rcall DisplayC bcf CALIBRATE, 2 bcf CALIBRATE, 3 bcf CALIBRATE, 4 ENDIF_ TESTSCREEN 1 IF_ .Z. DISPLAYONCE TemperatureStr bcf CALIBRATE, 0 ; reset the calibration flag to NO bcf CALIBRATE, 1 ; reset the 1 point calibration flag IF_ PBSTATE,ISA == 1 ; Fast pulse btg CALIBRATE, 6 ; Toggle the temperature measurement between F & C movlw B'11000000' andwf CALIBRATE, W movwf EEDATA MOVLF 0x01, EEADR rcall WriteEEPROM ENDIF_ IF_ CALIBRATE, 5 == 1 ; If conversion is done rcall GetTemperature ; Determine the temperature IF_ CALIBRATE, 6 == 0 ; Display in Farenheit movlw 32 ; Add 32 to the temperature addwf TEMPERATUREL, F clrf WREG addwfc TEMPERATUREH, F ENDIF_ rcall DisplayTemperature ; Display the temperature rcall DisplayUnit ; Display the units bcf CALIBRATE, 5 ; Clear the conversion done flag MOVLF ConversionTime, CONVERSIONCOUNTER ;Reset the conversion counter. ENDIF_ ENDIF_ TESTSCREEN 2 IF_ .Z. DISPLAYONCE ChipSelStr IF_ PBSTATE,ISA == 1 ; Fast pulse btg CALIBRATE, 7; ; Toggle the flag indicating which chip is being used movlw B'11000000' andwf CALIBRATE, W movwf EEDATA MOVLF 0x01, EEADR rcall WriteEEPROM ENDIF_ rcall ChipSelect ; Display the current chip ENDIF_ TESTSCREEN 3 IF_ .Z. DISPLAYONCE CalibrateStr IF_ PBSTATE,ISA == 1 ; Fast pulse btg CALIBRATE, 0 ; Toggle Yes or No Flag ENDIF_ rcall DisplayYesNo ; Display if the user wants to calibrate or not ENDIF_ TESTSCREEN 4 IF_ .Z. IF_ CALIBRATE, 0 == 0 ; Check to see if the user wants to calibrate MOVLF 1, SCREEN ; Reset the screen index DISPLAYONCE TemperatureStr ELSE_ ; if the user chose to calibrate DISPLAYONCE CalibrateStr rcall DisplayPoint ENDIF_ IF_ PBSTATE,ISA == 1 ; Fast pulse btg CALIBRATE, 1 ; Toggle the 1 or 2 point calibration flag ENDIF_ ENDIF_ TESTSCREEN 5 IF_ .Z. DISPLAYONCE CalibrateStr DISPLAYONCE FreezeStr DISPLAYONCE BeginStr IF_ PBSTATE,ISA == 1 ; Fast pulse IF_ CALIBRATE, 4 == 0 ; If calibration not in progress bsf CALIBRATE, 4 ; Set the Calibration In Progress flag bsf CALIBRATE, 2 ; Set the calibration flag for freeze clrf CALIBRATIONOFFSET ; Reset the offset movff CALIBRATIONOFFSET, EEDATA ; Save the new calibration to EEPROM MOVLF 0x02, EEADR rcall WriteEEPROM MOVLF 100, CALIBRATIONRANGE ; Reset the calibration range for a 1 point ; calibration movff CALIBRATIONRANGE, EEDATA ; Save the new calibration range to EEPROM MOVLF 0x03, EEADR rcall WriteEEPROM MOVLF WaitTime, WAITCOUNTER ; Reset the wait counter MOVLF LoopCounterThr, LOOPCOUNTER ; Reset teh loop counter POINT ClearBeginStr rcall DisplayC POINT Bar1 ; Start the progress bar rcall DisplayC movff TBLPTRH, OLDTBLPTRH movff TBLPTRL, OLDTBLPTRL ENDIF_ ENDIF_ IF_ CALIBRATE, 4 == 1 ; If the calibration is still in progress rcall Wait10Sec ; Continue the 10 sec wait ENDIF_ ENDIF_ TESTSCREEN 6 IF_ .Z. IF_ CALIBRATE, 1 == 0 ; Check for a 1 point calibration MOVLF 1,SCREEN ; Reset the screen index DISPLAYONCE TemperatureStr ELSE_ DISPLAYONCE CalibrateStr DISPLAYONCE BoilStr DISPLAYONCE BeginStr IF_ PBSTATE,ISA == 1 ; Fast pulse IF_ CALIBRATE, 4 == 0 ; If calibration not in progress bsf CALIBRATE, 4 ; Set the Calibration In Progress flag bsf CALIBRATE, 3 ; Set the calibration flag for boil MOVLF 100, CALIBRATIONRANGE ; Reset the calibration range movff CALIBRATIONRANGE, EEDATA ; Save the new calibration range to EEPROM MOVLF 0x03, EEADR rcall WriteEEPROM MOVLF WaitTime, WAITCOUNTER ; Reset the wait counter MOVLF LoopCounterThr, LOOPCOUNTER ; Reset teh loop counter POINT ClearBeginStr rcall DisplayC POINT Bar1 ; Start the progress bar rcall DisplayC movff TBLPTRH, OLDTBLPTRH ; Save table location for next movff TBLPTRL, OLDTBLPTRL ; status bar character ENDIF_ ENDIF_ IF_ CALIBRATE, 4 == 1 If calibration is still in progress rcall Wait10Sec ; Continue the 10 sec wait ENDIF_ ENDIF_ ENDIF_ return ;;;;;; GetTemperature Subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine handles the serial interface to the 6674x and sets the new ; value for TMEPERATUREH and TEMPERATUREL. ; GetTemperature bcf PORTB, RB1 ; Clear chip select bcf PIR1, SSPIF ; Clear the flag MOVLF 0xFF, SSPBUF ; Start the transfer REPEAT_ UNTIL_ PIR1, SSPIF == 1 ; Wait until transfer is complete movff SSPBUF, TEMPERATUREH ; First byte is the high byte bcf PIR1, SSPIF ; Clear the flag movff TEMPERATUREH, SSPBUF ; Start the trnsfer REPEAT_ UNTIL_ PIR1, SSPIF == 1 ; Wait until transfer is complete movff SSPBUF, TEMPERATUREL ; Second byte is the low byte bsf PORTB, RB1 ; Set the chip select IF_ TEMPERATUREL, 4 == 1 ; Check for open circuit POINT ErrorStr ; Display error message rcall DisplayC bcf CALIBRATE, 4 ; Cancel any calibrations ELSE_ rcall AdjustTemperatureVal ; Adjust the temperature value for ; calibrations and units F/C ENDIF_ return ;;;;;; AdjustTemperatureVal Subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine is used to take the binary value from the 667x and transform ; it into a real temperature complete with calibration corrections. ; AdjustTemperatureVal IF_ CALIBRATE, 7 == 0 ; 6674 chip MOVLF 5, SHIFTVALUE ; Set the number of places to shift ELSE_ MOVLF 3, SHIFTVALUE ENDIF_ rcall ShiftRight ; Shift the temperature data movff TEMPERATUREH, AARGB0 ; Make the temperature cover the entire movff TEMPERATUREL, AARGB1 ; range IF_ CALIBRATE, 7 == 0 ; 6674 chip IF_ CALIBRATE, 6 == 1 ; Display in Celcius MOVLF 125, BARGB0 ; Incremnts .125 degrees ELSE_ ; Display in Farenheit MOVLF 225, BARGB0 ; Increments .225 degrees, 32 will be added later ENDIF_ ELSE_ ; 6675 chip IF_ CALIBRATE, 6 == 1 ; Display in Celcius MOVLF 25, BARGB0 ; Increments .25 degrees ELSE_ ; Display in Farenheit MOVLF 45, BARGB0 ; Increments .45 degrees, 32 will be added later ENDIF_ ENDIF_ call FXM1608U IF_ CALIBRATE, 7 == 0 ; 6674 chip MOVLF 0x03, BARGB0 ; Divide by 1000 MOVLF 0xE8, BARGB1 ELSE_ ; 6675 chip clrf BARGB0 MOVLF 100, BARGB1 ; Divide by 100 ENDIF_ call FXD2416U movff AARGB1, TEMPERATUREH ; Save the result movff AARGB2, TEMPERATUREL ;; The following will use the calibration constants to adjust the temperature ;; measurement by the following equation --- ;; ;; Celcius -> temp = (temp from chip - CALIBRATIONOFFSET) * (100 / CALIBRATIONRANGE) ;; Farenheit -> temp = (temp from chip - CALIBRATIONOFFSET) * (180 / CALIBRATIONRANGEF IF_ CALIBRATE, 6 == 1 ; Display in Celcius movf CALIBRATIONOFFSET, W ELSE_ ; Display in Farenheit movff CALIBRATIONOFFSET, AARGB0 ; Adjust the calibration offset by 9/5 MOVLF 9, BARGB0 call FXM0808U MOVLF 5, BARGB0 call FXD1608U movf AARGB1, W ENDIF_ subwf TEMPERATUREL, F ; Subtract the calibration offset clrf WREG subwfb TEMPERATUREH, F IF_ .B. ; Limit minimum temp to 0 degrees clrf TEMPERATUREH clrf TEMPERATUREL ENDIF_ movff TEMPERATUREH, AARGB0 ; Load the math variables movff TEMPERATUREL, AARGB1 IF_ CALIBRATE, 6 == 1 ; Display in Celcius MOVLF 100, BARGB0 ; Multiply by 100 ELSE_ ; Display in Farenheit MOVLF 180, BARGB0 ; Multiply by 180 ENDIF_ call FXM1608U movff AARGB0, TEMPERATUREU ; Save the result movff AARGB1, TEMPERATUREH movff AARGB2, TEMPERATUREL IF_ CALIBRATE, 6 == 1 ; Display in Celcius movff CALIBRATIONRANGE, BARGB0 ELSE_ ; Display in Farenheit movff CALIBRATIONRANGE, AARGB0 ; Adjust the calibration range by 9/5 MOVLF 9, BARGB0 call FXM0808U MOVLF 5, BARGB0 call FXD1608U movff AARGB1, BARGB0 ENDIF_ movff TEMPERATUREU, AARGB0 movff TEMPERATUREH, AARGB1 movff TEMPERATUREL, AARGB2 call FXD2408U ; Divide by the calibration range movff AARGB1, TEMPERATUREH ; Set the new temperature movff AARGB2, TEMPERATUREL return ;;;;;; ShiftRight Subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine will shift the temperature data to the right due to ; the way the 667x sends the data to the PIC. ; ShiftRight REPEAT_ bcf STATUS, C ; Shift a 2 byte number to the right rrcf TEMPERATUREH, F rrcf TEMPERATUREL, F decf SHIFTVALUE, F UNTIL_ .Z. return ;;;;;; ChipSelect Subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine displays the chip in use, 6674 or 6675. ; ChipSelect IF_ CALIBRATE, 7 == 0 ; Check the current chip POINT Chip6674Str ELSE_ POINT Chip6675Str ENDIF_ rcall DisplayC ; Display the current chip return ;;;;;; DisplayYesNo Subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine displays the YES or NO choice for the user. ; DisplayYesNo IF_ CALIBRATE, 0 == 0 ; Check to see if the user wants to calibrate POINT NoStr ELSE_ POINT YesStr ENDIF_ rcall DisplayC ; Display choice for the user to view return ;;;;;; DisplayPoint Subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine displays the 1 or 2 point calibration choice. ; DisplayPoint IF_ CALIBRATE, 1 == 0 ; Check to see if the user chose 1 or 2 point calibration POINT OneStr ELSE_ ; 2 point calibration POINT TwoStr ENDIF_ rcall DisplayC ; Display the choice to the user POINT PointStr rcall DisplayC return ;;;;;; DisplayUnit Subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine displays the unit the user has chosen, F or C. ; DisplayUnit IF_ CALIBRATE, 6 == 0 ; If Farenheit POINT FarenheitStr ELSE_ ; If Celcius POINT CelsiusStr ENDIF_ rcall DisplayC ; Display temperature unit return ;;;;;; Calibrate Subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine gets the latest temperature values and loads ; the FIFO array that will be used to determine the new calibration ; data. ; Calibrate IF_ CALIBRATE, 5 == 1 ; If conversion is done IF_ CALIBRATE, 6 == 0 ; If in Farenheit mode bsf CALIBRATE, 6 ; Force to celcius call GetTemperature ; Determine temperature in celcius bcf CALIBRATE, 6 ; Reset to farenheit ELSE_ call GetTemperature ENDIF_ rcall LoadFIFO ; Load the FIFO bcf CALIBRATE, 5 ; Clear the conversion done flag MOVLF ConversionTime, CONVERSIONCOUNTER ;Reset the conversion counter. ENDIF_ return ;;;;;; LoadFIFO Subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine updates FIFO array with 2 byte numbers. ; LoadFIFO lfsr 0, FIFO + FIFOSize - 3 ; Set pointer to low byte of second to last number lfsr 1, FIFO + FIFOSize - 1 ; Set pointer to low byte of last number REPEAT_ movff POSTDEC0, POSTDEC1 ;Move the data to the right in the FIFO array incf FSR0L, W ;Done? sublw low FIFO UNTIL_ .Z. movff TEMPERATUREH, PREINC0 ; Load the latest temperature into the first 2 bytes movff TEMPERATUREL, PREINC0 ; of the FIFO, high byte first return ;;;;;; Average Subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine averages the temperature values located in the FIFO array. ; Average lfsr 0, FIFO + FIFOSize - 1 ; Set pointer to last byte of the FIFO clrf CALIBRATEAVERAGEL ; Reset the average clrf CALIBRATEAVERAGEH REPEAT_ movf POSTDEC0, W ; Load the low byte into W addwf CALIBRATEAVERAGEL, F ; Add to Average low movf POSTDEC0, W ; Load the high byte into W addwfc CALIBRATEAVERAGEH, F ; Add to Average high incf FSR0L, W ;Done? sublw low FIFO UNTIL_ .Z. movff CALIBRATEAVERAGEH, AARGB0 ; Load the math variables movff CALIBRATEAVERAGEL, AARGB1 movlw FIFOSize/2 ; Divide by number of 2 byte values in the FIFO movwf BARGB0 call FXD1608U return ;;;;;; Wait10Sec Subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; This subroutine waits 10 sec during calibrations before setting the new ; calibration limits. A status bar is diplayed to the screen while this ; function is being called. ; Wait10Sec movf LOOPCOUNTER, F IF_ .Z. ; Is 1 second up decf WAITCOUNTER ; Are 10 seconds up IF_ .Z. ; Yes bcf CALIBRATE, 4 ; Clear the calibration in progress bit POINT EndStr ; Let the user know calibration has completed rcall DisplayC IF_ CALIBRATE, 2 == 1 ; if freeze is done bcf CALIBRATE, 2 ; Reset the freeze calibration done flag rcall Average ; Average most recent temperatures movf AARGB1, W ; Move the new offset to W movwf CALIBRATIONOFFSET ; Set the new offset movff CALIBRATIONOFFSET, EEDATA ; Save the new calibration to EEPROM MOVLF 0x02, EEADR rcall WriteEEPROM MOVLF 100, CALIBRATIONRANGE ; Reset the calibration range for a 1 point ; calibration movff CALIBRATIONRANGE, EEDATA ; Save the new calibration range to EEPROM MOVLF 0x03, EEADR rcall WriteEEPROM ENDIF_ IF_ CALIBRATE, 3 == 1 ; if boil is done bcf CALIBRATE, 3 ; Reset the boil calibration done flag rcall Average ; Average most recent temperatures movf AARGB1, W ; Move the new range to W movwf CALIBRATIONRANGE ; Set the new range movff CALIBRATIONRANGE, EEDATA ; Save the new calibration range to EEPROM MOVLF 0x03, EEADR rcall WriteEEPROM ENDIF_ ELSE_ movff OLDTBLPTRH, TBLPTRH ; Reset the table pointer to the next status movff OLDTBLPTRL, TBLPTRL ; character MOVLF LoopCounterThr, LOOPCOUNTER ; Reset the loop counter incf TBLPTRL ; Get the next status bar character clrf WREG addwfc TBLPTRH,F rcall DisplayC ; Display status bar or 'END' movff TBLPTRH, OLDTBLPTRH ; Save the table pointer to the next status movff TBLPTRL, OLDTBLPTRL ; character ENDIF_ ENDIF_ rcall Calibrate ; Call the calibrate routine return ;;;;;; ReadEEPROM Subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Reads the EEPROM and initializes the RAM data to whatever is in the EEPROM ; addresses. On the very first time this function will initialize the EEPROM ; data. ; ReadEEPROM clrf EEADR bsf EECON1, RD ; Read the first location in EEPROM movf EEDATA, W xorlw B'10101010' ; Check for very first time IF_ .Z. ; Not first time MOVLF 0x01, EEADR ; Load the EEPROM address bsf EECON1, RD ; Set the read bit movff EEDATA, CALIBRATE ; Get last saved CALIBRATE MOVLF 0x02, EEADR ; Load the EEPROM address bsf EECON1, RD ; Set the read bit movff EEDATA, CALIBRATIONOFFSET ; Get last saved offset MOVLF 0x03, EEADR ; Load the EEPROM address bsf EECON1, RD ; Set the read bit movff EEDATA, CALIBRATIONRANGE ; Get last saved range ELSE_ ; Very first time MOVLF B'10101010', EEDATA ; Load in our first time number into address 0x00 MOVLF 0x00, EEADR ; Load the EEPROM address rcall WriteEEPROM ; Write to the EEPROM clrf CALIBRATE ; Set initial CALIBRATE movff CALIBRATE, EEDATA MOVLF 0x01, EEADR ; Load the EEPROM address rcall WriteEEPROM ; Write to the EEPROM clrf CALIBRATIONOFFSET ; Set intial OFFSET movff CALIBRATIONOFFSET, EEDATA MOVLF 0x02, EEADR ; Load the EEPROM address rcall WriteEEPROM ; Write to the EEPROM MOVLF 100, CALIBRATIONRANGE ; Set initial range movff CALIBRATIONRANGE, EEDATA MOVLF 0x03, EEADR ; Load the EEPROM address rcall WriteEEPROM ; Write to the EEPROM ENDIF_ return ;;;;;; WriteEEPROM Subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Writes whatever is in EEDATA to the address already loaded in EEADR. This ; is used for non volatile data. ; WriteEEPROM bcf PIR2, EEIF ; Set up the EEPROM for writing bsf EECON1, WREN ; Set the write enable bcf INTCON, GIEH ; Disable interrupts MOVLF 0x55, EECON2 ; Set the magic number MOVLF 0xAA, EECON2 bsf EECON1, WR ; Set the write bit REPEAT_ UNTIL_ PIR2, EEIF == 1 ; Wait until the writing is done bcf EECON1, WREN ; Clear the write enable bsf INTCON, GIEH ; Reenable interrupts return ;;;;;; DisplayDecimal Subroutine ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; Displays the temperature as a decimal number. ; DisplayTemperature lfsr 0,DECSTR+6 movff TEMPERATUREH, AARGB0 ; Get the temperature values ready movff TEMPERATUREL, AARGB1 ; to display MOVLF 10,BARGB0 ;Set the divisor REPEAT_ bsf PORTB, RB0 ;Toggle this pin to view with scope call FXD1608U ;Divide bcf PORTB, RB0 ;Toggle this pin to view with scope movf REMB0,W ;Put the remainder in the WREG iorlw 0x30 ;Convert to ASCII movwf POSTDEC0 ;Move ASCII code to string movf AARGB0, W ;Check for zero quotient iorwf AARGB1, W UNTIL_ .Z. movf FSR0L,W ;At the begining? sublw low DECSTR IF_ .NZ. REPEAT_ movlw 0x20 ;Load ASCII code for a space into WREG movwf POSTDEC0 ;Move the ASCCII code to the string movf FSR0L,W ;Done? sublw low DECSTR UNTIL_ .Z. ENDIF_ MOVLF 0xC0,INDF0 ;Add cursor position to the string clrf DECSTR+7 ;Add end-of-string terminator rcall DisplayV return ;;;;;;; Constant strings ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; LCDstr db 0x33,0x32,0x28,0x01,0x0c,0x06,0x00 ;Initialization string for LCD TemperatureStr db "\x80 TEMP \x00" ; Display TEMP title ChipSelStr db "\x80CHIP SEL\x00" ; Display chip selection title CalibrateStr db "\x80CALIBRAT\x00" ; Display caibrate title FarenheitStr db "\xC6\xDFF\x00" ; Display 'degree symbol'F CelsiusStr db "\xC6\xDFC\x00" ; Display 'degree symbol'C NoStr db "\xC0 NO\x00" ; Display NO choice YesStr db "\xC0 YES\x00" ; Display YES choice Chip6674Str db "\xC0 6674\x00" ; Display 6674 chip Chip6675Str db "\xC0 6675\x00" ; Display 6675 chip BeginStr db "\xC5BGN\x00" ; Let the user know calibration is ready to start ClearBeginStr db "\xC5 \x00" ; Clear the BeginStr EndStr db "\xC5END\x00" ; Let the user know calibration is done FreezeStr db "\x00\xC0FREZ \x00" ; Freeze calibration title BoilStr db "\x00\xC0BOIL \x00" ; Boil calibration title PointStr db "\x00\xC1 POINT \x00" ; For 1 or 2 point calibration choice OneStr db "\x00\xC01\x00" ; Write '1' to the screen TwoStr db "\x00\xC02\x00" ; Write '2' to the screen Clear1 db "\x80 \x00" ;Clear line 1 ; Clear top line of display Clear2 db "\xC0 \x00" ;Clear line 2 ; Clear bottom line of the display ErrorStr db "\xC0 ERROR \x00" ; Display error string ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; User defined characters to display a progress bar ;; ;; Block1 db 0x48, 0x80, 0x80, 0x90, 0x90, 0x90, 0x80, 0x80, 0x80, 0x00 Block2 db 0x50, 0x80, 0x80, 0x98, 0x98, 0x98, 0x80, 0x80, 0x80, 0x00 Block3 db 0x58, 0x80, 0x80, 0x9C, 0x9C, 0x9C, 0x80, 0x80, 0x80, 0x00 Block4 db 0x60, 0x80, 0x80, 0x9E, 0x9E, 0x9E, 0x80, 0x80, 0x80, 0x00 Block5 db 0x68, 0x80, 0x80, 0x9F, 0x9F, 0x9F, 0x80, 0x80, 0x80, 0x00 Bar1 db 0x00, 0xC6, 0x01, 0x00 Bar2 db 0x00, 0xC6, 0x02, 0x00 Bar3 db 0x00, 0xC6, 0x03, 0x00 Bar4 db 0x00, 0xC6, 0x04, 0x00 Bar5 db 0x00, 0xC6, 0x05, 0x00 Bar6 db 0xC6, 0x05, 0x01, 0x00 Bar7 db 0xC6, 0x05, 0x02, 0x00 Bar8 db 0xC6, 0x05, 0x03, 0x00 Bar9 db 0xC6, 0x05, 0x04, 0x00 Bar10 db 0xC6, 0x05, 0x05, 0x00 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; Math include files ;; ;; #include #include #include #include #include #include end