; ; Water System Controller ; ; Copyright (C) 1996, 1999 Allan N. Hessenflow, Los Gatos, California. ; ; Permission is granted to use this code or portions thereof for non- ; commercial purposes provided this copyright notice is preserved ; intact and credit is given to the author in any accompanying ; documentation. ; ; allanh@kallisti.com ; list c=80, f=INHX8M, p=16C74 __config _CP_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC include ; Program locs resetVector equ h'0000' ; Address of RESET Vector interruptVector equ h'0004' ; Address of Interrupt Vector ; Misc. constants OscFreq equ d'16000000' ; Oscillator Frequency is 16 MHz ; LCD memory locations lcdLine0 equ h'00' lcdLine1 equ h'40' ; PORTA bits pressure equ 0 ; pressure transducer serialDTR equ 4 ; handshake input ; PORTB bits #define wellPump1 PORTB,0 #define pressurePump PORTB,1 #define levelSwitch1 PORTB,2 #define levelSwitch2 PORTB,3 #define levelSwitch3 PORTB,4 #define levelSwitch4 PORTB,5 button1 equ 6 button2 equ 7 ; PORTC bits backlight equ 0 serialCTS equ 1 ; handshake output speaker equ 2 eepromClock equ 3 eepromData equ 4 #define wellPump2 PORTC,5 serialXmit equ 6 serialRecv equ 7 ; PORTD bits lcdData equ PORTD ; LCD data lines interface lcdDataTris equ TRISD ; PORTE bits #define lcdRS PORTE,0 ; LCD Register-Select control line #define lcdRW PORTE,1 ; LCD Read/Write control line #define lcdE PORTE,2 ; LCD Enable control line ; variables (bank 0) cblock h'20' savedW ; isr temp location - must have same ; address in bank 1 savedStatus ; isr temp location savedFSR ; isr temp location savedADCResult ; isr temp location lowByte ; isr temp highByte ; isr temp tempChannel ; isr temp ; some temp variables used in main code lowTemp highTemp lowTemp2 highTemp2 digit lcdTemp ; LCD subroutines internal use tableIndex ; Index to table strings count ; A counter delay ; Used in delayxxx routines xDelay ; Used in xDelayxxx routines ; following timers run at 7.6Hz pumpOnTimer ; minimum pump run time pumpOffTimer ; minimum pump relaxation time switchTimerLSB ; time between switching wells switchTimerMSB lastWell alarmTimer ; time between beeps for alarm beepTimer ; beep duration timer button1Timer ; button 1 debounce timer button2Timer ; button 2 debounce timer displayTimer ; status display update timer modeResetTimer ; reset mode to automatic after wantPressure ; want pressure pump on wantWells ; want wells on sampleCounter ; # of summed samples of each adc channel adcChannel ; current channel to digitize ; the following eight locations must be sequential sum0LSB ; sum adc channel 0, low byte sum0MSB ; sum adc channel 0, high byte sum1LSB ; sum adc channel 1, low byte sum1MSB ; sum adc channel 1, high byte sum2LSB ; sum adc channel 2, low byte sum2MSB ; sum adc channel 2, high byte sum3LSB ; sum adc channel 3, low byte sum3MSB ; sum adc channel 3, high byte ssum1LSB ; sum of squares channel 1 low byte ssum1 ; sum of squares channel 1 middle byte ssum1MSB ; sum of squares channel 1 high byte ssum2LSB ; sum of squares channel 2 low byte ssum2 ; sum of squares channel 2 middle byte ssum2MSB ; sum of squares channel 2 high byte ssum3LSB ; sum of squares channel 3 low byte ssum3 ; sum of squares channel 3 middle byte ssum3MSB ; sum of squares channel 3 high byte pressureLSB ; current pressure, low byte pressureMSB ; current pressure, high byte offset1 ; pump 1 current offset offset2 ; pump 2 current offset offset3 ; pump 3 current offset current1LSB ; pump 1 current LSB current1 ; pump 1 current middle byte current1MSB ; pump 1 current MSB current2LSB ; pump 2 current LSB current2 ; pump 2 current middle byte current2MSB ; pump 2 current MSB current3LSB ; pump 3 current LSB current3 ; pump 3 current middle byte current3MSB ; pump 3 current MSB time ; 15.625KHz timer newSampleValues ; new values available flag buttonsStoredState ; current button states button1Down ; button 1 pushed flag button2Down ; button 2 pushed flag endBank0 endc ; variables (bank 1) cblock h'a0' savedW2 ; isr temp location - must have same ; address in bank 0 endBank1 endc if ( endBank0 > h'80' ) messg "Warning: Out of space in bank 0" endif if ( endBank1 > h'100' ) messg "Warning: Out of space in bank 1" endif if ( savedW != (savedW2 & h'7f') ) messg "Warning: W save location not equivalent in both banks" endif ; Program start org resetVector reset goto start ; This is the Periperal Interrupt routine. org interruptVector ; Interrupt vector location interrupt movwf savedW ; save W; could be in either bank swapf STATUS,W bcf STATUS,RP0 ; change to bank 0 movwf savedStatus ; save status movf FSR,W movwf savedFSR btfsc PIR1,ADIF call handleADC btfsc PIR1,TMR2IF call handleTimer movf savedFSR,W movwf FSR swapf savedStatus,W ; get original status back movwf STATUS swapf savedW,F swapf savedW,W retfie handleADC movlw sum0LSB addwf adcChannel,W addwf adcChannel,W movwf FSR ; FSR is now index pointing at lsb of sum movf ADRES,W movwf savedADCResult bcf PIR1,ADIF addwf INDF,F incf FSR,F ; increment doesn't effect Carry btfsc STATUS,C incf INDF,F ; FSR now points to sumxMSB movf adcChannel,F ; check for channel 0 btfsc STATUS,Z return ; for pressure channel, we're done movlw offset1-1 ; -1 because we start at channel 1 addwf adcChannel,W movwf FSR ; we now point at offset for this channel movf savedADCResult,W subwf INDF,W ; subtract from offset btfss STATUS,C ; take absolute value xorlw h'ff' btfss STATUS,C addlw h'01' movwf savedADCResult movlw ssum1LSB-3 ; -3 because we start at channel 1 addwf adcChannel,W addwf adcChannel,W addwf adcChannel,W movwf FSR ; now point at LSB of sum of squares clrf highByte clrf lowByte movf savedADCResult,W bcf STATUS,C btfsc savedADCResult,0 addwf highByte,F rrf highByte,F rrf lowByte,F btfsc savedADCResult,1 addwf highByte,F rrf highByte,F rrf lowByte,F btfsc savedADCResult,2 addwf highByte,F rrf highByte,F rrf lowByte,F btfsc savedADCResult,3 addwf highByte,F rrf highByte,F rrf lowByte,F btfsc savedADCResult,4 addwf highByte,F rrf highByte,F rrf lowByte,F btfsc savedADCResult,5 addwf highByte,F rrf highByte,F rrf lowByte,F btfsc savedADCResult,6 addwf highByte,F rrf highByte,F rrf lowByte,F btfsc savedADCResult,7 addwf highByte,F rrf highByte,F rrf lowByte,F movf lowByte,W ; add 16 bit value to 24 bits addwf INDF,F incf FSR,F btfss STATUS,C goto noCarry incf INDF,F btfss STATUS,Z goto noCarry incf FSR,F incf INDF,F decf FSR,F noCarry movf highByte,W addwf INDF,F incf FSR,F btfsc STATUS,C incf INDF,F return handleTimer bcf PIR1,TMR2IF incf time,F btfsc time,0 bsf ADCON0,GO btfsc time,0 return ; bit 0 is set, so time!=0, so we're done ; update adc channel incf adcChannel,F btfsc adcChannel,2 clrf adcChannel swapf adcChannel,W movwf tempChannel bcf STATUS,C rrf tempChannel,W iorlw h'81' ; fosc/32 mode, not currently converting, operating movwf ADCON0 movf adcChannel,F btfss STATUS,Z goto doneWithADC incf sampleCounter,F btfss STATUS,Z goto doneWithADC ; copy values into final locations, zero sums movf sum0LSB,W ; pressure movwf pressureLSB clrf sum0LSB movf sum0MSB,W movwf pressureMSB clrf sum0MSB movf sum1MSB,W ; current motor 1 offset movwf offset1 clrf sum1MSB clrf sum1LSB movf sum2MSB,W ; current motor 2 offset movwf offset2 clrf sum2MSB clrf sum2LSB movf sum3MSB,W ; current motor 3 offset movwf offset3 clrf sum3MSB clrf sum3LSB movf ssum1LSB,W ; motor 1 current movwf current1LSB clrf ssum1LSB movf ssum1,W movwf current1 clrf ssum1 movf ssum1MSB,W movwf current1MSB clrf ssum1MSB movf ssum2LSB,W ; motor 2 current movwf current2LSB clrf ssum2LSB movf ssum2,W movwf current2 clrf ssum2 movf ssum2MSB,W movwf current2MSB clrf ssum2MSB movf ssum3LSB,W ; motor 3 current movwf current3LSB clrf ssum3LSB movf ssum3,W movwf current3 clrf ssum3 movf ssum3MSB,W movwf current3MSB clrf ssum3MSB bsf newSampleValues,0 doneWithADC movf time,F btfss STATUS,Z return ; do time==0 stuff movf button1Timer,F ; check button 1 btfss STATUS,Z goto timer1NotZero movf buttonsStoredState,W xorwf PORTB,W andlw h'40' btfsc STATUS,Z goto button1Done movlw h'40' xorwf buttonsStoredState,F movlw d'11' movwf button1Timer btfss buttonsStoredState,6 bsf button1Down,0 timer1NotZero decf button1Timer,F button1Done movf button2Timer,F ; now button 2 btfss STATUS,Z goto timer2NotZero movf buttonsStoredState,W xorwf PORTB,W andlw h'80' btfsc STATUS,Z return ; all done! movlw h'80' xorwf buttonsStoredState,F movlw d'11' movwf button2Timer btfss buttonsStoredState,7 bsf button2Down,0 timer2NotZero decf button2Timer,F return ; Initialize processor registers start ; As a general design guideline, we'll be leaving the processor in register ; bank 0. When we need to access bank 1, that piece of code will switch ; to bank 1 and back to 0 when done. ; The LCD data port will be left as outputs. ; bank 0 init clrf STATUS ; Do initialization, Select bank 0 clrf INTCON ; Clear int-flags, Disable interrupts clrf PCLATH ; Keep in lower 2KByte clrf ADCON0 clrf PORTA clrf PORTB clrf PORTC clrf PORTD clrf PORTE movlw h'20' ; zero all bank 0 general purpose memory movwf FSR initLoop1 clrf INDF incf FSR,F btfss FSR,7 goto initLoop1 movlw h'30' ; start time non-zero so button checking movwf time ; task won't coincide with grabbing values movlw h'80' ; start with reasonable starting values for offsets movwf offset1 movwf offset2 movwf offset3 ; bank 1 init bsf STATUS, RP0 ; Select bank 1 clrf PIE1 & h'7f' clrf PIE2 & h'7f' movlw h'3f' ; all inputs movwf TRISA&0x7f movlw h'fc' ; RB0-1 outputs, all others inputs movwf TRISB&0x7f movlw h'90' ; RC0-3,5,6 outputs, all others inputs movwf TRISC&0x7f movlw h'00' ; RD0-7 outputs movwf TRISD&0x7f movlw h'00' ; RE0-2 outputs movwf TRISE&0x7f movlw h'02' movwf ADCON1&0x7f ; RA0,1,2,5,3 analog inputs, vref==vdd bsf OPTION_REG&0x7f, NOT_RBPU ; Disable PORTB pull-ups ; we won't bother clearing bank 1; we ; don't have anything there yet that ; cares bcf STATUS, RP0 ; Select bank 0 call lcdInit bsf STATUS, RP0 ; Select bank 1 movlw h'ff' movwf PR2 & h'7f' ; maximum period on timer2/ccp1 bcf STATUS, RP0 ; Select bank 0 clrf TMR2 ; start at known state movlw h'04' movwf T2CON ; prescaler=postscaler=1 clrf CCPR1L ; minimum duty cycle movlw h'0c' movwf CCP1CON ; setup ccp1 as pwm bsf INTCON,PEIE bsf STATUS, RP0 ; Select bank 1 bsf PIE1&h'7f',TMR2IE bsf PIE1&h'7f',ADIE bcf STATUS, RP0 ; Select bank 0 bcf PIR1,ADIF bcf PIR1,TMR2IF ; clear pending interrupts bsf INTCON,GIE call lcdClear ; put status frame up movlw lcdLine0 call lcdSDDA call waitMessage ;debugLoop ; movlw h'ff' ; call xDelay500 ; 128ms ; movlw h'ff' ; call xDelay500 ; 128ms ; movlw h'ff' ; call xDelay500 ; 128ms ; movlw h'ff' ; call xDelay500 ; 128ms ; movlw lcdLine1 ; call lcdSDDA ; movf time,W ; call displayHex ; movlw lcdLine1+d'3' ; call lcdSDDA ; movf TMR2,W ; call displayHex ; movlw lcdLine1+d'6' ; call lcdSDDA ; movf T2CON,W ; call displayHex ; movlw lcdLine1+d'9' ; call lcdSDDA ; bsf STATUS,RP0 ; movf PR2&h'7f',W ; bcf STATUS,RP0 ; call displayHex ; movlw lcdLine1+d'12' ; call lcdSDDA ; bsf STATUS,RP0 ; movf PIE2&h'7f',W ; bcf STATUS,RP0 ; call displayHex ; movlw lcdLine1+d'15' ; call lcdSDDA ; movf INTCON,W ; call displayHex ; movlw lcdLine1+d'18' ; call lcdSDDA ; bsf STATUS,RP0 ; movf PIE1&h'7f',W ; bcf STATUS,RP0 ; call displayHex ; goto debugLoop waitLoop1 btfss newSampleValues,0 goto waitLoop1 ; wait for one set of values to be valid bcf newSampleValues,0 waitLoop2 btfss newSampleValues,0 goto waitLoop2 ; and a second one, just to be sure things are stable bcf newSampleValues,0 call lcdClear ; put status frame up movlw lcdLine0 call lcdSDDA call pumpStatusMessage movlw lcdLine1 call lcdSDDA call pressureStatusMessage mainLoop ; handle tone generation first, as it's the only really ; CPU time intensive part of the main code btfss newSampleValues,0 goto mainLoop ; everything from here on we only run at 7.6Hz bcf newSampleValues,0 movf pumpOffTimer,F btfss STATUS,Z decf pumpOffTimer,F movf pumpOnTimer,F btfss STATUS,Z decf pumpOnTimer,F movf switchTimerLSB,F btfss STATUS,Z goto switchNotZero movf switchTimerMSB,F btfss STATUS,Z goto switchNotZero goto doneWithSwitchTimer switchNotZero movf switchTimerLSB,F btfsc STATUS,Z decf switchTimerMSB,F decf switchTimerLSB,F doneWithSwitchTimer btfsc levelSwitch2 bcf wantWells,0 btfsc wantWells,0 goto leaveWellsAlone movf pumpOnTimer,F btfss STATUS,Z goto leaveWellsAlone btfss wellPump1 goto leaveWell1Alone bcf wellPump1 movlw h'6' movwf pumpOffTimer leaveWell1Alone btfss wellPump2 goto leaveWellsAlone bcf wellPump2 movlw h'6' movwf pumpOffTimer leaveWellsAlone btfsc levelSwitch2 goto bypassSwitch3 btfss levelSwitch3 bsf wantWells,0 bypassSwitch3 btfss wantWells,0 goto dontTurnWellsOn btfsc wantPressure,0 goto dontTurnWellsOn btfsc pressurePump goto dontTurnWellsOn movf pumpOffTimer,F btfss STATUS,Z goto dontTurnWellsOn btfsc wellPump1 goto notBothOff btfsc wellPump2 goto notBothOff movlw h'28' movwf pumpOnTimer movlw (d'6840'>>8) & h'ff' movwf switchTimerMSB movlw d'6840' & h'ff' movwf switchTimerLSB btfsc lastWell,0 goto lastWellWas2 bsf wellPump2 movlw h'28' movwf pumpOnTimer bsf lastWell,0 goto notBothOff lastWellWas2 bsf wellPump1 movlw h'28' movwf pumpOnTimer bcf lastWell,0 notBothOff movf switchTimerLSB,F btfss STATUS,Z goto dontTurnWellsOn movf switchTimerMSB,F btfss STATUS,Z goto dontTurnWellsOn bcf wellPump1 bcf wellPump2 movlw h'6' movwf pumpOffTimer dontTurnWellsOn btfss wantPressure,0 goto dontNeedPressure btfsc pressurePump goto dontNeedPressure btfss wellPump1 btfsc wellPump2 goto onePumpOn movf pumpOffTimer,F btfss STATUS,Z goto dontNeedPressure bsf pressurePump movlw h'28' movwf pumpOnTimer goto dontNeedPressure onePumpOn movf pumpOnTimer,F btfss STATUS,Z goto dontNeedPressure movlw h'6' movwf pumpOffTimer bcf wellPump1 bcf wellPump2 dontNeedPressure ; low setpoint 28723 ; high setpoint 39168 btfss levelSwitch4 goto disablePressure movlw (-d'28723'>>8) & h'ff' addwf pressureMSB,W btfsc STATUS,Z goto checkLowPointLSB btfss STATUS,C goto enablePressure goto checkHighPoint checkLowPointLSB ; check lsb movlw -d'28723' & h'ff' addwf pressureLSB,W btfsc STATUS,C goto checkHighPoint enablePressure bsf wantPressure,0 goto pressureDone checkHighPoint movlw (-d'39168'>>8) & h'ff' addwf pressureMSB,W btfsc STATUS,Z goto checkHighPointLSB btfsc STATUS,C goto disablePressure goto pressureDone checkHighPointLSB movlw -d'39168' & h'ff' addwf pressureMSB,W btfss STATUS,C goto pressureDone disablePressure bcf wantPressure,0 pressureDone btfsc wantPressure,0 goto pressureReallyDone btfss pressurePump goto pressureReallyDone movf pumpOnTimer,F btfss STATUS,Z goto pressureReallyDone bcf pressurePump movlw h'6' movwf pumpOffTimer pressureReallyDone ; only updating status display is left here incf displayTimer,F movlw h'03' andwf displayTimer,W btfss STATUS,Z goto mainLoop ; display pump status messages movlw lcdLine0+d'3' call lcdSDDA btfsc wellPump1 goto pump1Running call pumpOffMessage goto checkPump2 pump1Running call pumpRunMessage checkPump2 movlw lcdLine0+d'10' call lcdSDDA btfsc wellPump2 goto pump2Running call pumpOffMessage goto checkPump3 pump2Running call pumpRunMessage checkPump3 movlw lcdLine0+d'17' call lcdSDDA btfsc pressurePump goto pump3Running ; check for dry btfsc levelSwitch4 goto pressurePumpWet call pumpDryMessage goto checkPressure pressurePumpWet call pumpOffMessage goto checkPressure pump3Running call pumpRunMessage checkPressure movlw lcdLine1 ; display switch status call lcdSDDA movlw h'ff' btfss levelSwitch4 movlw ' ' call lcdPutChar movlw h'ff' btfss levelSwitch3 movlw ' ' call lcdPutChar movlw h'ff' btfss levelSwitch2 movlw ' ' call lcdPutChar movlw h'ff' btfss levelSwitch1 movlw ' ' call lcdPutChar movlw lcdLine1+d'12' call lcdSDDA movf pressureLSB,W movwf lowTemp movf pressureMSB,W movwf highTemp movlw -d'13107' & h'ff' ; take care of 1V offset addwf lowTemp,F btfsc STATUS,C incf highTemp,F movlw (-d'13107'>>8) & h'ff' addwf highTemp,F btfsc STATUS,C goto noBorrow clrf lowTemp clrf highTemp noBorrow clrf digit tensLoop movf lowTemp,W movwf lowTemp2 movf highTemp,W movwf highTemp2 movlw -d'5243' & h'ff' addwf lowTemp,F btfsc STATUS,C incf highTemp,F movlw (-d'5243'>>8) & h'ff' addwf highTemp,F btfss STATUS,C goto tensDone incf digit,F goto tensLoop tensDone movf lowTemp2,W ; get value back before underflow movwf lowTemp movf highTemp2,W movwf highTemp movf digit,W addlw '0' movf digit,F btfsc STATUS,Z movlw ' ' call lcdPutChar clrf digit onesLoop movf lowTemp,W movwf lowTemp2 movf highTemp,W movwf highTemp2 movlw -d'525' & h'ff' addwf lowTemp,F btfsc STATUS,C incf highTemp,F movlw (-d'525'>>8) & h'ff' addwf highTemp,F btfss STATUS,C goto onesDone incf digit,F goto onesLoop onesDone movf lowTemp2,W ; get value back before underflow movwf lowTemp movf highTemp2,W movwf highTemp movf digit,W addlw '0' call lcdPutChar movlw '.' call lcdPutChar clrf digit fracLoop movlw -d'53' & h'ff' addwf lowTemp,F btfsc STATUS,C incf highTemp,F movlw (-d'53'>>8) & h'ff' addwf highTemp,F btfss STATUS,C goto fracDone incf digit,F goto fracLoop fracDone movf digit,W addlw '0' call lcdPutChar goto mainLoop ; Stay in this loop forever pressureStatusMessage movlw high msg2 movwf PCLATH movlw 0 dispMsg2 movwf tableIndex call msg2 andlw h'ff' btfsc STATUS,Z goto pressureMessageEnd call lcdPutChar movf tableIndex,W addlw 1 goto dispMsg2 pressureMessageEnd return waitMessage movlw high msg4 movwf PCLATH movlw 0 dispMsg4 movwf tableIndex call msg4 andlw h'ff' btfsc STATUS,Z goto waitMessageEnd call lcdPutChar movf tableIndex,W addlw 1 goto dispMsg4 waitMessageEnd return pumpStatusMessage movlw high msg3 movwf PCLATH movlw 0 dispMsg3 movwf tableIndex call msg3 andlw h'ff' btfsc STATUS,Z goto pressureMessageEnd call lcdPutChar movf tableIndex,W addlw 1 goto dispMsg3 pumpStatusMessageEnd return displayHex movwf digit swapf digit,W andlw h'0f' call displayNibble movf digit,W andlw h'0f' displayNibble addlw h'f6' btfsc STATUS,C addlw 'a'-'0'-d'10' addlw '0'-h'f6' call lcdPutChar return pumpOffMessage movlw 'O' call lcdPutChar movlw 'f' call lcdPutChar movlw 'f' call lcdPutChar return pumpRunMessage movlw 'R' call lcdPutChar movlw 'u' call lcdPutChar movlw 'n' call lcdPutChar return pumpDryMessage movlw 'D' call lcdPutChar movlw 'r' call lcdPutChar movlw 'y' call lcdPutChar return ; lcdInit lcdInit ; Busy-flag is not yet valid bcf lcdRW bcf lcdRS bcf lcdE movlw h'1e' call xDelay500 ; 30 * 0.5mS = 15mS ; Busy Flag should be valid from here movlw h'38' ; 8-bit-interface, 2-lines call lcdPutCmd movlw h'00' ; disp.off, curs.off, no-blink call lcdDMode call lcdClear movlw h'04' ; disp.on, curs.off call lcdDMode movlw h'02' ; auto-inc (shift-cursor) call lcdEMode return ; lcdEnable ; Pulses LCD enable pin lcdEnable bsf lcdE ; LCD E-line High bcf lcdE ; LCD E-line Low return ; lcdBusy ; Returns when LCD busy-flag is inactive lcdBusy bsf STATUS,RP0 ; Select Register page 1 movlw h'ff' ; Set LCD data port for input movwf lcdDataTris&0x7f bcf STATUS, RP0 ; Select Register page 0 bcf lcdRS ; Set LCD for command mode bsf lcdRW ; Setup to read busy flag bsf lcdE ; LCD E-line High movf lcdData, W ; Read busy flag + DDram address bcf lcdE ; LCD E-line Low andlw h'80' ; Check Busy flag, High = Busy btfss STATUS, Z goto lcdBusy lcdNotBusy bcf lcdRW bsf STATUS, RP0 ; Select Register page 1 movlw h'00' movwf lcdDataTris&0x7f; Set PORTB for output bcf STATUS, RP0 ; Select Register page 0 return ; lcdClear ; Clears display and returns cursor to home position (upper-left corner). lcdClear movlw h'01' call lcdPutCmd return ; lcdHome ; Returns cursor to home position. ; Returns display to original position (when shifted). lcdHome movlw h'02' call lcdPutCmd return ; lcdEMode ; Sets entry mode of display. ; Required entry mode must be set in W ; b0 : 0 = no display shift 1 = display shift ; b1 : 0 = auto-decrement 1 = auto-increment ; b2-7 : don't care lcdEMode andlw h'03' ; Strip upper bits iorlw h'04' ; Function set call lcdPutCmd return ; lcdDMode ; Sets display control. ; Required display mode must be set in W ; b0 : 0 = cursor blink off 1 = cursor blink on ; b1 : 0 = cursor off 1 = cursor on ; b2 : 0 = display off 1 = display on (display data remains in DDRAM) ; b3-7 : don't care lcdDMode andlw h'07' ; Strip upper bits iorlw h'08' ; Function set call lcdPutCmd return ; lcdSCGA ; Sets Character-Generator-RAM address. CGRAM is read/written after ; this setting. ; Required CGRAM address must be set in W ; b0-5 : required CGRAM address ; b6-7 : don't care lcdSCGA andlw h'3f' ; Strip upper bits iorlw h'40' ; Function set call lcdPutCmd return ; lcdSDDA ; Sets the Display-Data-RAM address. DDRAM data is read/written after ; this setting. ; Required DDRAM address must be set in W ; b0-6 : required DDRAM address ; b7 : don't care lcdSDDA iorlw h'80' ; Function set call lcdPutCmd return ; lcdGAddr ; Returns address counter contents, used for both DDRAM and CGRAM. ; RAM address is returned in W lcdGAddr bsf STATUS,RP0 ; Select Register page 1 movlw h'ff' ; Set LCD data port for input movwf lcdDataTris&0x7f bcf STATUS, RP0 ; Select Register page 0 bcf lcdRS ; Set LCD for command mode bsf lcdRW ; Setup to read busy flag bsf lcdE ; LCD E-line High movf lcdData, W ; Read busy flag + RAM address bcf lcdE ; LCD E-line Low andlw h'7f' ; Strip upper bit bcf lcdRW bsf STATUS, RP0 ; Select Register page 1 movlw h'00' movwf lcdDataTris&0x7f; Set PORTB for output bcf STATUS, RP0 ; Select Register page 0 return ; lcdPutChar ; Sends character to LCD ; Required character must be in W lcdPutChar movwf lcdTemp ; Character to be sent is in W call lcdBusy ; Wait for LCD to be ready bcf lcdRW ; Set LCD in read mode bsf lcdRS ; Set LCD in data mode bsf lcdE ; LCD E-line High movf lcdTemp, W movwf lcdData ; Send data to LCD bcf lcdE ; LCD E-line Low return ; lcdPutCmd ; Sends command to LCD ; Required command must be in W lcdPutCmd movwf lcdTemp ; Command to be sent is in W call lcdBusy ; Wait for LCD to be ready bcf lcdRW ; Set LCD in read mode bcf lcdRS ; Set LCD in command mode bsf lcdE ; LCD E-line High movf lcdTemp, W movwf lcdData ; Send data to LCD bcf lcdE ; LCD E-line Low return delay500 movlw d'165' ; +1 1 cycle movwf delay ; +2 1 cycle delay500Loop decfsz delay, F ; step 1 1 cycle goto delay500Loop ; step 2 2 cycles movlw d'165' ; +1 1 cycle movwf delay ; +2 1 cycle delay500Loop2 decfsz delay, F ; step 1 1 cycle goto delay500Loop2 ; step 2 2 cycles movlw d'165' ; +1 1 cycle movwf delay ; +2 1 cycle delay500Loop3 decfsz delay, F ; step 1 1 cycle goto delay500Loop3 ; step 2 2 cycles movlw d'165' ; +1 1 cycle movwf delay ; +2 1 cycle delay500Loop4 decfsz delay, F ; step 1 1 cycle goto delay500Loop4 ; step 2 2 cycles delay500End return ; +3 2 cycles xDelay500 movwf xDelay ; +1 1 cycle xDelay500Loop call delay500 ; step1 wait 500uSec decfsz xDelay, F ; step2 1 cycle goto xDelay500Loop ; step3 2 cycles xDelay500End return ; +2 2 cycles msg2 addwf PCL,F dt " PSI", 0 msg2End equ $-1 if ( (msg2 & h'ff') >= (msg2End & h'ff') ) messg "Warning: Table 'msg2' crosses page boundary in computed jump" endif org ($+h'ff') & h'3f00' ; start at next page boundary msg3 addwf PCL,F dt "W1: W2: Pr:", 0 msg3End equ $-1 if ( (msg3 & h'ff') >= (msg3End & h'ff') ) messg "Warning: Table 'msg3' crosses page boundary in computed jump" endif msg4 addwf PCL,F dt "Wait...", 0 msg4End equ $-1 if ( (msg4 & h'ff') >= (msg4End & h'ff') ) messg "Warning: Table 'msg4' crosses page boundary in computed jump" endif end