 title  "Watermeter"
;
;
;
;  This Code Sends the data to the LCD in 4 Bit mode and
;   writes a welcome string on the display, than after a short while clears
;   the screen and boots up with the program. There are three views: 
;   view 0 is the main view showing a scale and a bar graph representing
;   the level of fluid in a container. View 1 shows the volume of the
;   fluid in liters and the voltage of the power supply in volts. View 2
;   is the setting mode which can be used to define the volume in liters
;   for each stripe on the bar graph. This value is stored in EEPROM.
;
;  The data is sent to the LCD module using six wires (4 data wires, the E
;   line and the RS line). The RW line is not used (permanently to ground) so
;   reading from the LCD is not possible (it is not necessary in this
;   application). For that reason, polling to see if the LCD is ready is
;   also not possible. That's why correct timing must be used before sending
;   the next command to the LCD.
;
;  One special feature of this device is that the LCD, normally designed for
;   horizontal operation, is used vertically! Therefore the program features
;   some kind of 'semi graphics engine' which allows to display characters
;   rotated 90°. This is done by making use of the character generator of the
;   LCD module. Only 8 characters at a time can be displayed rotated.
;
;
;
;  Hardware Notes for LCD:
;   Reset is tied directly to Vcc and PWRT is Enabled.
;   The PIC is a 16F873 Running at 4 MHz.
;   PortB.7 is the E line
;   PortB.6 is the RS line
;   PortB.0 -> 3 are the data lines D4 -> D7
;
;
; buttons: left = on/off    middle = view     right = set
;
;
; This program also makes use of the built-in AD converter of the
; PIC16F873.
; Voltage measurement: measures between 0.00V and 15.00V, precision 0.015V
; AD configuration: Vref- at Vss, Vref+ at Vdd.
; Input must be divided by means of voltage divider, with a factor 3.0.
;
; Water level measurement: Vref- at Vss, Vref+ at Vdd
;
;
; This program is designed for use with a 16 x 2 character LCD module with
; backlight. The power to the LCD module can be put on or off by the software.
; The same goes for the backlight (with use of a transistor).
;
;
; (C) Geert Van Espen 2001
;
;
#define NODEBUG

  LIST P=16F873, R=DEC          ;  16F873 Runs at 4 MHz
  errorlevel 0, -302, -307
  INCLUDE "p16f873.inc"

;**********************************************************************
;*                                                                    *
;*     Variables                                                      *
;*                                                                    *
;**********************************************************************
;  Register Usage
 CBLOCK 0x020                   ; Start Registers at End of the Values.

Dlay                            ; 8 Bit Delay Variable.
DlayI                           ; 8 Bit Delay Variable, only for interrupts.
DlayTemp                        ;
Temp:3                          ; Temporary Value Used When Sending Out Data.
NOTemp                          ; Temporary Value to "NybbleOutput".
CursorPosition                  ;
LoopCounter                     ;
LLoopCounter                    ;
offset                          ;
mode                            ;
view                            ;



;***********************************************************************
; variables for SetCursor

; local variables
scsr                            ;

;***********************************************************************
; variables for Graphics engine (functions LoadCHAR, LoadInvChar, Paint)

; parameters
gCursor                         ; Graphic cursor.

; local variables
gCount

;***********************************************************************
; variables for waterMeter

; parameters


; local variables
waterLevel
sensorCnt
showCount

;***********************************************************************
; variables for various show routines

; parameters


; local variables
shTemp

;***********************************************************************
; variables for timer service

; parameters
Seconds                         ;
vpbH                            ;
vpbL                            ;

elapsedSeconds:2                ;
elapsedSecondsB:2               ;
bShowFlags                      ; bit0=4 secs, bit1=2 secs, bit2=1 sec
                                ; bit3=0.5 secs

; local variables
TimerL                          ;
TimerH                          ;

;***********************************************************************
; variables for context saving during interrupt service
w_safe                          ;
status_safe                     ;
pclath_safe                     ;

;***********************************************************************
; variables for AddBCD

; parameters
BCD_A_0                         ;
BCD_A_1                         ;
BCD_A_2                         ;
BCD_A_3                         ;
BCD_B_0                         ;
BCD_B_1                         ;
BCD_B_2                         ;
BCD_B_3                         ;
result0                         ;
result1                         ;
result2                         ;
result3                         ;

;***********************************************************************
; variables for ByteToDec and AD2Voltage

; parameters
Asc0                            ;
Asc1                            ;
Asc2                            ;
Asc3                            ;

; local variables               ;
TempByte                        ;

;***********************************************************************
; variables for Ascii2Bin

;***********************************************************************
; variables for keyboard routine

; parameters
key                             ;

; local variables
bKbdPressed                     ;
keypad                          ;

;***********************************************************************
; variables for Div4823, Mul1616 and Mul2424

; parameters
Divisor:3                       ; msb first
Dividend:6                      ; msb first

Product:6                       ; msb first
Product32:4                     ; msb first
Multipland:3                    ; msb first


; local variables
BitCount                        ;


 ENDC


Multiplier EQU Product + 3      ; 3 bytes shared with Product's
                                ; less significant bytes (+3..5).

;**********************************************************************
;*                                                                    *
;*     Definitions                                                    *
;*                                                                    *
;**********************************************************************
#DEFINE LCD     PORTB
#DEFINE E       7
#DEFINE RS      6
#DEFINE POWER   2
#DEFINE BACKL   3

z       equ     2               ;
RBPU    equ     7               ;

#DEFINE KLOK    0x43

; Sensitivity can be adjusted here. The more sensitivity is needed,
; the lower the value should be. This value must be between D'1' and
; D'255'. A value of D'1' represents about 5 mV sensitivity.
; Example value: D'250' or D'187'
#DEFINE SENSITIVITY D'250'

;**********************************************************************
;*                                                                    *
;*     Macros                                                         *
;*                                                                    *
;**********************************************************************

EStrobe MACRO			;  Strobe the "E" Bit
  bsf	 LCD, E
  bcf	 LCD, E
 ENDM

fcall	macro subroutine_name
	local here
	lcall subroutine_name
	pagesel here
here:
	endm


bank0 macro
  bcf   STATUS, RP0             ;
  bcf   STATUS, RP1             ; Bank 0.
  endm

bank2 macro
  bsf   STATUS, RP1             ;
  bcf   STATUS, RP0             ; Bank 2.
  endm

magic   macro                           ; magic EEPROM write sequence
  movlw   55H                           ;
  movwf   EECON2^80H                    ;
  movlw   0AAH                          ;
  movwf   EECON2^80H                    ;
  endm


 PAGE
 __CONFIG _CP_OFF & _XT_OSC & _PWRTE_ON  & _WDT_OFF & _LVP_OFF
                                ;  Note that the WatchDog Timer is OFF
;

;
  org    0                      ;
  goto   init                   ;
;

  org    4                      ;
;**********************************************************************
;*                                                                    *
;*     01  Interrupts                  parent = xx  none              *
;*                                                                    *
;**********************************************************************
;
  movwf  w_safe                 ; Save context.
  swapf  STATUS, w              ;
  clrf   STATUS                 ;
  movwf  status_safe            ;
  movf   PCLATH, w              ;
  movwf  pclath_safe            ;
  clrf   PCLATH                 ; Jump to page 0.

  btfsc  INTCON, RBIF           ; Change on RB int?
  goto   RBWakeUpService        ; Yes, then service.
  btfsc  INTCON, T0IF           ; Timer int?
  goto   TimerService           ; Yes, then service.

; we are now on INT interrupt
  bcf    INTCON, INTE           ; Clear int mask.
  bcf    INTCON, INTF           ; Clear flag.
  retfie                        ; Return from int interrupt.

;**********************************************************************
;*                                                                    *
;*     TIMER interrupt                                                *
;*                                                                    *
;**********************************************************************
TimerService
; We are now on timer interrupt: indicate that we did service!
  bcf    INTCON, T0IE           ; Clear TMR0 int mask.
  bcf    INTCON, T0IF           ; Clear flag.

  incf   TimerL, f              ; Increment 16-bit low level counter.
  btfsc  STATUS, Z              ;
  incf   TimerH, f              ;
;3D0 27A 20E
;7A1 4F5 41D

  movlw  0x0e                   ; Test for half second break.
  subwf  TimerL, w              ;
  btfss  STATUS, Z              ;
  goto   HalfSecTest_af         ;
  movlw  0x02                   ;
  subwf  TimerH, w              ;
  btfss  STATUS, Z              ;
  goto   HalfSecTest_af         ;
  bsf    bShowFlags, 3          ; Mark 1/2 second interval.
HalfSecTest_af

;
  movlw  0x1d                   ;
  subwf  TimerL, w              ;
  btfss  STATUS, Z              ;
  goto   SecTest_af             ;
  movlw  0x04                   ;
  subwf  TimerH, w              ;
  btfss  STATUS, Z              ;
  goto   SecTest_af             ;
  clrf   TimerL                 ;
  clrf   TimerH                 ;
  incf   Seconds, f             ; Another second has gone by.

  movlw  1                      ; Decrement the timeout value for the
  subwf  elapsedSeconds + 1, f  ; power to the LCD module.
  btfss  STATUS, C              ;
  decf   elapsedSeconds, f      ;

  movlw  1                      ; Decrement the timeout value for the
  subwf  elapsedSecondsB + 1, f ; power to the backlight of the LCD
  btfss  STATUS, C              ; module.
  decf   elapsedSecondsB, f     ;

  bsf    bShowFlags, 2          ; Mark 1 second interval.
  bsf    bShowFlags, 3          ; Mark 1/2 second interval.

  btfsc  Seconds, 0             ; Are bit 0 and 1 of seconds cleared?
  goto   Correctie_af           ;
  bsf    bShowFlags, 1          ; Mark 2 second interval.
  btfsc  Seconds, 1             ;
  goto   Correctie_af           ;
  movlw  1                      ; Yes: boots low counter with 2.
  addwf  TimerL, f              ;
  bsf    bShowFlags, 0          ; Mark 4 second interval.

Correctie_af
  movlw  D'60'                  ; Now increment the Minutes and Hours if
  subwf  Seconds, w             ; necessary.
  btfss  STATUS, Z              ;
  goto   SecTest_af             ;
  clrf   Seconds                ;
SecTest_af


  movf   pclath_safe, w         ; Restore context.
  movwf  PCLATH                 ;
  swapf  status_safe, w         ;
  movwf  STATUS                 ;
  swapf  w_safe, f              ;
  swapf  w_safe, w              ;


  bsf    INTCON, T0IE           ; Set TMR0 int mask.

  retfie                        ; Return from timer interrupt.


;**********************************************************************
;*                                                                    *
;*     PORTB change interrupt                                         *
;*                                                                    *
;*                                                                    *
;*     Function: Indicates that a button is pressed. The main program *
;*               should check which one.                              *
;*                                                                    *
;*               If a button is pressed (RB4 or RB5), the boolean     *
;*               bKbdPressed is set to 1. It is the responsibility    *
;*               of the main program to check this boolean, then      *
;*               check which button is pressed, and finaly clear      *
;*               the boolean.                                         *
;*                                                                    *
;**********************************************************************
;
; This service is the only one that can wake up the processor
; from sleep mode.

#define KEYPORT PORTB



RBWakeUpService
  bcf    INTCON, RBIE           ; Clear mask.
  bcf    INTCON, RBIF           ; Clear flag.

  movf   KEYPORT, w             ; Read keypad.
  call   Dlay5i                 ; Debounce.
  movf   KEYPORT, w             ; Read keypad again.

  movlw  B'00001111'            ; On key press, go faster.
;  movwf  bShowFlags             ;

  bsf    bKbdPressed, 0         ; Indicate key pressed.


  movf   pclath_safe, w         ; Restore context.
  movwf  PCLATH                 ;
  swapf  status_safe, w         ;
  movwf  STATUS                 ;
  swapf  w_safe, f              ;
  swapf  w_safe, w              ;

  bsf    INTCON, RBIE           ; Set mask.


  retfie                        ; Return from interrupt.
;
;

;**********************************************************************
;*                                                                    *
;*     01  Program                     parent = xx  none              *
;*                                                                    *
;*     Function: main program.                                        *
;*                                                                    *
;*     params: none                                                   *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
init

  clrf   PORTA                  ; Do some initializations.
  clrf   PORTB                  ;
  clrf   PORTC                  ;

  clrf   waterLevel             ;
  clrf   TimerL                 ;
  clrf   TimerH                 ;
  clrf   Seconds                ;
  clrf   vpbH                   ;
  clrf   vpbL                   ;
  clrf   elapsedSeconds         ;
  movlw  D'60'                  ;
  movwf  elapsedSeconds + 1     ;
  clrf   elapsedSecondsB        ;
  movlw  D'60'                  ;
  movwf  elapsedSecondsB + 1    ;
  clrf   bKbdPressed            ;

  movlw  B'00001111'            ;
  movwf  bShowFlags             ;

  clrf   BCD_A_0                ;
  clrf   BCD_A_1                ;
  clrf   BCD_A_2                ;
  clrf   BCD_A_3                ;
  clrf   BCD_B_0                ;
  clrf   BCD_B_1                ;
  clrf   BCD_B_2                ;
  clrf   BCD_B_3                ;

  movlw  1                      ; Start in mode 1 (short time on).
  movwf  mode                   ;
  clrf   view                   ;

  clrf   PORTA                  ;
  clrf   PORTB                  ;
  clrf   PORTC                  ;

  bsf    STATUS, RP0            ; PortA all digital.
  movlw  0xD6                   ;
  movwf  ADCON1                 ;
  bcf    STATUS, RP0            ;

  movlw  B'00110011'            ; Enable RA0, 1, 4 and 5 input, rest output.
  bsf    STATUS, RP0            ;
  movwf  TRISA ^ 0x080          ;
  bcf    STATUS, RP0            ;

  movlw  B'00110000'            ; Enable RB4 and 5 for input, rest output.
  bsf    STATUS, RP0            ;
  movwf  TRISB ^ 0x080          ;
  bcf    STATUS, RP0            ;

  movlw  B'11111111'            ; Enable RC for input.
  bsf    STATUS, RP0            ;
  movwf  TRISC ^ 0x080          ;
  bcf    STATUS, RP0            ;

  bsf    PORTA, POWER           ; Put power for LCD on.
  bsf    PORTA, BACKL           ; Put backlight power for LCD on.

  call   Dlay250                ; Power on self test: this is
  bcf    PORTA, BACKL           ; just a little flikkering of the
  call   Dlay250                ; backlight.
  bsf    PORTA, BACKL           ;
  call   Dlay250                ;
  bcf    PORTA, BACKL           ;
  call   Dlay250                ;
  bsf    PORTA, BACKL           ;
  call   Dlay250                ;
  bcf    PORTA, BACKL           ;
post_af



; Set the timer.
  bsf    STATUS, RP0            ; Select page 1.
#ifdef DEBUG
  movlw  B'00000000'            ;
#else
  movlw  B'00000000'            ; Prescaler 1:2.
#endif
  movwf  OPTION_REG             ;
  bcf    OPTION_REG, RBPU       ; Enable pull up on RB port.
  bcf    STATUS, RP0            ; Select page 0.






;  clrf   TMR0                   ;
  bsf    INTCON, GIE            ; Globally allow interrupts.
  bsf    INTCON, T0IE           ; Enable timer interrupt.
  bsf    INTCON, RBIE           ; Enable interrupt on change.





; Initialize the keypad.
  movlw  0x10                   ; Indicate no key pressed.
  movwf  key                    ;

  call   WakeUp                 ; Do initializations same as after wake up from sleep.

  movlw  A'1'                   ; Debug info to the LCD display.
  call   SendCHAR               ;

  call   ee_init                ; Load last vpb.

  movlw  A'2'                   ; Debug info to the LCD display.
  call   SendCHAR               ;


  movlw	 0x001                  ; Clear the Display RAM.
  call   SendINS                ;
  call   Dlay5                  ; Note, can take up to 4.1 msecs.



  clrf   FSR                    ; Output the Message.
; Send demo string to the LCD.
OutLoop
  movf   FSR, w                 ;
  movwf  offset                 ;
  incf   offset, f              ;
  movlw  LOW Message            ; Get low bits of table.
  addwf  offset, f              ; Do an 8-bit add operation.
  movlw  HIGH Message           ; Get high 5 bits of table.
  btfsc  STATUS, C              ; Page crossed?
  addlw  1                      ; Yes: then increment high address.
  movwf  PCLATH                 ; Load high address in latch.
  movf   offset, w              ; Load computed offset in w register.
  incf   FSR, f                 ;
  call   Message                ;
  iorlw	 0                      ; At the End of the Message?
  btfsc	 STATUS, Z              ;
  goto   OutLoop_af             ; Yes - Equal to Zero.
  call   SendCHAR               ; Output the ASCII Character.
  goto   OutLoop                ;
OutLoop_af
  goto   skippy                 ;

Message                         ; Message to Output.
  movwf	 PCL                    ; Output the Characters.
  dt    "Watermeter", 0


skippy





; Leave the message for a short while on the screen.
  call   Dlay250                ;
  call   Dlay250                ;
  call   Dlay250                ;
  call   Dlay250                ;
leavemessage_af

;
  bcf    PORTA, BACKL           ; Put backlight power for LCD off.

MAIN_LOOP
; goto MAIN_LOOP
; Now the main loop is coming...
;
  clrf   CursorPosition         ;
  movlw	 0x001                  ; Clear the Display RAM.
  call   SendINS                ;
  call   Dlay5                  ; Note, can take up to 4.1 msecs.



Loop                            ; Loop Forever.

  movlw  0                      ;
  movwf  LLoopCounter           ; Inner loop for higher responsitivity to the keypad.
  movlw  2                      ;
  movwf  LoopCounter            ; Inner-inner loop for higher responsitivity to the keypad.
LLoop
;  call   Dlay160                ;

  movf   CursorPosition, w      ;
  call   SetCursor              ; Parameter in w.

; Show things on the screen.

  btfss  bShowFlags, 3          ; Show voltmeter only at 0.5 sec intervals.
  goto   svolt_af               ;
  call   ShowVoltmeter          ;
  call   ShowWater              ;
  bcf    bShowFlags, 3          ;
svolt_af

;  call   ShowVolumePerBar       ;
  call   ShowMode               ;

; Handle the keyboard.

  call   readButtons            ; Read the keyboard.
  btfsc  key, 4                 ; If no key pressed,
  goto   keypadtest_af          ; then stop testing the keyboard.



  btfss  key, 3                 ; If power to the pump, at least another
  goto   atleast_af             ; 5 minutes backlight and power.
  call   BackLightAtLeast300    ;
  call   PowerAtLeast300        ;
atleast_af


  movlw  1                      ;
  movwf  LoopCounter            ; On key press, go faster.
  movwf  LLoopCounter           ; On key press, go faster.
  movlw  B'00001111'            ; On key press, go faster.
  movwf  bShowFlags             ;

  btfss  key, 0                 ; Test if button 3 is pressed.
  goto   b3_released            ;
  incf   CursorPosition, f      ; Yes, increment clock cursor.
  call   TopAfElapsed           ; At each button pressed, renew the timeout values.

  movlw  1                      ; First time button 3, engage set view (view 2).
  subwf  CursorPosition, w      ;
  btfss  STATUS, Z              ;
  goto   setm_af                ;
  movlw  2                      ;
  movwf  view                   ;
  movlw	 1                      ; clear the Display RAM.
  call   SendINS                ;
  call   Dlay5                  ; Note, can take up to 4.1 msecs.
setm_af

b3_checkrelease
  btfss  key, 0                 ; Wait for button 3 to be released.
  goto   b3_released            ;
  call   readButtons            ;
  goto   b3_checkrelease        ;
b3_released
  
  movlw  4                      ; Test for overflow of the cursor.
  subwf  CursorPosition, w      ;
  btfss  STATUS, Z              ;
  goto   ovf_af                 ;
  clrf   view                   ; Overflow: leave set view.
  movlw	 1                      ; clear the Display RAM.
  call   SendINS                ;
  call   Dlay5                  ; Note, can take up to 4.1 msecs.
  call   LoadFont               ;
ovf_af

  movlw  2                      ; If we are not in view 2, then
  subwf  view, w                ;
  btfss  STATUS, Z              ; the cursor should always be 0.
  clrf   CursorPosition         ;

  btfss  key, 1                 ; Test if middle button is pressed.
  goto   middle_af              ;

  call   TopAfElapsed           ; At each button pressed, renew the timeout values.

b2_checkrelease
  btfss  key, 1                 ; Wait for button 2 to be released.
  goto   b2_released            ;
  call   readButtons            ;
  goto   b2_checkrelease        ;
b2_released                     ;
  movlw  2                      ; Ignore middle key during setting mode.
  subwf  view, w                ;
  btfsc  STATUS, Z              ;
  goto   middle_af              ;

                                ; This is a view change, so
  movlw	 1                      ; clear the Display RAM.
  call   SendINS                ;
  call   Dlay5                  ; Note, can take up to 4.1 msecs.
  incf   view, f                ;
  movlw  2                      ;
  subwf  view, w                ;
  btfss  STATUS, Z              ;
  goto   middle_af              ;
  clrf   view                   ;
  call   LoadFont               ;


middle_af


  btfss  key, 2                 ; Test if button 1 is pressed.
  goto   set_af                 ;

  call   TopAfElapsed           ; At each button pressed, renew the timeout values.

b1_checkrelease
  btfss  key, 2                 ; Wait for button 1 to be released.
  goto   b1_released            ;
  call   readButtons            ;
  goto   b1_checkrelease        ;
b1_released

  movf   CursorPosition, w      ; Button 1 pressed, so move volume per bar forward. 
  btfsc  STATUS, Z              ; Unless we are not setting the volume per bar.
  goto   modeset                ;
  call   SetVolumePerBar        ; Parameter in w.
  goto   set_af                 ;

modeset                         ; This is a modechange, so
  incf   mode, f                ; increment the mode and test if it did not
  movlw  4                      ; overflow.
  subwf  mode, w                ;
  btfsc  STATUS, Z              ;
  clrf   mode                   ; If overflowed, reset to zero.
  call   TopAfElapsed           ;

  movf   view, f                ; For view 0 we need the standard set
  btfsc  STATUS, Z              ; of custom characters.
  call   LoadFont               ;

set_af




keypadtest_af
  movlw  0x10                   ; Ready for next time.
  movwf  key                    ;

  movf   CursorPosition, w      ;
  call   SetCursor              ; Parameter in w.
  call   ShowVolumePerBar       ;

; Go asleep if mode went to 0 (due to key press) or when timed out.
  movf   mode, f                ;
  btfsc  STATUS, Z              ;
  goto   slapertje              ;
  btfss  elapsedSeconds, 7      ;
  goto   sleep_af               ;
slapertje
  call   aSleep                 ; Take precautions before going to sleep.
  sleep                         ; Go to sleep.
  call   WakeUp                 ; Initialize after wakeing up from sleep.
sleep_af


; Put off backlight if timed out.
  btfss  elapsedSecondsB, 7     ;
  bsf    PORTA, BACKL           ; Put backlight power for LCD on.
  btfsc  elapsedSecondsB, 7     ;
  bcf    PORTA, BACKL           ; Put backlight power for LCD off.

  decfsz LLoopCounter, f        ; End fast loop.
  goto   LLoop                  ;
  decfsz LoopCounter, f         ;
  goto   LLoop                  ;

  goto   Loop                   ; End slow loop.




; Subroutines


;**********************************************************************
;*                                                                    *
;*     SendCHAR                                                       *
;*                                                                    *
;*     Function: sends char to LCD.                                   *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
SendCHAR                        ; Send the Character to the LCD.
  movwf	 Temp                   ; Save the Temporary Value.

  swapf	 Temp, w                ; Send the High Nybble.
  bsf    STATUS, C              ; RS = 1.
  call   NybbleOut              ;

  movf   Temp, w                ; Send the Low Nybble.
  bsf    STATUS, C              ; RS = 1.
  call   NybbleOut              ;


  return                        ;


;**********************************************************************
;*                                                                    *
;*     LoadCHAR                                                       *
;*                                                                    *
;*     Function: loads 1 custom char (w) in place indicated by        *
;*               gCursor                                              *
;*                                                                    *
;*     input:    w must be between ' ' and 'Z'                        *
;*               gCursor can be between 0 and 15 and represents       *
;*               the following cursor positions:                      *
;*                                                                    *
;*                                                 top left of LCD    *
;*                            +-----------+ +-----------+             *
;*                            ¦           ¦ ¦           ¦             *
;*                            +-----------+ +-----------+             *
;*                            +-----------+ +-----------+             *
;*                            ¦           ¦ ¦           ¦             *
;*                            +-----------+ +-----------+             *
;*                            +-----------+ +-----------+             *
;*                            ¦           ¦ ¦           ¦             *
;*                            +-----------+ +-----------+             *
;*                            +-----------+ +-----------+             *
;*                            ¦           ¦ ¦           ¦             *
;*                            +-----------+ +-----------+             *
;*                            +-----------+ +-----------+             *
;*                            ¦  3     2  ¦ ¦  1     0  ¦             *
;*                            +-----------+ +-----------+             *
;*                            +-----------+ +-----------+             *
;*                            ¦  7     6  ¦ ¦  5     4  ¦             *
;*                            +-----------+ +-----------+             *
;*                            +-----------+ +-----------+             *
;*                            ¦ 11    10  ¦ ¦  9     8  ¦             *
;*                            +-----------+ +-----------+             *
;*                            +-----------+ +-----------+             *
;*                            ¦ 15    14  ¦ ¦ 13    12  ¦             *
;*                            +-----------+ +-----------+             *
;*                            +-----------+ +-----------+             *
;*                            ¦           ¦ ¦           ¦             *
;*                            +-----------+ +-----------+             *
;*                            +-----------+ +-----------+             *
;*                            ¦           ¦ ¦           ¦             *
;*                            +-----------+ +-----------+             *
;*                            +-----------+ +-----------+             *
;*                            ¦           ¦ ¦           ¦             *
;*                            +-----------+ +-----------+             *
;*                            +-----------+ +-----------+             *
;*                            ¦           ¦ ¦           ¦             *
;*                            +-----------+ +-----------+             *
;*                                                                    *
;*                (the rectangular blocks represent character cells)  *
;*                                                                    *
;*                                                                    *
;*     return: gCursor (incremented by 1)                             *
;*                                                                    *
;**********************************************************************

LoadCHAR

; Load one character (4 bytes) into CGRAM.

  movwf  FSR                    ; Move w to FSR (minus space because
  movlw  A' '                   ; table starts there) and
  subwf  FSR, f                 ; multiply with 4.
  bcf    STATUS, C              ;
  rlf    FSR, f                 ;
  rlf    FSR, f                 ; FSR is now pointer in char table.

  movlw  4                      ; One character is 4 bytes (half a
  movwf  gCount                 ; character cell).

  movlw  0x0f                   ; Foolproof the input parameter.
  andwf  gCursor, f             ;
  bcf    STATUS, C              ;
  rlf    gCursor, f             ; gCursor must be multiplied with 4 to
  rlf    gCursor, f             ; calculate the CGRAM address.
  movf   gCursor, w             ;
  iorlw	 B'01000000'            ; Load font.
  call	 SendINS                ;
  call	 Dlay5                  ;
  bcf    STATUS, C              ; Repair gCursor.
  rrf    gCursor, f             ;
  rrf    gCursor, f             ;

  
LoadLoop
  movf   FSR, w                 ;
  movwf  offset                 ;
  incf   offset, f              ;
  movlw  LOW Charset            ; Get low 8 bits of table.
  addwf  offset, f              ; Do an 8-bit add operation.
  movlw  HIGH Charset           ; Get high 5 bits of table.
  btfsc  STATUS, C              ; Page crossed?
  addlw  1                      ; Yes: then increment high address.
  movwf  PCLATH                 ; Load high address in latch.
  movf   offset, w              ; Load computed offset in w register.
  incf   FSR, f                 ; FSR ready for next iteration.
  call   Charset                ;
  call   SendCHAR               ; Output the Font data.
  decfsz gCount, f              ; At the end of the char?
  goto   LoadLoop               ;

  incf   gCursor, f             ; Make cursor ready for next call.
  return                        ;



;**********************************************************************
;*                                                                    *
;*     LoadInvCHAR                                                    *
;*                                                                    *
;*     Function: same as LoadCHAR, but characters are loaded in       *
;*               reverse video.                                       *
;*                                                                    *
;**********************************************************************

LoadInvCHAR

; Load font.

  movwf  FSR                    ; Move w to FSR (minus space because
  movlw  A' '                   ; table starts there) and
  subwf  FSR, f                 ; multiply with 4.
  bcf    STATUS, C              ;
  rlf    FSR, f                 ;
  rlf    FSR, f                 ; FSR is now pointer in char table.

  movlw  4                      ;
  movwf  gCount                 ;

  movlw  0x0f                   ;
  andwf  gCursor, f             ;
  bcf    STATUS, C              ;
  rlf    gCursor, f             ;
  rlf    gCursor, f             ;
  movf   gCursor, w             ;
  iorlw	 B'01000000'            ; Load font.
  call	 SendINS                ;
  call	 Dlay5                  ;
  bcf    STATUS, C              ; Repair gCursor.
  rrf    gCursor, f             ;
  rrf    gCursor, f             ;

  
LoadInvLoop
  movf   FSR, w                 ;
  movwf  offset                 ;
  incf   offset, f              ;
  movlw  LOW Charset            ; Get low 8 bits of table.
  addwf  offset, f              ; Do an 8-bit add operation.
  movlw  HIGH Charset           ; Get high 5 bits of table.
  btfsc  STATUS, C              ; Page crossed?
  addlw  1                      ; Yes: then increment high address.
  movwf  PCLATH                 ; Load high address in latch.
  movf   offset, w              ; Load computed offset in w register.
  incf   FSR, f                 ; FSR ready for next iteration.
  call   Charset                ;
  xorlw  0xff                   ;
  call   SendCHAR               ; Output the Font data.
  decfsz gCount, f              ; At the end of the char?
  goto   LoadInvLoop            ;

  incf   gCursor, f             ; Make cursor ready for next call.
  return                        ;




Charset
  movwf  PCL                    ;
  DT 0, 0, 0, 0                 ; space
  DT 0, 0, 0x1d, 0              ; !
  DT 0, 0x0c, 0, 0x0c           ; "
  DT 0x17, 0, 0, 0              ; #
  DT 0, 0x1f, 0x0a, 0x1f        ; $
  DT 0, 0, 0, 0                 ; %
  DT 0, 0, 0, 0                 ; &
  DT 0, 0, 0x18, 0              ; '
  DT 0, 0, 0x11, 0x0e           ; (
  DT 0, 0, 0x0e, 0x11           ; )
  DT 0, 0x15, 0x0e, 0x15        ; *
  DT 0, 4, 0x0e, 4              ; +
  DT 0, 0, 6, 1                 ; ,
  DT 0, 4, 4, 4                 ; -
  DT 0, 3, 3, 0                 ; .
  DT 0, 0x10, 0x0c, 3           ; /
  DT 0, 0x1f, 0x11, 0x1f        ; 0
  DT 0, 0x1f, 0, 0              ; 1
  DT 0, 0x1d, 0x15, 0x17        ; 2
  DT 0, 0x1f, 0x15, 0x15        ; 3
  DT 0, 0x0f, 4, 0x1c           ; 4
  DT 0, 0x17, 0x15, 0x1d        ; 5
  DT 0, 0x17, 0x15, 0x1f        ; 6
  DT 0, 0x1f, 0x10, 0x10        ; 7
  DT 0, 0x1f, 0x15, 0x1f        ; 8
  DT 0, 0x1f, 0x15, 0x1d        ; 9
  DT 0, 0x1b, 0x1b, 0           ; :
  DT 0, 0, 0x16, 1              ; ;
  DT 0, 0x11, 0x0a, 4           ; <
  DT 0, 5, 5, 5                 ; =
  DT 0, 4, 0x0a, 0x11           ; >
  DT 0, 0, 0, 0                 ; ?
  DT 0, 4, 8, 4                 ; @
  DT 0, 0x1f, 0x14, 0x1f        ; A
  DT 0, 0x0a, 0x15, 0x1f        ; B
  DT 0, 0x11, 0x11, 0x1f        ; C
  DT 0, 0x0e, 0x11, 0x1f        ; D
  DT 0, 0x15, 0x15, 0x1f        ; E
  DT 0, 0x14, 0x14, 0x1f        ; F
  DT 0, 0x17, 0x11, 0x1f        ; G
  DT 0, 0x1f, 4, 0x1f           ; H
  DT 0, 0x11, 0x1f, 0x11        ; I
  DT 0, 0x1e, 1, 2              ; J
  DT 0, 0x13, 0x0c, 0x1f        ; K
  DT 0, 1, 1, 0x1f              ; L
  DT 0, 0x1f, 8, 0x1f           ; M
  DT 0, 0x1f, 0x10, 0x1f        ; N
  DT 0, 0x0e, 0x11, 0x0e        ; O
  DT 0, 0x1c, 0x14, 0x1f        ; P
  DT 0, 0x0f, 0x13, 0x0e        ; Q
  DT 0, 0x1b, 0x14, 0x1f        ; R
  DT 0, 0x12, 0x15, 9           ; S
  DT 0, 0x10, 0x1f, 0x10        ; T
  DT 0, 0x1e, 1, 0x1e           ; U
  DT 0, 0x1c, 3, 0x1c           ; V
  DT 0, 0x1f, 3, 0x1f           ; W
  DT 0, 0x1b, 4, 0x1b           ; X
  DT 0, 0x18, 7, 0x18           ; Y
  DT 0, 0x19, 0x15, 0x13        ; Z



;**********************************************************************
;*                                                                    *
;*     Paint                                                          *
;*                                                                    *
;*     Function: paints the 16 x 20 graphics area.                    *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
Paint
  movlw  0x084                  ; Move cursor.
  call   SendINS                ;
  call   Dlay160                ; Note, can take up to 160 usecs.

  movlw  0                      ;
  call   SendCHAR               ;
  movlw  2                      ;
  call   SendCHAR               ;
  movlw  4                      ;
  call   SendCHAR               ;
  movlw  6                      ;
  call   SendCHAR               ;

  movlw  0x0c4                  ; Move cursor.
  call   SendINS                ;
  call   Dlay160                ; Note, can take up to 160 usecs.

  movlw  1                      ;
  call   SendCHAR               ;
  movlw  3                      ;
  call   SendCHAR               ;
  movlw  5                      ;
  call   SendCHAR               ;
  movlw  7                      ;
  call   SendCHAR               ;



  return                        ;

;**********************************************************************
;*                                                                    *
;*     BackLightAtLeast300                                            *
;*                                                                    *
;*     Function: makes sure that there are at least another 300 secs  *
;*               left before backlight timeout.                       *
;*                                                                    *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
BackLightAtLeast300
  movf   elapsedSecondsB, w     ;
  movwf  Temp                   ;
  movf   elapsedSecondsB + 1, w ;
  movwf  Temp + 1               ;
  movlw  0x2c                   ;
  subwf  Temp + 1, f            ;
  btfss  STATUS, C              ;
  decf   Temp, f                ;
  movlw  1                      ;
  subwf  Temp, f                ;

  btfss  Temp, 7                ;
  return                        ;

  movlw  0x2c                   ;
  movwf  elapsedSecondsB + 1    ;
  movlw  1                      ;
  movwf  elapsedSecondsB        ;

  return                        ;


;**********************************************************************
;*                                                                    *
;*     PowerAtLeast300                                                *
;*                                                                    *
;*     Function: makes sure that there are at least another 300 secs  *
;*               left before backlight timeout.                       *
;*                                                                    *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
PowerAtLeast300
  movf   elapsedSeconds, w      ;
  movwf  Temp                   ;
  movf   elapsedSeconds + 1, w  ;
  movwf  Temp + 1               ;
  movlw  0x2c                   ;
  subwf  Temp + 1, f            ;
  btfss  STATUS, C              ;
  decf   Temp, f                ;
  movlw  1                      ;
  subwf  Temp, f                ;

  btfss  Temp, 7                ;
  return                        ;

  movlw  0x2c                   ;
  movwf  elapsedSeconds + 1     ;
  movlw  1                      ;
  movwf  elapsedSeconds         ;

  return                        ;


;**********************************************************************
;*                                                                    *
;*     TopAfElepased                                                  *
;*                                                                    *
;*     Function: makes sure that the elapse counters are put high     *
;*               enough according to the current mode.                *
;*                                                                    *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
TopAfElapsed
  movlw  1                      ;
  subwf  mode, w                ;
  btfsc  STATUS, Z              ;
  goto   topaf1                 ;
  movlw  2                      ;
  subwf  mode, w                ;
  btfsc  STATUS, Z              ;
  goto   topaf2                 ;
  movlw  3                      ;
  subwf  mode, w                ;
  btfsc  STATUS, Z              ;
  goto   topaf3                 ;
  return                        ;

topaf1
  movlw  D'60'                  ;
  movwf  elapsedSeconds + 1     ;
  clrf   elapsedSeconds         ;
  movlw  D'60'                  ;
  movwf  elapsedSecondsB + 1    ;
  clrf   elapsedSecondsB        ;
  return                        ;
topaf2
  movlw  0x10                   ;
  movwf  elapsedSeconds + 1     ;
  movlw  0x0e                   ;
  movwf  elapsedSeconds         ;
  movlw  D'60'                  ;
  movwf  elapsedSecondsB + 1    ;
  clrf   elapsedSecondsB        ;
  return                        ;
topaf3
  movlw  0x10                   ;
  movwf  elapsedSeconds + 1     ;
  movlw  0x0e                   ;
  movwf  elapsedSeconds         ;
  movlw  0x10                   ;
  movwf  elapsedSecondsB + 1    ;
  movlw  0x0e                   ;
  movwf  elapsedSecondsB        ;
  return                        ;



;**********************************************************************
;*                                                                    *
;*     ee_init                                                        *
;*                                                                    *
;*     Function: reads EEPROM to initialize some variables.           *
;*                                                                    *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
; ee_init
;
; initialise vpbL and vpbH from EEPROM

ee_init

  bank2
  clrf   EEADR                  ; read address 0
  bank0
  call   ee_rd                  ;
  bank2
  movf   EEDATA,w               ; read EEPROM
  bank0
  movwf  vpbL                   ; store in vpbL

  bank2
  movlw  1                      ; read address 1
  movwf  EEADR                  ;
  bank0
  call   ee_rd                  ;
  bank2
  movf   EEDATA,w               ; read EEPROM
  bank0
  movwf  vpbH                   ; store in vpbH

  return                        ;
  

   
;**********************************************************************
;*                                                                    *
;*     ee_wr                                                          *
;*                                                                    *
;*     Function: writes one byte to EEPROM                            *
;*                                                                    *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
; ee_wr
;
; Writes byte in EEDATA to EEPROM location at EEADR.  Interrupts
; should be disabled before calling ee_wr.

ee_wr
  bsf   STATUS, RP1             ;
  bsf   STATUS, RP0             ; Bank 3.
  btfsc EECON1, WR              ; Wait for
  goto  $-1                     ; write to finish.
  bcf   EECON1, EEPGD           ; Point to Data memory.
  bsf   EECON1, WREN            ; Enable writes.
  movlw 0x55                    ; Write 55h to
  movwf EECON2                  ; EECON2.
  movlw 0xaa                    ; Write AAh to
  movwf EECON2                  ; EECON2.
  bsf   EECON1, WR              ; Start write operation.

  btfsc EECON1, WR              ; Wait for
  goto  $-1                     ; write to finish.

  bcf   EECON1, WREN            ; Disable writes.

  bank0
  return                        ;


;**********************************************************************
;*                                                                    *
;*     ee_rd                                                          *
;*                                                                    *
;*     Function: reads one byte from EEPROM                           *
;*                                                                    *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
; ee_rd 
; 
; Reads EEPROM byte at EEPROM location EEADR into EEDATA

ee_rd
  bsf   STATUS, RP1             ;
  bsf   STATUS, RP0             ; Bank 3.
  bcf   EECON1, EEPGD           ; Point to Data memory.
  bsf   EECON1, RD              ; Start read operation.
  bank0
  return                        ;
  

;**********************************************************************
;*                                                                    *
;*     WakeUp                                                         *
;*                                                                    *
;*     Function: performs every action necessary after waking up      *
;*               from sleep.                                          *
;*                                                                    *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
WakeUp
; Initialize ports.
  bsf    STATUS, RP0            ; PortA all digital.
  movlw  0xD6                   ;
  movwf  ADCON1                 ;
  bcf    STATUS, RP0            ;

  movlw  B'00110011'            ; Enable RA0, 1, 4 and 5 input, rest output.
  bsf    STATUS, RP0            ;
  movwf  TRISA ^ 0x080          ;
  bcf    STATUS, RP0            ;

  movlw  B'00110000'            ; Enable RB4 and 5 for input, rest output.
  bsf    STATUS, RP0            ;
  movwf  TRISB ^ 0x080          ;
  bcf    STATUS, RP0            ;

  movlw  B'11111111'            ; Enable RC for input.
  bsf    STATUS, RP0            ;
  movwf  TRISC ^ 0x080          ;
  bcf    STATUS, RP0            ;

  bsf    PORTA, POWER           ; Put power for LCD on.
  bsf    PORTA, BACKL           ; Put backlight power for LCD on.

; Wait before reset.

  call   Dlay250                ; Wait 20 msecs before Reset.

; Initialise the LCD.
  bcf    STATUS, C              ; Clear Carry (Instruction Out).
  movlw  0x03                   ; Reset Command.
  call   NybbleOut              ; Send the Nybble.
  call	 Dlay5                  ; Wait 5 msecs before Sending Again.

  EStrobe                       ;
  call   Dlay160                ; Wait 160 usecs before Sending the Third Time.

  EStrobe                       ;
  call   Dlay160                ; Wait 160 usecs before Sending the Fourth Time.

  bcf    STATUS, C              ;
  movlw  0x02                   ; Set 4 Bit Mode.
  call   NybbleOut              ;
  call	 Dlay160                ;


  movlw	 0x028                  ; Note that it is a 2 Line Display.
  call   SendINS                ;
  call   Dlay160                ;

  movlw  0x008                  ; Turn off the Display.
  call   SendINS                ;
  call   Dlay160                ;

  movlw	 0x001                  ; Clear the Display RAM.
  call   SendINS                ;
  call   Dlay5                  ; Note, can take up to 4.1 msecs.

  movlw	 0x006                  ; Enable Cursor Move Direction.
  call	 SendINS                ;
  call	 Dlay160                ;

  movlw	 0x00C                  ; Turn the LCD Back On.
  call	 SendINS                ;
  call	 Dlay160                ;

; Initialize character set and display.
  call   LoadFont               ; Load the standard set of custom characters.

  movlw	 0x001                  ; Clear the Display RAM.
  call   SendINS                ;
  call   Dlay5                  ; Note, can take up to 4.1 msecs.

  movlw  0x080                  ; Move cursor.
  call   SendINS                ;
  call   Dlay160                ; Note, can take up to 160 usecs.

; Initialize some variables.
  movlw  1                      ;
  movwf  mode                   ;
  clrf   view                   ;
  clrf   CursorPosition         ;

  clrf   elapsedSeconds         ;
  movlw  D'60'                  ;
  movwf  elapsedSeconds + 1     ;
  clrf   elapsedSecondsB        ;
  movlw  D'60'                  ;
  movwf  elapsedSecondsB + 1    ;
  clrf   bKbdPressed            ;


  return                        ;


;**********************************************************************
;*                                                                    *
;*     aSleep                                                         *
;*                                                                    *
;*     Function: prepare before going to sleep.                       *
;*                                                                    *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
aSleep
  bsf    STATUS, RP0            ; PortA all digital.
  movlw  0xD6                   ;
  movwf  ADCON1                 ;
  bcf    STATUS, RP0            ;

  movlw  B'00110011'            ; Enable RA0, 1, 4 and 5 input, rest output.
  bsf    STATUS, RP0            ;
  movwf  TRISA ^ 0x080          ;
  bcf    STATUS, RP0            ;

  movlw  B'00110000'            ; Enable RB4 and 5 for input, rest output.
  bsf    STATUS, RP0            ;
  movwf  TRISB ^ 0x080          ;
  bcf    STATUS, RP0            ;

  movlw  B'11111111'            ; Enable RC for input.
  bsf    STATUS, RP0            ;
  movwf  TRISC ^ 0x080          ;
  bcf    STATUS, RP0            ;

  clrf   PORTB                  ; Save power.

  bcf    PORTA, POWER           ; Put power for LCD off.
  bcf    PORTA, BACKL           ; Put backlight power for LCD off.



  movlw  1                      ;
  movwf  mode                   ;
  clrf   view                   ;

  return                        ;


;**********************************************************************
;*                                                                    *
;*     SendINS                                                        *
;*                                                                    *
;*     Function: sends instruction to LCD.                            *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
SendINS                         ; Send the Instruction to the LCD.
  movwf	 Temp                   ; Save the Temporary Value.

  swapf	 Temp, w                ; Send the High Nybble.
  bcf    STATUS, C              ; RS = 0.
  call   NybbleOut              ;

  movf   Temp, w                ; Send the Low Nybble.
  bcf    STATUS, C              ; RS = 0.
  call   NybbleOut              ;

  return                        ;

;**********************************************************************
;*                                                                    *
;*     NybbleOut                                                      *
;*                                                                    *
;*     Function: send a Nybble to the LCD.                            *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
NybbleOut                       ; Send a Nybble to the LCD.

  movwf	 NOTemp                 ; Save the Nybble to Shift Out.
;  swapf  NOTemp, f              ; Setup to Output to the High Part of the Byte.

  bcf    NOTemp, 4              ;
  bcf    NOTemp, 5              ;
  btfsc  STATUS, C              ; Put out the RS Bit.
  bsf    NOTemp, RS             ;
  btfss  STATUS, C              ;
  bcf    NOTemp, RS             ;
  bcf    NOTemp, E              ;

  movf   NOTemp, w              ;
  movwf  LCD                    ;

  
  EStrobe                       ; Strobe out the LCD Data.

  movlw  256 - ( 20  / 4 )      ; Loop Until Carry Set.
dlayNO
  addlw  1                      ;
  btfss  STATUS, C              ;
  goto   dlayNO                 ;
  return                        ;





;**********************************************************************
;*                                                                    *
;*     LoadFont                                                       *
;*                                                                    *
;*     Function: loads some custom characters to CGRAM                *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************

LoadFont

  movlw	 B'01000000'            ; Load font.
  call	 SendINS                ;
  call	 Dlay5                  ;



; Load font.
  clrf   FSR                    ;
FontLoop
  movf   FSR, w                 ;
  movwf  offset                 ;
  incf   offset, f              ;
  movlw  LOW Font               ; Get low 8 bits of table.
  addwf  offset, f              ; Do an 8-bit add operation.
  movlw  HIGH Font              ; Get high 5 bits of table.
  btfsc  STATUS, C              ; Page crossed?
  addlw  1                      ; Yes: then increment high address.
  movwf  PCLATH                 ; Load high address in latch.
  movf   offset, w              ; Load computed offset in w register.
  incf   FSR, f                 ;
  call   Font                   ;
  call   SendCHAR               ; Output the Font data.
#ifdef DEBUG
  movlw  1                      ; At the End of the Font?
#else
  movlw  D'64'                  ; At the End of the Font?
#endif
  subwf  FSR, w                 ;
  btfss  STATUS, Z              ;
  goto   FontLoop               ;

  return                        ;




Font
  movwf  PCL                    ;
  DT 0, 0, 0x1f, 0, 0, 0, 0, 0  ; 1
  DT 0, 0, 0x1d, 0x15, 0x17, 0, 0, 0; 2
  DT 0, 0, 0x1f, 0x15, 0x15, 0, 0, 0; 3
  DT 0, 0, 0x1f, 0x04, 0x1c, 0, 0, 0; 4
  DT 0, 0, 0x17, 0x15, 0x1d, 0, 0, 0; 5
  DT 0, 0, 0x17, 0x15, 0x1f, 0, 0, 0; 6
  DT 0, 0, 0x1f, 0x10, 0x10, 0, 0, 0; 7
  DT 0, 0, 0x1f, 0x15, 0x1f, 0, 0, 0; 8



;**********************************************************************
;*                                                                    *
;*     readButtons                                                    *
;*                                                                    *
;*                                                                    *
;*     Function: scans the buttons connected on PORT KEYPORT and does *
;*               debouncing.                                          *
;*                                                                    *
;*                                                                    *
;**********************************************************************
;
; This routine checks which input is changed and stores it
; into variable 'key'.
; Bit 0 = right button (RA1)
; Bit 1 = middle button (RA4)
; Bit 2 = left button (RB4)
; Bit 3 = pump is working (RB5)
; Bit 4 = no key pressed
;

readButtons

  movf   KEYPORT, w             ; Read buttons connected to PORTB.
  call   Dlay1                  ; Debounce.
  movf   KEYPORT, w             ; Read buttons again.
  andlw  0xf0                   ; Only interested in high nibble.
  movwf  keypad                 ;

  btfss  keypad, 4              ; Translate to key.
  bsf    key, 2                 ;
  btfsc  keypad, 4              ;
  bcf    key, 2                 ;

  btfsc  keypad, 5              ; Translate to key.
  bsf    key, 3                 ;
  btfss  keypad, 5              ;
  bcf    key, 3                 ;


  bsf    STATUS, RP0            ; PortA all digital.
  movlw  0xd6                   ;
  movwf  ADCON1                 ;
  bcf    STATUS, RP0            ;


  movf   PORTA, w               ; Read buttons connected to PORTA.
  call   Dlay5                  ; Debounce.
  movf   PORTA, w               ; Read buttons again.
  movwf  keypad                 ;

  btfss  keypad, 4              ; Translate to key.
  bsf    key, 1                 ;
  btfsc  keypad, 4              ;
  bcf    key, 1                 ;

  btfss  keypad, 1              ; Translate to key.
  bsf    key, 0                 ;
  btfsc  keypad, 1              ;
  bcf    key, 0                 ;


  movf   key, w                 ;
  movwf  keypad                 ;
  movlw  B'00001111'            ;
  andwf  keypad, f              ;

  movf   keypad, f              ;
  btfsc  STATUS, Z              ;
  bsf    key, 4                 ;

  btfss  STATUS, Z              ;
  bcf    key, 4                 ;

;  clrf   KEYPORT
;  clrf   PORTA

  return                        ;
;
;**********************************************************************
;*                                                                    *
;*     Show routines                                                  *
;*                                                                    *
;*     Function: various routines to show specific values on          *
;*                                                                    *
;*               specific places on the screen.                       *
;*                                                                    *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************

ShowVoltmeter
  call   ReadAD4                ;
  fcall  ConvertAD2Voltage      ;
  fcall  AD2Voltage             ;

  movlw  0                      ;
  subwf  view, w                ;
  btfss  STATUS, Z              ;
  goto   svm_1                  ;
  return                        ;
svm_1
  movlw  1                      ;
  subwf  view, w                ;
  btfss  STATUS, Z              ;
  goto   svm_2                  ;
  goto   svm_sam                ;
svm_2
  return                        ;

svm_sam
  clrf   gCursor                ; Move cursor.

  movf   Asc1, w                ; Show voltage on screen.
  call   LoadCHAR               ;
  movlw  A'.'                   ;
  call   LoadCHAR               ;
  movf   Asc2, w                ;
  call   LoadCHAR               ;
  movf   Asc3, w                ;
  call   LoadCHAR               ;
  movlw  A'T'                   ;
  call   LoadCHAR               ;
  movlw  A'L'                   ;
  call   LoadCHAR               ;
  movlw  A'O'                   ;
  call   LoadCHAR               ;
  movlw  A'V'                   ;
  call   LoadCHAR               ;

  call   Paint                  ; Paint graphics screen.

  return                        ;

ShowMode
;  movlw  0x80                   ; Move cursor position.
;  call	 SendINS                ;
;  call	 Dlay160                ; Note, can take up to 160 usecs.

;  movf   elapsedSeconds, w
;  movwf  ADRESH
;  movf   elapsedSeconds + 1, w
;  bsf    STATUS, RP0
;  movwf  ADRESL
;  bcf    STATUS, RP0
;  fcall  AD2Voltage
;  movf   Asc3, w
;  call   SendCHAR
;  movf   Asc2, w
;  call   SendCHAR
;  movf   Asc1, w
;  call   SendCHAR
;  movf   Asc0, w
;  call   SendCHAR
;  return
  
  movlw  1                      ;
  subwf  mode, w                ;
  btfsc  STATUS, Z              ;
  goto   sm1                    ;
  movlw  2                      ;
  subwf  mode, w                ;
  btfsc  STATUS, Z              ;
  goto   sm2                    ;
  movlw  3                      ;
  subwf  mode, w                ;
  btfsc  STATUS, Z              ;
  goto   sm3                    ;
  return                        ;

sm1
  movlw  A' '                   ;
  movwf  Asc0                   ;
  movlw  0xdb                   ;
  movwf  Asc1                   ;
  movlw  A' '                   ;
  movwf  Asc2                   ;
  movlw  0xdb                   ;
  movwf  Asc3                   ;
  goto   sm_sam                 ;
sm2
  movlw  A' '                   ;
  movwf  Asc0                   ;
  movlw  0xdb                   ;
  movwf  Asc1                   ;
  movlw  0xdb                   ;
  movwf  Asc2                   ;
  movlw  0xdb                   ;
  movwf  Asc3                   ;
  goto   sm_sam                 ;
sm3
  movlw  0xdb                   ;
  movwf  Asc0                   ;
  movlw  0xdb                   ;
  movwf  Asc1                   ;
  movlw  0xdb                   ;
  movwf  Asc2                   ;
  movlw  0xdb                   ;
  movwf  Asc3                   ;
sm_sam
  movlw  0x80                   ; Move cursor position.
  call	 SendINS                ;
  call	 Dlay160                ; Note, can take up to 160 usecs.

  movf   Asc0, w                ;
  call   SendCHAR               ;
  movf   Asc1, w                ;
  call   SendCHAR               ;
  movlw  A'*'                   ;
  call   SendCHAR               ;

  movlw  0xc0                   ; Move cursor position.
  call	 SendINS                ;
  call	 Dlay160                ; Note, can take up to 160 usecs.

  movf   Asc2, w                ;
  call   SendCHAR               ;
  movf   Asc3, w                ;
  call   SendCHAR               ;
  movlw  A'o'                   ;
  call   SendCHAR               ;

  return                        ;


ShowVolumePerBar
  movlw  2                      ;
  subwf  view, w                ;
  btfss  STATUS, Z              ;
  return                        ;

  movf   vpbH, w                ;
  movwf  ADRESH                 ;
  movf   vpbL, w                ;
  bsf    STATUS, RP0            ; Select bank 1.
  movwf  ADRESL                 ;
  bcf    STATUS, RP0            ; Select bank 0.

  fcall  AD2Voltage             ;

  clrf   gCursor                ;

  clrf   shTemp                 ;
  movlw  1                      ;
  subwf  CursorPosition, w      ;
  btfsc  STATUS, Z              ;
  bsf    shTemp, 0              ;
  movlw  2                      ;
  subwf  CursorPosition, w      ;
  btfsc  STATUS, Z              ;
  bsf    shTemp, 1              ;
  movlw  3                      ;
  subwf  CursorPosition, w      ;
  btfsc  STATUS, Z              ;
  bsf    shTemp, 2              ;

  movf   Asc0, w                ;
  call   LoadCHAR               ;
  movlw  A'.'                   ;
  call   LoadCHAR               ;
  movf   Asc1, w                ;
  call   LoadCHAR               ;
  movf   Asc2, w                ;
  call   LoadCHAR               ;

  movlw  A' '                   ;
  btfsc  shTemp, 2              ;
  movlw  A'@'                   ;
  call   LoadCHAR               ;
  movlw  A' '                   ;
  call   LoadCHAR               ;
  movlw  A' '                   ;
  btfsc  shTemp, 1              ;
  movlw  A'@'                   ;
  call   LoadCHAR               ;
  movlw  A' '                   ;
  btfsc  shTemp, 0              ;
  movlw  A'@'                   ;
  call   LoadCHAR               ;

  movlw  A'/'                   ;
  call   LoadCHAR               ;
  movlw  A'T'                   ;
  call   LoadCHAR               ;
  movlw  A'I'                   ;
  call   LoadCHAR               ;
  movlw  A'L'                   ;
  call   LoadCHAR               ;

  movlw  A' '                   ;
  call   LoadCHAR               ;
  movlw  A'R'                   ;
  call   LoadCHAR               ;
  movlw  A'A'                   ;
  call   LoadCHAR               ;
  movlw  A'B'                   ;
  call   LoadCHAR               ;

  call   Paint                  ;

  return                        ;




ShowWater
  movf   view, f                ;
  btfsc  STATUS, Z              ;
  goto   sw0                    ;
  movlw  1                      ;
  subwf  view, w                ;
  btfsc  STATUS, Z              ;
  goto   sw1                    ;
  return                        ;

sw0
;  movlw  4                      ;
;  movwf  showCount              ;
ShowW
  call   readWaterLevel         ;
;  decfsz showCount, f           ;
;  goto   ShowW                  ;

  movlw	 0x0c7                  ; Move cursor.
  call	 SendINS                ;
  call	 Dlay160                ; Note, can take up to 160 usecs.

  movlw  7                      ; Show scale.
  call   SendCHAR               ;
  movlw  6                      ;
  call   SendCHAR               ;
  movlw  5                      ;
  call   SendCHAR               ;
  movlw  4                      ;
  call   SendCHAR               ;
  movlw  3                      ;
  call   SendCHAR               ;
  movlw  2                      ;
  call   SendCHAR               ;
  movlw  1                      ;
  call   SendCHAR               ;
  movlw  0                      ;
  call   SendCHAR               ;

  movlw	 0x087                  ; Move cursor.
  call	 SendINS                ;
  call	 Dlay160                ; Note, can take up to 160 usecs.

  clrw                          ; Clean up signal.
  btfsc  waterLevel, 7          ;
  iorlw  B'01111111'            ;
  btfsc  waterLevel, 6          ;
  iorlw  B'00111111'            ;
  btfsc  waterLevel, 5          ;
  iorlw  B'00011111'            ;
  btfsc  waterLevel, 4          ;
  iorlw  B'00001111'            ;
  btfsc  waterLevel, 3          ;
  iorlw  B'00000111'            ;
  btfsc  waterLevel, 2          ;
  iorlw  B'00000011'            ;
  btfsc  waterLevel, 1          ;
  iorlw  B'00000001'            ;
  iorwf  waterLevel, f          ;

  movlw  A' '                   ;
  btfsc  waterLevel, 7          ;
  movlw  255                    ;
  call   SendCHAR               ;
  movlw  A' '                   ;
  btfsc  waterLevel, 6          ;
  movlw  255                    ;
  call   SendCHAR               ;
  movlw  A' '                   ;
  btfsc  waterLevel, 5          ;
  movlw  255                    ;
  call   SendCHAR               ;
  movlw  A' '                   ;
  btfsc  waterLevel, 4          ;
  movlw  255                    ;
  call   SendCHAR               ;
  movlw  A' '                   ;
  btfsc  waterLevel, 3          ;
  movlw  255                    ;
  call   SendCHAR               ;
  movlw  A' '                   ;
  btfsc  waterLevel, 2          ;
  movlw  255                    ;
  call   SendCHAR               ;
  movlw  A' '                   ;
  btfsc  waterLevel, 1          ;
  movlw  255                    ;
  call   SendCHAR               ;
  movlw  A' '                   ;
  btfsc  waterLevel, 0          ;
  movlw  255                    ;
  call   SendCHAR               ;

  return                        ;

sw1
;  movlw  4                      ;
;  movwf  showCount              ;
ShowW1
  call   readWaterLevel         ;
;  decfsz showCount, f           ;
;  goto   ShowW1                 ;

  clrf   Multipland             ;
  clrf   Multipland + 1         ;

  btfsc  waterLevel, 0          ; Clean up signal.
  movlw  1                      ;
  btfsc  waterLevel, 1          ;
  movlw  2                      ;
  btfsc  waterLevel, 2          ;
  movlw  3                      ;
  btfsc  waterLevel, 3          ;
  movlw  4                      ;
  btfsc  waterLevel, 4          ;
  movlw  5                      ;
  btfsc  waterLevel, 5          ;
  movlw  6                      ;
  btfsc  waterLevel, 6          ;
  movlw  7                      ;
  btfsc  waterLevel, 7          ;
  movlw  8                      ;
  movwf  Multipland + 1         ;

  movf   vpbL, w                ;
  movwf  Multiplier + 1         ;
  movf   vpbH, w                ;
  movwf  Multiplier             ;

  fcall  Mul1616                ;
  movf   Product32, w           ;
  movwf  Dividend + 2           ;
  movf   Product32 + 1, w       ;
  movwf  Dividend + 3           ;
  movf   Product32 + 2, w       ;
  movwf  Dividend + 4           ;
  movf   Product32 + 3, w       ;
  movwf  Dividend + 5           ;
  clrf   Dividend               ;
  clrf   Dividend + 1           ;

  clrf   Divisor                ;
  clrf   Divisor + 1            ;
  movlw  D'10'                  ;
  movwf  Divisor + 2            ;

  fcall  Div4823                ;
  movf   Dividend + 5, w        ;
  bsf    STATUS, RP0            ;
  movwf  ADRESL                 ;
  bcf    STATUS, RP0            ;
  movf   Dividend + 4, w        ;
  movwf  ADRESH                 ;

  fcall  AD2Voltage             ;

  movlw  8                      ;
  movwf  gCursor                ;

  movf   Asc0, w                ;
  call   LoadCHAR               ;
  movf   Asc1, w                ;
  call   LoadCHAR               ;
  movf   Asc2, w                ;
  call   LoadCHAR               ;
  movlw  A' '                   ;
  call   LoadCHAR               ;
  movlw  A'R'                   ;
  call   LoadCHAR               ;
  movlw  A'T'                   ;
  call   LoadCHAR               ;
  movlw  A'I'                   ;
  call   LoadCHAR               ;
  movlw  A'L'                   ;
  call   LoadCHAR               ;

  call   Paint                  ;

  return                        ;



;**********************************************************************
;*                                                                    *
;*     Dlay160                                                        *
;*                                                                    *
;*     Function: delays 160 usecs.                                    *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
Dlay160                         ;  Delay 160 usecs

;  movlw  D'40'                  ;
  movlw  D'40'                  ;
  movwf  Dlay                   ;

dlay_160
#ifdef DEBUG
  movlw  255                    ; Loop Until Carry Set.
#else
;  movlw  256 - ( 160 / 4 )      ; Loop Until Carry Set.
  movlw  256 - ( 50  / 4 )      ; Loop Until Carry Set.
#endif
dlay160
  addlw  1                      ;
  btfss  STATUS, C              ;
  goto   dlay160                ;

  return                        ;



;**********************************************************************
;*                                                                    *
;*     Dlay5i                                                         *
;*                                                                    *
;*     Function: like Dlay5 but specially for interrupt routines.     *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************

Dlay5i                          ; Delay 5 msecs.
#ifdef DEBUG
  movlw  1                      ; Set up the Delay.
#else
  movlw  4                      ; Set up the Delay.
#endif
  movwf  DlayI                  ;

#ifdef DEBUG
  movlw  255                    ;
#else
  movlw  256 - 0x0E8            ;
#endif

  addlw  1                      ;
  btfsc  STATUS, Z              ;
  decfsz DlayI, f               ;
  goto   $-3                    ;

  return                        ;

;**********************************************************************
;*                                                                    *
;*     Dlay20i                                                        *
;*                                                                    *
;*     Function: like Dlay20 but specially for interrupt routines.    *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************

Dlay20i                         ;  Delay 20 msecs

  call   Dlay5i                 ;
  call   Dlay5i                 ;
  call   Dlay5i                 ;
  call   Dlay5i                 ;

  return                        ;

;**********************************************************************
;*                                                                    *
;*     Dlay025                                                        *
;*                                                                    *
;*     Function: delays 0.25 msec.                                    *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
Dlay025
; Delay = 0.00025 seconds
; Clock frequency = 4 MHz

; Actual delay = 0.00025 seconds = 250 cycles
; Error = 0 %

			;250 cycles
	movlw	0x53
	movwf	DlayTemp
Dlay025_00
	decfsz	DlayTemp, f
	goto	Dlay025_00

  return                        ;


;**********************************************************************
;*                                                                    *
;*     Dlay05                                                         *
;*                                                                    *
;*     Function: delays 0.5 msec.                                     *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
Dlay05

; Delay = 0.0005 seconds
; Clock frequency = 4 MHz

; Actual delay = 0.0005 seconds = 500 cycles
; Error = 0 %

			;499 cycles
	movlw	0xa6
	movwf	DlayTemp
Delay05_1
	decfsz	DlayTemp, f
	goto	Delay05_1

			;1 cycles
	nop

  return                        ;


;**********************************************************************
;*                                                                    *
;*     Dlay1                                                          *
;*                                                                    *
;*     Function: delays 1 msec.                                       *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************

; Delay = 0.001 seconds
; Clock frequency = 4 MHz

; Actual delay = 0.001 seconds = 1000 cycles
; Error = 0 %
Dlay1

			;981 cycles
	movlw	0x0e
	movwf	Dlay
Dlay1_00
	movlw	0x16
	movwf	DlayTemp
Dlay1_01
	decfsz	DlayTemp, f
	goto	Dlay1_01
	decfsz	Dlay, f
	goto	Dlay1_00

			;13 cycles
	movlw	0x04
	movwf	Dlay
Dlay1_10
	decfsz	Dlay, f
	goto	Dlay1_10

			;2 cycles
	goto	$+1

			;4 cycles (including call)
	return


;**********************************************************************
;*                                                                    *
;*     Dlay5                                                          *
;*                                                                    *
;*     Function: delays 5 msecs.                                      *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************

Dlay5                           ; Delay 5 msecs.
#ifdef DEBUG
  movlw  1                      ; Set up the Delay.
#else
  movlw  4                      ; Set up the Delay.
#endif
  movwf  Dlay                   ;

#ifdef DEBUG
  movlw  255                    ;
#else
  movlw  256 - 0x0E8            ;
#endif

  addlw  1                      ;
  btfsc  STATUS, Z              ;
  decfsz Dlay, f                ;
  goto   $-3                    ;

  return                        ;

;**********************************************************************
;*                                                                    *
;*     Dlay20                                                         *
;*                                                                    *
;*     Function: delays 20 msecs.                                     *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************

Dlay20                          ;  Delay 20 msecs

  call   Dlay5                  ;
  call   Dlay5                  ;
  call   Dlay5                  ;
  call   Dlay5                  ;

  return

;**********************************************************************
;*                                                                    *
;*     Dlay50                                                         *
;*                                                                    *
;*     Function: delays 50 msecs.                                     *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************

Dlay50                          ;  Delay 50 msecs

  call   Dlay20                 ;
  call   Dlay20                 ;
  call   Dlay5                  ;
  call   Dlay5                  ;

  return


;**********************************************************************
;*                                                                    *
;*     Dlay250                                                        *
;*                                                                    *
;*     Function: delays 250 msecs.                                    *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
Dlay250
#ifdef DEBUG
  movlw  D'1'                   ;  Set up the Delay
#else
  movlw  D'50'                  ;  Set up the Delay
#endif
  movwf  DlayTemp               ;
Dlay250Lus
  call   Dlay5                  ;
  decfsz DlayTemp, f            ;
  goto   Dlay250Lus             ;

  return                        ;
  

;**********************************************************************
;*                                                                    *
;*     SetCursor                                                      *
;*                                                                    *
;*     Function: sets the cursor according to the w register.         *
;*                 w = 0 cursor off                                   *
;*                     1 cursor under high digit of vpb               *
;*                     2 cursor under low digit of vpb                *
;*                     3 cursor under decimal digit of vpb            *
;*                                                                    *
;*                                                                    *
;*     return: none.                                                  *
;*                                                                    *
;**********************************************************************
SetCursor
  andlw  7                      ;
;  addwf  PCL                    ; Simulate a case select.
;  goto   csr0                   ;
;  goto   csr1                   ;
;  goto   csr2                   ;
;  goto   csr3                   ;
;  goto   csr4                   ;
;  goto   csr5                   ;
;  goto   csr_af                 ;
;  goto   csr_af                 ;

  movwf  scsr                   ;

  movlw  0                      ;
  subwf  scsr, w                ;
  btfsc  STATUS, Z              ;
  goto   csr0                   ;
  movlw  1                      ;
  subwf  scsr, w                ;
  btfsc  STATUS, Z              ;
  goto   csr1                   ;
  movlw  2                      ;
  subwf  scsr, w                ;
  btfsc  STATUS, Z              ;
  goto   csr2                   ;
  movlw  3                      ;
  subwf  scsr, w                ;
  btfsc  STATUS, Z              ;
  goto   csr3                   ;
  goto   csr_af                 ;

csr0
  goto   csr_af                 ;
csr1
  movlw	 3                      ; Move cursor.
  goto   csr_on                 ;
csr2
  movlw  2                      ; Move cursor.
  goto   csr_on                 ;
csr3
  movlw	 0                      ; Move cursor.
  goto   csr_on                 ;

csr_on

  
;  movlw  A'^'                   ;
;  call   SendCHAR               ;

;  call   Dlay50                 ;


csr_af
  return                        ;



;**********************************************************************
;*                                                                    *
;*     SetVolumePerBar                                                *
;*                                                                    *
;*     Function: sets the vpb according to the current cursor         *
;*               position which must be in w.                         *
;*                 w = 1 advance with 100                             *
;*                     2 advance with 10                              *
;*                     3 advance with 1                               *
;*                                                                    *
;*     return: none.                                                  *
;*                                                                    *
;**********************************************************************
SetVolumePerBar
  andlw  7                      ;
;  addwf  PCL                    ; Simulate a case select.
;  goto   scl_af                 ;
;  goto   scl1                   ;
;  goto   scl2                   ;
;  goto   scl3                   ;
;  goto   scl4                   ;
;  goto   scl5                   ;
;  goto   scl_af                 ;
;  goto   scl_af                 ;


  movwf  FSR                    ;
  movlw  1                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  goto   scl1                   ;
  movlw  2                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  goto   scl2                   ;
  movlw  3                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  goto   scl3                   ;
  goto   scl_af                 ;  


scl1
  movlw  D'100'                 ;
  addwf  vpbL, f                ;
  btfsc  STATUS, C              ;
  incf   vpbH, f                ;
  goto   scl_af                 ;
scl2
  movlw  D'10'                  ;
  addwf  vpbL, f                ;
  btfsc  STATUS, C              ;
  incf   vpbH, f                ;
  goto   scl_af                 ;
scl3
  movlw  D'1'                   ;
  addwf  vpbL, f                ;
  btfsc  STATUS, C              ;
  incf   vpbH, f                ;
  goto   scl_af                 ;

scl_af

  movf   vpbL, w                ;
  movwf  Temp + 1               ;
  movf   vpbH, w                ;
  movwf  Temp                   ;
  movlw  0xE8                   ;
  subwf  Temp + 1, f            ;
  movlw  0x3                    ;
  btfss  STATUS, C              ;
  decf   Temp, f                ;
  subwf  Temp, f                ;
  btfsc  Temp, 7                ;
  goto   scl_really_af          ;
  
  clrf   vpbL                   ;
  clrf   vpbH                   ;

scl_really_af

; write volume per bar to EEPROM
  bcf    INTCON, GIE            ; globally disable interrupts
  bank2
  clrf   EEADR                  ;
  bank0
  movf   vpbL, w                ;
  bank2
  movwf  EEDATA                 ;
  bank0
  call   ee_wr                  ; write to EEPROM
  bank2
  movlw  1                      ;
  movwf  EEADR                  ;
  bank0
  movf   vpbH, w                ;
  bank2
  movwf  EEDATA                 ;
  bank0
  call   ee_wr                  ; write to EEPROM
  bsf    INTCON, GIE            ; globally allow interrupts

  return                        ;



;**********************************************************************
;*                                                                    *
;*     ReadAD0                                                        *
;*                                                                    *
;*     Function: reads the voltage from the RA port 0 (water level)   *
;*                                                                    *
;*     return: ADRESH:ADRESL                                          *
;*                                                                    *
;*     Assumptions: Vref- at Vss                                      *
;*                  Vref+ at Vdd                                      *
;*                                                                    *
;**********************************************************************
ReadAD0

  clrf   ADRESH                 ;
  bsf    STATUS, RP0            ; Select bank 1.
  clrf   ADRESL                 ;
  bcf    STATUS, RP0            ; Select bank 0.




  bsf    STATUS, RP0            ; Select bank 1.
  movlw  B'10001000'            ; Configure analog pins.
  movwf  ADCON1                 ;
  bcf    STATUS, RP0            ; Select bank 0.

  bcf    ADCON0, 3              ; Select AD channel 0.
  bcf    ADCON0, 4              ;
  bcf    ADCON0, 5              ;

  bsf    ADCON0, 6              ; Select conversion clock.
  bcf    ADCON0, 7              ;

  bsf    ADCON0, 0              ; Turn on AD module.


  call   Dlay160                ; Wait the required acquisition time.
;  call   Dlay160                ;


  bsf    ADCON0, 2              ; Start the conversion.

  nop                           ;
  btfsc  ADCON0, 2              ; Conversion done?
  goto   $-2                    ; No, keep polling.
  call   Dlay160                ; Yes, make ready for next time.
;  call   Dlay160                ;
  bcf    ADCON0, 0              ; Turn off AD module.

ReadAD0A
;  call   AdjustADres            ;

  return                        ;



;**********************************************************************
;*                                                                    *
;*     ReadAD4                                                        *
;*                                                                    *
;*     Function: reads the voltage from the RA port 5 (batt. voltage) *
;*                                                                    *
;*     return: ADRESH:ADRESL                                          *
;*                                                                    *
;*     Assumptions: Vref- Vss                                         *
;*                  Vref+ Vdd                                         *
;*                                                                    *
;**********************************************************************
ReadAD4

  clrf   ADRESH                 ;
  bsf    STATUS, RP0            ; Select bank 1.
  clrf   ADRESL                 ;
  bcf    STATUS, RP0            ; Select bank 0.




  bsf    STATUS, RP0            ; Select bank 1.
  movlw  B'10000000'            ; Configure analog pins.
  movwf  ADCON1                 ;
  bcf    STATUS, RP0            ; Select bank 0.

  bcf    ADCON0, 3              ; Select AD channel 4.
  bcf    ADCON0, 4              ;
  bsf    ADCON0, 5              ;

  bsf    ADCON0, 6              ; Select conversion clock.
  bcf    ADCON0, 7              ;

  bsf    ADCON0, 0              ; Turn on AD module.


  call   Dlay160                ; Wait the required acquisition time.
;  call   Dlay160                ;


  bsf    ADCON0, 2              ; Start the conversion.

  nop                           ;
  btfsc  ADCON0, 2              ; Conversion done?
  goto   $-2                    ; No, keep polling.
  call   Dlay160                ; Yes, make ready for next time.
;  call   Dlay160                ;
  bcf    ADCON0, 0              ; Turn off AD module.

ReadAD4A

  return                        ;



;**********************************************************************
;*                                                                    *
;*     readWaterLevel                                                 *
;*                                                                    *
;*     Function: reads the 8 water sensors                            *
;*                                                                    *
;*     return: waterLevel                                             *
;*                                                                    *
;**********************************************************************
readWaterLevel

  clrf   sensorCnt              ;
;  clrf   waterLevel             ;


; Do some preparations.
  movlw  B'00110011'            ; Enable RA0, 1, 4 and 5 input, rest output.
  bsf    STATUS, RP0            ;
  movwf  TRISA ^ 0x080          ;
  bcf    STATUS, RP0            ;


  clrf   PORTC                  ;
  movlw  B'11111111'            ; Enable RC for input.
  bsf    STATUS, RP0            ;
  movwf  TRISC ^ 0x080          ;
  bcf    STATUS, RP0            ;




sensorLoop

; Do prolog.
  call   Dlay160                ;

  movf   sensorCnt, w           ; Make the current sensor output
  call   trisPortCoutput        ; and high.
  movf   sensorCnt, w           ;
  call   setPortC               ;

  call   Dlay5                  ; Keep sensor high for a while.
  call   Dlay5                  ;
  call   Dlay5                  ;



; Read AD port 0.
  clrf   ADRESH                 ;
  bsf    STATUS, RP0            ; Select bank 1.
  clrf   ADRESL                 ;
  bcf    STATUS, RP0            ; Select bank 0.

  bsf    STATUS, RP0            ; Select bank 1.
  movlw  B'10000000'            ; Configure analog pins.
  movwf  ADCON1                 ;
  bcf    STATUS, RP0            ; Select bank 0.

  bcf    ADCON0, 3              ; Select AD channel 0.
  bcf    ADCON0, 4              ;
  bcf    ADCON0, 5              ;

  bsf    ADCON0, 6              ; Select conversion clock.
  bcf    ADCON0, 7              ;

  bsf    ADCON0, 0              ; Turn on AD module.

  call   Dlay160                ; Wait the required acquisition time.
  call   Dlay160                ;

  bsf    ADCON0, 2              ; Start the conversion.

  nop                           ;
  btfsc  ADCON0, 2              ; Conversion done?
  goto   $-2                    ; No, keep polling.
  call   Dlay160                ; Yes, make ready for next time.
;  bcf    ADCON0, 0              ; Turn off AD module.




; Do epilog.

  call   Dlay160                ;
  call   Dlay160                ;

  movf   sensorCnt, w           ; Make sensor low again and input.
  call   clearPortC             ;

;  clrf   PORTC
  movf   sensorCnt, w           ;
  call   trisPortCinput         ;

  call   Dlay160                ;


; Evaluate result.
  movf   sensorCnt, w           ;
  call   clearWaterBit          ;
  movf   ADRESH, f              ;
  btfsc  STATUS, Z              ;
  goto   eval_L                 ;
  call   setWaterBit            ;
  goto   eval_af                ;
eval_L
  bsf    STATUS, RP0            ; Select bank 1.
  movlw  SENSITIVITY            ;
  subwf  ADRESL, w              ;
  bcf    STATUS, RP0            ; Select bank 0.
  btfss  STATUS, C              ;
  goto   eval_af                ;
  movf   sensorCnt, w           ;
  call   setWaterBit            ;
eval_af



; End the loop.

  call   kbdPressedTest         ;
  btfsc  STATUS, C              ;
  return                        ;

  incf   sensorCnt, f           ;
  btfss  sensorCnt, 3           ; Sensor 8 is the last sensor.
  goto   sensorLoop             ;


; End of measurement, so we must clean up now.
  call   Dlay5                  ;

  bcf    ADCON0, 0              ; Turn off AD module.

  clrf   PORTC                  ;
  bsf    STATUS, RP0            ; Select bank 1.
  movlw  B'10000111'            ; Configure analog pins to all digital.
  movwf  ADCON1                 ;
  bcf    STATUS, RP0            ; Select bank 0.

  movlw  B'00110010'            ; Enable RA1, 4 and 5 input, rest output.
  bsf    STATUS, RP0            ;
  movwf  TRISA ^ 0x080          ;
  bcf    STATUS, RP0            ;

  bsf    PORTA, 0               ;
;  call   setAllButPortC         ;

  call   Dlay5                  ; Make RA0 a while high for anti-corrosing.
  call   Dlay5                  ;
  call   Dlay5                  ;
  call   Dlay160                ;
  call   Dlay160                ;

  bcf    PORTA, 0               ;

  movlw  B'00110011'            ; Enable RA0, 1, 4 and 5 input, rest output.
  bsf    STATUS, RP0            ;
  movwf  TRISA ^ 0x080          ;
  bcf    STATUS, RP0            ;

  call   Dlay5                  ;

;  call   reverseSensors         ;

  return                        ;


#ifdef OLD_CODE
;**********************************************************************
;*                                                                    *
;*     readWaterLevel     ---- OLD                                    *
;*                                                                    *
;*     Function: reads the 8 water sensors                            *
;*                                                                    *
;*     return: waterLevel                                             *
;*                                                                    *
;**********************************************************************
readWaterLevel

  clrf   sensorCnt              ;
  clrf   waterLevel             ;

sensorLoop

; Do prolog.
  movlw  B'00110011'            ; Enable RA0, 1, 4 and 5 input, rest output.
  bsf    STATUS, RP0            ;
  movwf  TRISA ^ 0x080          ;
  bcf    STATUS, RP0            ;

  movlw  B'00000000'            ; Enable RC for output.
  bsf    STATUS, RP0            ;
  movwf  TRISC ^ 0x080          ;
  bcf    STATUS, RP0            ;

  bcf    PORTC, 0               ;
  bcf    PORTC, 1               ;
  bcf    PORTC, 2               ;
  bcf    PORTC, 3               ;
  bcf    PORTC, 4               ;
  bcf    PORTC, 5               ;
  bcf    PORTC, 6               ;
  bcf    PORTC, 7               ;

  call   Dlay160                ;

  movf   sensorCnt, w           ;
  call   setPortC               ;

  call   Dlay5                  ;
  call   Dlay5                  ;
  call   Dlay5                  ;



; Read AD port 0.
  clrf   ADRESH                 ;
  bsf    STATUS, RP0            ; Select bank 1.
  clrf   ADRESL                 ;
  bcf    STATUS, RP0            ; Select bank 0.

  bsf    STATUS, RP0            ; Select bank 1.
  movlw  B'10000000'            ; Configure analog pins.
  movwf  ADCON1                 ;
  bcf    STATUS, RP0            ; Select bank 0.

  bcf    ADCON0, 3              ; Select AD channel 0.
  bcf    ADCON0, 4              ;
  bcf    ADCON0, 5              ;

  bsf    ADCON0, 6              ; Select conversion clock.
  bcf    ADCON0, 7              ;

  bsf    ADCON0, 0              ; Turn on AD module.

  call   Dlay160                ; Wait the required acquisition time.

  bsf    ADCON0, 2              ; Start the conversion.

  nop                           ;
  btfsc  ADCON0, 2              ; Conversion done?
  goto   $-2                    ; No, keep polling.
  call   Dlay160                ; Yes, make ready for next time.
;  bcf    ADCON0, 0              ; Turn off AD module.




; Do epilog.

  movf   sensorCnt, w           ;
  call   clearPortC             ;

;  clrf   PORTC
  movf   sensorCnt, w           ;
  call   trisPortCinput         ;

  call   Dlay160                ;

  bsf    STATUS, RP0            ; Select bank 1.
  movlw  B'10000111'            ; Configure analog pins to all digital.
  movwf  ADCON1                 ;
  bcf    STATUS, RP0            ; Select bank 0.

  movlw  B'00110010'            ; Enable RA 1, 4 and 5 input, rest output.
  bsf    STATUS, RP0            ;
  movwf  TRISA ^ 0x080          ;
  bcf    STATUS, RP0            ;

  bsf    PORTA, 0               ;
  call   setAllButPortC         ;

  call   Dlay5                  ;
  call   Dlay5                  ;
  call   Dlay5                  ;
  call   Dlay160                ;
  call   Dlay160                ;

  bcf    PORTA, 0               ;

  movlw  B'00110011'            ; Enable RA0, 1, 4 and 5 input, rest output.
  bsf    STATUS, RP0            ;
  movwf  TRISA ^ 0x080          ;
  bcf    STATUS, RP0            ;


; Evaluate result.
  movf   sensorCnt, w           ;
  movf   ADRESH, f              ;
  btfsc  STATUS, Z              ;
  goto   eval_L                 ;
  call   setWaterBit            ;
  goto   eval_af                ;
eval_L
  bsf    STATUS, RP0            ; Select bank 1.
  movlw  SENSITIVITY            ;
  subwf  ADRESL, w              ;
  bcf    STATUS, RP0            ; Select bank 0.
  btfss  STATUS, C              ;
  goto   eval_af                ;
  movf   sensorCnt, w           ;
  call   setWaterBit            ;
eval_af



; End the loop.

  incf   sensorCnt, f           ;
  btfss  sensorCnt, 3           ; Sensor 8 is the last sensor.
  goto   sensorLoop             ;

  bcf    ADCON0, 0              ; Turn off AD module.

  clrf   PORTC                  ;
  call   Dlay5                  ;
  call   Dlay5                  ;
  call   Dlay5                  ;


  return                        ;

#endif
;**********************************************************************
;*                                                                    *
;*     reverseSensors                                                 *
;*                                                                    *
;*     Function: reverses the sensors to de-corrose them              *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
reverseSensors


  bsf    STATUS, RP0            ; Select bank 1.
  movlw  B'10000111'            ; Configure analog pins to all digital.
  movwf  ADCON1                 ;
  bcf    STATUS, RP0            ; Select bank 0.

  movlw  B'00110010'            ; Enable RA1, 4 and 5 input, rest output.
  bsf    STATUS, RP0            ;
  movwf  TRISA ^ 0x080          ;
  bcf    STATUS, RP0            ;

  clrf   PORTC                  ;
  movlw  B'00000000'            ; Enable RC for output.
  bsf    STATUS, RP0            ;
  movwf  TRISC ^ 0x080          ;
  bcf    STATUS, RP0            ;



  call   Dlay5                  ;
  call   Dlay5                  ;

  movlw  B'11111111'            ;
  movwf  PORTC                  ;
  bsf    PORTA, 0               ;

  movlw  D'1'                   ;
  movwf  sensorCnt              ;
revLoop
  call   Dlay5                  ;
  call   kbdPressedTest         ;
  btfsc  STATUS, C              ;
  return                        ;
  decfsz sensorCnt, f           ;
  goto   revLoop                ;


  clrf   PORTC                  ;
  bcf    PORTA, 0               ;


  call   Dlay5                  ;
  call   Dlay5                  ;



  movlw  B'00110011'            ; Enable RA0, 1, 4 and 5 input, rest output.
  bsf    STATUS, RP0            ;
  movwf  TRISA ^ 0x080          ;
  bcf    STATUS, RP0            ;

  clrf   PORTC                  ;
  movlw  B'11111111'            ; Enable RC for input.
  bsf    STATUS, RP0            ;
  movwf  TRISC ^ 0x080          ;
  bcf    STATUS, RP0            ;

  call   Dlay5                  ;




#ifdef OLD_CODE
  clrf   sensorCnt              ;

; Do some preparations.

  bsf    STATUS, RP0            ; Select bank 1.
  movlw  B'10000111'            ; Configure analog pins to all digital.
  movwf  ADCON1                 ;
  bcf    STATUS, RP0            ; Select bank 0.

  movlw  B'00110010'            ; Enable RA1, 4 and 5 input, rest output.
  bsf    STATUS, RP0            ;
  movwf  TRISA ^ 0x080          ;
  bcf    STATUS, RP0            ;

  clrf   PORTC                  ;
  movlw  B'00000000'            ; Enable RC for output.
  bsf    STATUS, RP0            ;
  movwf  TRISC ^ 0x080          ;
  bcf    STATUS, RP0            ;

  movlw  D'255'                 ; All sensors high.
  movwf  PORTC                  ;
  bsf    PORTA, 0               ;


reverseLoop

; Do prolog.
  call   Dlay160                ;

  movf   sensorCnt, w           ; Make the current sensor low.
  call   clearPortC             ;

  call   Dlay5                  ; Keep sensor low for a while.
  call   Dlay5                  ;
  call   Dlay5                  ;

;
;
;
; Do epilog.

  call   Dlay160                ;
  call   Dlay160                ;

  movf   sensorCnt, w           ; Make sensor high again.
  call   setPortC               ;

  call   Dlay160                ;



; End the loop.

  incf   sensorCnt, f           ;
  btfss  sensorCnt, 3           ; Sensor 8 is the last sensor.
  goto   reverseLoop            ;


; End of reversing, so we must clean up now.
  call   Dlay5                  ;

  bcf    PORTA, 0               ;

  call   Dlay5                  ; Make RA0 a while low.
  call   Dlay5                  ;
  call   Dlay5                  ;
  call   Dlay160                ;
  call   Dlay160                ;

  movlw  B'00110011'            ; Enable RA0, 1, 4 and 5 input, rest output.
  bsf    STATUS, RP0            ;
  movwf  TRISA ^ 0x080          ;
  bcf    STATUS, RP0            ;

  clrf   PORTC                  ;
  movlw  B'11111111'            ; Enable RC for input.
  bsf    STATUS, RP0            ;
  movwf  TRISC ^ 0x080          ;
  bcf    STATUS, RP0            ;

  call   Dlay5                  ;

#endif

  return                        ;


;**********************************************************************
;*                                                                    *
;*     setPortC                                                       *
;*                                                                    *
;*     Function: sets 1 bit in port C, namely the one indicated       *
;*               by the w register.                                   *
;*                                                                    *
;*     input: w                                                       *
;*                                                                    *
;*     output: PORTC                                                  *
;*                                                                    *
;**********************************************************************
setPortC
  movwf  FSR                    ;

  movlw  0                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bsf    PORTC, 0               ;
  movlw  1                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bsf    PORTC, 1               ;
  movlw  2                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bsf    PORTC, 2               ;
  movlw  3                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bsf    PORTC, 3               ;
  movlw  4                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bsf    PORTC, 4               ;
  movlw  5                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bsf    PORTC, 5               ;
  movlw  6                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bsf    PORTC, 6               ;
  movlw  7                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bsf    PORTC, 7               ;

  movf   FSR, w                 ;

  return                        ;

;**********************************************************************
;*                                                                    *
;*     clearPortC                                                     *
;*                                                                    *
;*     Function: clears 1 bit in port C, namely the one indicated     *
;*               by the w register.                                   *
;*                                                                    *
;*     input: w                                                       *
;*                                                                    *
;*     output: PORTC                                                  *
;*                                                                    *
;**********************************************************************
clearPortC
  movwf  FSR                    ;

  movlw  0                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bcf    PORTC, 0               ;
  movlw  1                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bcf    PORTC, 1               ;
  movlw  2                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bcf    PORTC, 2               ;
  movlw  3                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bcf    PORTC, 3               ;
  movlw  4                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bcf    PORTC, 4               ;
  movlw  5                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bcf    PORTC, 5               ;
  movlw  6                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bcf    PORTC, 6               ;
  movlw  7                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bcf    PORTC, 7               ;

  movf   FSR, w                 ;

  return                        ;


;**********************************************************************
;*                                                                    *
;*     trisPortCinput                                                 *
;*                                                                    *
;*     Function: sets 1 bit in port C as input port, namely the one   *
;*               indicated by the w register.                         *
;*                                                                    *
;*     input: w                                                       *
;*                                                                    *
;*     output: PORTC                                                  *
;*                                                                    *
;**********************************************************************
trisPortCinput
  movwf  FSR                    ;

  movlw  0                      ;
  subwf  FSR, w                 ;
  bsf    STATUS, RP0            ;
  btfsc  STATUS, Z              ;
  bsf    TRISC, 0               ;
  bcf    STATUS, RP0            ;
  movlw  1                      ;
  subwf  FSR, w                 ;
  bsf    STATUS, RP0            ;
  btfsc  STATUS, Z              ;
  bsf    TRISC, 1               ;
  bcf    STATUS, RP0            ;
  movlw  2                      ;
  subwf  FSR, w                 ;
  bsf    STATUS, RP0            ;
  btfsc  STATUS, Z              ;
  bsf    TRISC, 2               ;
  bcf    STATUS, RP0            ;
  movlw  3                      ;
  subwf  FSR, w                 ;
  bsf    STATUS, RP0            ;
  btfsc  STATUS, Z              ;
  bsf    TRISC, 3               ;
  bcf    STATUS, RP0            ;
  movlw  4                      ;
  subwf  FSR, w                 ;
  bsf    STATUS, RP0            ;
  btfsc  STATUS, Z              ;
  bsf    TRISC, 4               ;
  bcf    STATUS, RP0            ;
  movlw  5                      ;
  subwf  FSR, w                 ;
  bsf    STATUS, RP0            ;
  btfsc  STATUS, Z              ;
  bsf    TRISC, 5               ;
  bcf    STATUS, RP0            ;
  movlw  6                      ;
  subwf  FSR, w                 ;
  bsf    STATUS, RP0            ;
  btfsc  STATUS, Z              ;
  bsf    TRISC, 6               ;
  bcf    STATUS, RP0            ;
  movlw  7                      ;
  subwf  FSR, w                 ;
  bsf    STATUS, RP0            ;
  btfsc  STATUS, Z              ;
  bsf    TRISC, 7               ;
  bcf    STATUS, RP0            ;


  movf   FSR, w                 ;

  return                        ;

;**********************************************************************
;*                                                                    *
;*     trisPortCoutput                                                *
;*                                                                    *
;*     Function: sets 1 bit in port C as output port, namely the one  *
;*               indicated by the w register.                         *
;*                                                                    *
;*     input: w                                                       *
;*                                                                    *
;*     output: PORTC                                                  *
;*                                                                    *
;**********************************************************************
trisPortCoutput
  movwf  FSR                    ;

  movlw  0                      ;
  subwf  FSR, w                 ;
  bsf    STATUS, RP0            ;
  btfsc  STATUS, Z              ;
  bcf    TRISC, 0               ;
  bcf    STATUS, RP0            ;
  movlw  1                      ;
  subwf  FSR, w                 ;
  bsf    STATUS, RP0            ;
  btfsc  STATUS, Z              ;
  bcf    TRISC, 1               ;
  bcf    STATUS, RP0            ;
  movlw  2                      ;
  subwf  FSR, w                 ;
  bsf    STATUS, RP0            ;
  btfsc  STATUS, Z              ;
  bcf    TRISC, 2               ;
  bcf    STATUS, RP0            ;
  movlw  3                      ;
  subwf  FSR, w                 ;
  bsf    STATUS, RP0            ;
  btfsc  STATUS, Z              ;
  bcf    TRISC, 3               ;
  bcf    STATUS, RP0            ;
  movlw  4                      ;
  subwf  FSR, w                 ;
  bsf    STATUS, RP0            ;
  btfsc  STATUS, Z              ;
  bcf    TRISC, 4               ;
  bcf    STATUS, RP0            ;
  movlw  5                      ;
  subwf  FSR, w                 ;
  bsf    STATUS, RP0            ;
  btfsc  STATUS, Z              ;
  bcf    TRISC, 5               ;
  bcf    STATUS, RP0            ;
  movlw  6                      ;
  subwf  FSR, w                 ;
  bsf    STATUS, RP0            ;
  btfsc  STATUS, Z              ;
  bcf    TRISC, 6               ;
  bcf    STATUS, RP0            ;
  movlw  7                      ;
  subwf  FSR, w                 ;
  bsf    STATUS, RP0            ;
  btfsc  STATUS, Z              ;
  bcf    TRISC, 7               ;
  bcf    STATUS, RP0            ;


  movf   FSR, w                 ;

  return                        ;

;**********************************************************************
;*                                                                    *
;*     setAllButPortC                                                 *
;*                                                                    *
;*     Function: sets all bits in port C, except one, namely the one  *
;*               indicated by the w register.                         *
;*                                                                    *
;*     input: w                                                       *
;*                                                                    *
;*     output: PORTC                                                  *
;*                                                                    *
;**********************************************************************
setAllButPortC
  movwf  FSR                    ;

  movlw  0                      ;
  subwf  FSR, w                 ;
  btfss  STATUS, Z              ;
  bsf    PORTC, 0               ;
  movlw  1                      ;
  subwf  FSR, w                 ;
  btfss  STATUS, Z              ;
  bsf    PORTC, 1               ;


  movlw  2                      ;
  subwf  FSR, w                 ;
  btfss  STATUS, Z              ;
  bsf    PORTC, 2               ;
  movlw  3                      ;
  subwf  FSR, w                 ;
  btfss  STATUS, Z              ;
  bsf    PORTC, 3               ;
  movlw  4                      ;
  subwf  FSR, w                 ;
  btfss  STATUS, Z              ;
  bsf    PORTC, 4               ;
  movlw  5                      ;
  subwf  FSR, w                 ;
  btfss  STATUS, Z              ;
  bsf    PORTC, 5               ;
  movlw  6                      ;
  subwf  FSR, w                 ;
  btfss  STATUS, Z              ;
  bsf    PORTC, 6               ;
  movlw  7                      ;
  subwf  FSR, w                 ;
  btfss  STATUS, Z              ;
  bsf    PORTC, 7               ;

setAllButPortC_af
  movf   FSR, w                 ;

  return                        ;

;**********************************************************************
;*                                                                    *
;*     setWaterBit                                                    *
;*                                                                    *
;*     Function: sets 1 bit in waterLevel, namely the one indicated   *
;*               by the w register.                                   *
;*                                                                    *
;*     input: w                                                       *
;*                                                                    *
;*     output: waterLevel                                             *
;*                                                                    *
;**********************************************************************
setWaterBit
  movwf  FSR                    ;

  movlw  0                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bsf    waterLevel, 0          ;
  movlw  1                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bsf    waterLevel, 1          ;
  movlw  2                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bsf    waterLevel, 2          ;
  movlw  3                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bsf    waterLevel, 3          ;
  movlw  4                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bsf    waterLevel, 4          ;
  movlw  5                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bsf    waterLevel, 5          ;
  movlw  6                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bsf    waterLevel, 6          ;
  movlw  7                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bsf    waterLevel, 7          ;

  movf   FSR, w                 ;

  return                        ;

;**********************************************************************
;*                                                                    *
;*     clearWaterBit                                                  *
;*                                                                    *
;*     Function: clears 1 bit in waterLevel, namely the one indicated *
;*               by the w register.                                   *
;*                                                                    *
;*     input: w                                                       *
;*                                                                    *
;*     output: waterLevel                                             *
;*                                                                    *
;**********************************************************************
clearWaterBit
  movwf  FSR                    ;

  movlw  0                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bcf    waterLevel, 0          ;
  movlw  1                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bcf    waterLevel, 1          ;
  movlw  2                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bcf    waterLevel, 2          ;
  movlw  3                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bcf    waterLevel, 3          ;
  movlw  4                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bcf    waterLevel, 4          ;
  movlw  5                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bcf    waterLevel, 5          ;
  movlw  6                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bcf    waterLevel, 6          ;
  movlw  7                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  bcf    waterLevel, 7          ;

  movf   FSR, w                 ;

  return                        ;


;**********************************************************************
;*                                                                    *
;*     kbdPressedTest                                                 *
;*                                                                    *
;*     Function: tests if keyboard is pressed, if yes turn boolean    *
;*               off and set carry flag, if no clear carry flag.      *
;*                                                                    *
;*               This can be useful when called from inside a long    *
;*               loop to end this loop prematurely, and so creating   *
;*               higher responsiveness to the keyboard.               *
;*                                                                    *
;*     output: carry flag                                             *
;*                                                                    *
;**********************************************************************
kbdPressedTest
; bcf STATUS, C
; return
;  btfsc  bKbdPressed, 0         ; Test the RB connected keys (boolean
;  goto   kbdPressed             ; set by interrupt handler).

;  btfss  PORTA, 1               ; Also test the RA connected keys.
;  goto   kbdPressed             ;
;  btfss  PORTA, 4               ;
;  goto   kbdPressed             ;

  btfss  PORTB, 4               ;
  goto   kbdPressed             ;


  bcf    STATUS, C              ;
  return                        ;


kbdPressed
  bcf    bKbdPressed, 0         ;
  bsf    STATUS, C              ;


  return                        ;





  org 0x0800




;**********************************************************************
;*                                                                    *
;*     ConvertAD2Voltage                                              *
;*                                                                    *
;*     Function: converts ADRESH:ADRESL to a format that is           *
;*               consistent with AD2Voltage routine.                  *
;*               Output is written to the input location.             *
;*                                                                    *
;*               Formulae used: input * 1517 / 1024                   *
;*                                                                    *
;*                                                                    *
;*                                                                    *
;*     return: ADRESH:ADRESL                                          *
;*                                                                    *
;*     Assumptions: Vref- at Vss, Vref+ at Vdd.                       *
;*                                                                    *
;*                                                                    *
;*                                                                    *
;*                                                                    *
;*                                                                    *
;*                                                                    *
;**********************************************************************
ConvertAD2Voltage
  bsf    STATUS, RP0            ;
  movf   ADRESL, w              ;
  bcf    STATUS, RP0            ;

  movwf  Multipland + 1         ;
  movf   ADRESH, w              ;
  movwf  Multipland             ;

  movlw  0x5                    ;
  movwf  Multiplier             ;
  movlw  0xed                   ;
  movwf  Multiplier + 1         ;

  fcall  Mul1616                ;

  clrf   Dividend               ;
  clrf   Dividend + 1           ;
  movf   Product32, w           ;
  movwf  Dividend + 2           ;
  movf   Product32 + 1, w       ;
  movwf  Dividend + 3           ;
  movf   Product32 + 2, w       ;
  movwf  Dividend + 4           ;
  movf   Product32 + 3, w       ;
  movwf  Dividend + 5           ;

  clrf   Divisor                ;
  movlw  4                      ;
  movwf  Divisor + 1            ;
  clrf   Divisor + 2            ;

  fcall  Div4823                ;

  movf   Dividend + 4, w        ;
  movwf  ADRESH                 ;

  movf   Dividend + 5, w        ;
  bsf    STATUS, RP0            ;
  movwf  ADRESL                 ;
  bcf    STATUS, RP0            ;

  return                        ;

;**********************************************************************
;*                                                                    *
;*     AdjustAD1                                                      *
;*                                                                    *
;*     Function: adjusts ADRESH:ADRESL by adding.                     *
;*                                                                    *
;*     input: ADRESH:ADRESL                                           *
;*                                                                    *
;*     return: ADRESH:ADRESL                                          *
;*                                                                    *
;**********************************************************************
AdjustAD1
  movlw  5                      ;
  bsf    STATUS, RP0            ;
  addwf  ADRESL, f              ;
  bcf    STATUS, RP0            ;
  btfsc  STATUS, C              ;
  incf   ADRESH, f              ;
  return                        ;

;**********************************************************************
;*                                                                    *
;*     AdjustAD2                                                      *
;*                                                                    *
;*     Function: adjusts ADRESH:ADRESL by adding.                     *
;*                                                                    *
;*     input: ADRESH:ADRESL                                           *
;*                                                                    *
;*     return: ADRESH:ADRESL                                          *
;*                                                                    *
;**********************************************************************
AdjustAD2
  movlw  5                      ;
  bsf    STATUS, RP0            ;
  addwf  ADRESL, f              ;
  bcf    STATUS, RP0            ;
  btfsc  STATUS, C              ;
  incf   ADRESH, f              ;
  return                        ;

;**********************************************************************
;*                                                                    *
;*     AdjustADres                                                    *
;*                                                                    *
;*     Function: adjusts ADRESH:ADRESL by cricking this up or down    *
;*               with a certain percentage. This is necessary if      *
;*               Vdd is not exactly 5V (all routines are based on     *
;*               this 5V). For example, if Vdd = 5.08V, the           *
;*               adjustmunt is +1.6%                                  *
;*                                                                    *
;*     input: ADRESH:ADRESL                                           *
;*                                                                    *
;*     return: ADRESH:ADRESL                                          *
;*                                                                    *
;**********************************************************************
AdjustADres
  clrf   Multipland             ;
  movf   ADRESH, w              ;
  movwf  Multipland + 1         ;
  bsf    STATUS, RP0            ;
  movf   ADRESL, w              ;
  bcf    STATUS, RP0            ;
  movwf  Multipland + 2         ;

  clrf   Multiplier             ;
  movlw  3                      ;
  movwf  Multiplier + 1         ;
  movlw  0xdb                   ;
  movwf  Multiplier + 2         ;

  fcall  Mul2424                ;

  movf   Product, w             ;
  movwf  Dividend               ;
  movf   Product + 1, w         ;
  movwf  Dividend + 1           ;
  movf   Product + 2, w         ;
  movwf  Dividend + 2           ;
  movf   Product + 3, w         ;
  movwf  Dividend + 3           ;
  movf   Product + 4, w         ;
  movwf  Dividend + 4           ;
  movf   Product + 5, w         ;
  movwf  Dividend + 5           ;

  clrf   Divisor                ;
  movlw  0x3                    ;
  movwf  Divisor + 1            ;
  movlw  0xe8                   ;
  movwf  Divisor + 2            ;

  fcall  Div4823                ;

  movf   Dividend + 4, w        ;
  movwf  ADRESH                 ;
  movf   Dividend + 5, w        ;
  bsf    STATUS, RP0            ;
  movwf  ADRESL                 ;
  bcf    STATUS, RP0            ;



  return                        ;



;**********************************************************************
;*                                                                    *
;*     Ascii2Bin                                                      *
;*                                                                    *
;*     Function: converts a numeric ascii string consisting           *
;*               of 2 bytes (in Asc1:Asc0) to its binary              *
;*               representation in the w register.                    *
;*                                                                    *
;*                                                                    *
;*     return: w                                                      *
;*                                                                    *
;**********************************************************************
Ascii2Bin
  movlw  0x30                   ; Start with low ascii byte.
  subwf  Asc0, w                ;
  movwf  result0                ; Temporary result in result0.

  movlw  0x30                   ; Now handle high ascii byte.
  subwf  Asc1, w                ;

; Multiply w with 10
  movwf  result1                ;
  bcf    STATUS, C              ;
  rlf    result1, f             ;
  movf   result1, w             ; Save 2 x w in w.
  rlf    result1, f             ;
  rlf    result1, f             ; Result1 is now original w times 8.
  addwf  result1, w             ; Plus 2 x w is 10 times.

  addwf  result0, w             ; Add the low byte.



  return                        ;





;**********************************************************************
;*                                                                    *
;*     ByteToDec                                                      *
;*                                                                    *
;*     Function: converts byte in w to ascii decimal value            *
;*                                                                    *
;*     return: Asc0, Asc1 and Asc2                                    *
;*                                                                    *
;**********************************************************************
ByteToDec
;Binary to decimal conversion (0..255)
;
;Input: w
;Output Asc2:Asc1:Asc0
;
  movwf  TempByte               ;

  clrw                          ;
  addlw  241                    ;
  movwf  Asc2                   ; b_2 = 2a_2 - 15

  addwf  Asc2, w                ;
  addwf  Asc2, w                ;
  addlw  253                    ;
  movwf  Asc1                   ;
  swapf  TempByte, w            ;
  andlw  0x0F                   ;
  addwf  Asc1, f                ;
  addwf  Asc1, f                ; b_1 = 6a_2 + 2a_1 - 48

  sublw  251                    ;
  movwf  Asc0                   ;
  addwf  Asc0, f                ;
  addwf  Asc0, f                ;
  addwf  Asc0, f                ;
  movf   TempByte, w            ;
  andlw  0x0F                   ;
  addwf  Asc0, f                ; b_0 = a_0 - 4(a_2 + a_1) - 20

  movlw  10                     ;
bin2dec999a                     ; 9 cycles max
  addwf  Asc0, f                ;
  decf   Asc1, f                ;
  skpc                          ;
  goto   bin2dec999a            ;

bin2dec999b                     ; 6 cycles max
  addwf  Asc1, f                ;
  decf   Asc2, f                ;
  skpc                          ;
  goto   bin2dec999b            ;

bin2dec999c                     ; 3 cycles max
  addwf  Asc2, f                ;
  skpc                          ;
  goto   bin2dec999c            ;

  movlw  0x30                   ;
  addwf  Asc2, f                ;
  addwf  Asc1, f                ;
  addwf  Asc0, f                ;

  return                        ;


;**********************************************************************
;*                                                                    *
;*     AD2Voltage                                                     *
;*                                                                    *
;*     Function: converts AD value in ADRESH:ADRESL to ascii          *
;*                                                                    *
;*     return: Asc0, Asc1, Asc2 and Asc3                              *
;*                                                                    *
;**********************************************************************
AD2Voltage
  bsf    STATUS, RP0            ; Select bank 1.
  movf   ADRESL, w              ; Move ADRESL to TempByte.
  bcf    STATUS, RP0            ; Select bank 0.
  movwf  TempByte               ;

  clrw                          ;
  clrf   BCD_B_3                ;
  addlw  241                    ;
  movwf  BCD_B_2                ; b_2 = 2a_2 - 15

  addwf  BCD_B_2, w             ;
  addwf  BCD_B_2, w             ;
  addlw  253                    ;
  movwf  BCD_B_1                ;
  swapf  TempByte, w            ;
  andlw  0x0F                   ;
  addwf  BCD_B_1, f             ;
  addwf  BCD_B_1, f             ; b_1 = 6a_2 + 2a_1 - 48

  sublw  251                    ;
  movwf  BCD_B_0                ;
  addwf  BCD_B_0, f             ;
  addwf  BCD_B_0, f             ;
  addwf  BCD_B_0, f             ;
  movf   TempByte, w            ;
  andlw  0x0F                   ;
  addwf  BCD_B_0, f             ; b_0 = a_0 - 4(a_2 + a_1) - 20

  movlw  10                     ;
ad2vol999a                      ; 9 cycles max
  addwf  BCD_B_0, f             ;
  decf   BCD_B_1, f             ;
  skpc                          ;
  goto   ad2vol999a             ;

ad2vol999b                      ; 6 cycles max
  addwf  BCD_B_1, f             ;
  decf   BCD_B_2, f             ;
  skpc                          ;
  goto   ad2vol999b             ;

ad2vol999c                      ; 3 cycles max
  addwf  BCD_B_2, f             ;
  skpc                          ;
  goto   ad2vol999c             ;

  btfss  ADRESH, 0              ;
  goto   ByteToVoltage9         ;
  movlw  6                      ;
  movwf  BCD_A_0                ;
  movlw  5                      ;
  movwf  BCD_A_1                ;
  movlw  2                      ;
  movwf  BCD_A_2                ;
  clrf   BCD_A_3                ;
  fcall  AddBCD                 ;
ByteToVoltage9
  btfss  ADRESH, 1              ;
  goto   ByteToVoltage10        ;
  movlw  2                      ;
  movwf  BCD_A_0                ;
  movlw  1                      ;
  movwf  BCD_A_1                ;
  movlw  5                      ;
  movwf  BCD_A_2                ;
  clrf   BCD_A_3                ;
  fcall  AddBCD                 ;
ByteToVoltage10
  btfss  ADRESH, 2              ;
  goto   ByteToVoltage11        ;
  movlw  4                      ;
  movwf  BCD_A_0                ;
  movlw  2                      ;
  movwf  BCD_A_1                ;
  movlw  0                      ;
  movwf  BCD_A_2                ;
  movlw  1                      ;
  movwf  BCD_A_3                ;
  fcall  AddBCD                 ;
ByteToVoltage11

  movf   BCD_B_0, w             ;
  addlw  0x30                   ;
  movwf  Asc0                   ;
  movf   BCD_B_1, w             ;
  addlw  0x30                   ;
  movwf  Asc1                   ;
  movf   BCD_B_2, w             ;
  addlw  0x30                   ;
  movwf  Asc2                   ;
  movf   BCD_B_3, w             ;
  addlw  0x30                   ;
  movwf  Asc3                   ;

  return                        ;





;**********************************************************************
;*                                                                    *
;*     AddBCD                                                         *
;*                                                                    *
;*     Function: does a BCD add of 2 numbers consisting of 4 bytes.   *
;*                                                                    *
;*                   BCD_A_3    BCD_A_2    BCD_A_1    BCD_A_0         *
;*               +   BCD_B_3    BCD_B_2    BCD_B_1    BCD_B_0         *
;*               ____________________________________________         *
;*                   result3    result2    result1    result0         *
;*                                                                    *
;*          the result is placed in BCD_B                             *
;*                                                                    *
;*                                                                    *
;*     return: HexToAsciiResult_L, HexToAsciiResult_H                 *
;*                                                                    *
;**********************************************************************
AddBCD
  clrf   result0                ;
  clrf   result1                ;
  clrf   result2                ;
  clrf   result3                ;
  clrf   Temp                   ;

  movf   BCD_A_0, w             ;
  addwf  BCD_B_0, w             ;
  movwf  result0                ;
  sublw  9                      ;
  btfsc  STATUS, C              ;
  goto   AddBCD0                ;
  movlw  0x0a                   ;
  subwf  result0, f             ;
  bsf    Temp, 0                ;

AddBCD0
  movf   BCD_A_1, w             ;
  btfsc  Temp, 0                ;
  addlw  1                      ;
  clrf   Temp                   ;
  addwf  BCD_B_1, w             ;
  movwf  result1                ;
  sublw  9                      ;
  btfsc  STATUS, C              ;
  goto   AddBCD1                ;
  movlw  0x0a                   ;
  subwf  result1, f             ;
  bsf    Temp, 0                ;
AddBCD1
  movf   BCD_A_2, w             ;
  btfsc  Temp, 0                ;
  addlw  1                      ;
  clrf   Temp                   ;
  addwf  BCD_B_2, w             ;
  movwf  result2                ;
  sublw  9                      ;
  btfsc  STATUS, C              ;
  goto   AddBCD2                ;
  movlw  0x0a                   ;
  subwf  result2, f             ;
  bsf    Temp, 0                ;

AddBCD2
  movf   BCD_A_3, w             ;
  btfsc  Temp, 0                ;
  addlw  1                      ;
  clrf   Temp                   ;
  addwf  BCD_B_3, w             ;
  movwf  result3                ;
  sublw  9                      ;
  btfsc  STATUS, C              ;
  goto   AddBCD3                ;
  movlw  0x0a                   ;
  subwf  result3, f             ;
  bsf    Temp, 0                ;

AddBCD3
  movf   result0, w             ;
  movwf  BCD_B_0                ;
  movf   result1, w             ;
  movwf  BCD_B_1                ;
  movf   result2, w             ;
  movwf  BCD_B_2                ;
  movf   result3, w             ;
  movwf  BCD_B_3                ;



  return                        ;




;**********************************************************************
;*                                                                    *
;*     Mul1616                                                        *
;*                                                                    *
;*     Function: multiplies a 16 bit number with a 16 bit number.     *
;*                                                                    *
;*     Product = Multipland * Multiplier                              *
;*                                                                    *
;*     input: Multipland 2 bytes, msb first                           *
;*            Multiplier 2 bytes, msb first                           *
;*                                                                    *
;*                                                                    *
;*                                                                    *
;*     return: Product32 - 4 bytes, msb first                         *
;*                                                                    *
;**********************************************************************
Mul1616

  
  clrf   Product32              ;
  clrf   Product32 + 1          ;
  clrf   Product32 + 2          ;
  clrf   Product32 + 3          ;
  bsf    Product32 + 2, 7       ;

m1
  rrf    Multipland, f          ;
  rrf    Multipland + 1, f      ;
  skpc                          ;
  goto   m2                     ;
  movf   Multiplier + 1, w      ;
  addwf  Product32 + 1, f       ;
  movf   Multiplier, w          ;
  skpnc                         ;
  incfsz Multiplier, w          ;
  addwf  Product32, f           ;

m2
  rrf    Product32, f           ;
  rrf    Product32 + 1, f       ;
  rrf    Product32 + 2, f       ;
  rrf    Product32 + 3, f       ;
  skpc                          ;
  goto   m1                     ;


  return                        ;



;**********************************************************************
;*                                                                    *
;*     Mul2424                                                        *
;*                                                                    *
;*     Function: multiplies a 24 bit number with a 24 bit number      *
;*               resulting in a 48 bit number.                        *
;*                                                                    *
;*     Product = Multipland * Multiplier                              *
;*                                                                    *
;*     Input: Multiplier - 3 bytes (shared with Product)              *
;*            Multipland - 3 bytes (not modified)                     *
;*                                                                    *
;*                                                                    *
;*                                                                    *
;*                                                                    *
;*     return: Product - 6 bytes                                      *
;*                                                                    *
;**********************************************************************
Mul2424

  clrf   Product                ; Clear destination.
  clrf   Product + 1            ;
  clrf   Product + 2            ;

        
  movlw  D'24'
  movwf  BitCount               ; Number of bits.

  rrf    Product + 3, f         ; Shift out to carry.
  rrf    Product + 4, f         ; Next multiplier bit.
  rrf    Product + 5, f         ;

ADD_LOOP_24x24

  btfss  STATUS, C              ; If carry is set we must add multipland
                                ; to the product.
  goto   SKIP_LOOP_24x24        ; Nope, skip this bit.
                
  movf   Multipland + 2, w      ; Get LSB of multiplicand.
  addwf  Product + 2, f         ; Add it to the lsb of the product.
  
  movf   Multipland + 1, w      ; Middle byte.
  btfsc  STATUS, C              ; Check carry for overflow.
  incfsz Multipland + 1, w      ; If carry set we add one to the source 
  addwf  Product + 1, f         ; and add it (if not zero, in
                                ; that case mulitpland = 0xff->0x00).
        
  movf   Multipland, w          ; MSB byte.
  btfsc  STATUS, C              ; Check carry.
  incfsz Multipland, w          ;
  addwf  Product, f             ; Handle overflow.

SKIP_LOOP_24x24
; Note carry contains most significant bit of
; addition here.

; Shift in carry and shift out
; next multiplier bit, starting from less
; significant bit.

  rrf    Product, f             ;
  rrf    Product + 1, f         ;
  rrf    Product + 2, f         ;
  rrf    Product + 3, f         ;
  rrf    Product + 4, f         ;
  rrf    Product + 5, f         ;

  decfsz BitCount, f            ;
  goto   ADD_LOOP_24x24         ;



  return                        ;

;**********************************************************************
;*                                                                    *
;*     Div4823                                                        *
;*                                                                    *
;*     Function: divides a 48 bit number by a 23 bit number.          *
;*                                                                    *
;*     return: result in Dividend.                                    *
;*                                                                    *
;**********************************************************************
;

Div4823
DIVIDE_48by23
; Test for zero division.
  movf   Divisor, w             ;
  iorwf  Divisor + 1, w         ;
  iorwf  Divisor + 2, w         ;
  btfsc  STATUS, Z              ;
  retlw  0                      ; Divisor = zero, not possible to calculate.
                                ; Return with zero in w.

; Prepare used variables.
  clrf   Temp                   ;
  clrf   Temp + 1               ;
  clrf   Temp + 2               ;

  movlw  D'48'                  ; Initialize bit counter.
  movwf  BitCount               ;

  setc                          ;

DIVIDE_LOOP_48by23
  rlf    Dividend + 5, f        ;
  rlf    Dividend + 4, f        ;
  rlf    Dividend + 3, f        ;
  rlf    Dividend + 2, f        ;
  rlf    Dividend + 1, f        ;
  rlf    Dividend, f            ;

; Shift in highest bit from dividend through carry in temp.
  rlf    Temp + 2, f            ;
  rlf    Temp + 1, f            ;
  rlf    Temp, f                ;

  movf   Divisor + 2, w         ; Get LSB of divisor.
  btfss  Dividend + 5, 0        ;
  goto   Div48by23_add          ;

; Subtract 23 bit divisor from 24 bit temp.
  subwf  Temp + 2, f            ; Subtract.

  movf   Divisor + 1, w         ; Get middle byte.
  skpc                          ; If overflow (from prev. subtraction)
  incfsz Divisor + 1, w         ; incresase source
  subwf  Temp + 1, f            ; and subtract from dest.

  movf   Divisor, w             ; Get top byte.
  skpc                          ; If overflow (from prev. subtraction)
  incfsz Divisor, w             ; increase source
  subwf  Temp, f                ; and subtract from dest.
  goto   DIVIDE_SKIP_48by23     ; Carry was set, subtraction ok,
                                ; continue with next bit.

Div48by23_add
; Result of subtraction was negative restore temp.
  addwf  Temp + 2, f            ; Add it to the lsb of temp.

  movf   Divisor + 1, w         ; Middle byte.
  btfsc  STATUS, C              ; Check carry for overflow from previous
                                ; addition.
  incfsz Divisor + 1, w         ; If carry set we add 1 to the source
  addwf  Temp + 1, f            ; and add it if not zero in that case
                                ; Product + Multipland = Product.

  movf   Divisor, w             ; MSB byte.
  btfsc  STATUS, C              ; Check carry for overflow from previous
                                ; addition.
  incfsz Divisor, w
  addwf  Temp, f                ; Handle overflow.

DIVIDE_SKIP_48by23
  decfsz BitCount, f            ; Decrement loop counter.
  goto   DIVIDE_LOOP_48by23     ; Another run.

; Finally shift in the last carry.
  rlf    Dividend + 5, f        ;
  rlf    Dividend + 4, f        ;
  rlf    Dividend + 3, f        ;
  rlf    Dividend + 2, f        ;
  rlf    Dividend + 1, f        ;
  rlf    Dividend, f            ;
  retlw  1                      ; Done.


;**********************************************************************
;*                                                                    *
;*     AdjustADresExtra                                               *
;*                                                                    *
;*     Function: adjusts ADRESH:ADRESL by cricking this up or down    *
;*               with a certain percentage and bias.                  *
;*                                                                    *
;*     input: ADRESH:ADRESL                                           *
;*                                                                    *
;*     return: ADRESH:ADRESL                                          *
;*                                                                    *
;**********************************************************************
AdjustADresExtra
  clrf   Multipland             ; Move ADRES register to multipland.
  movf   ADRESH, w              ;
  movwf  Multipland + 1         ;
  bsf    STATUS, RP0            ;
  movf   ADRESL, w              ;
  bcf    STATUS, RP0            ;
  movwf  Multipland + 2         ;

  movlw  D'00'                  ; Perform a reverse bias of 19.
  addwf  Dividend + 5, f        ;
  btfsc  STATUS, C              ;
  incf   Dividend + 4, f        ;

  clrf   Multiplier             ; Perform a multiplication with 1047
  movlw  4                      ; (4.7 percent).
  movwf  Multiplier + 1         ;
  movlw  0x17                   ;
  movwf  Multiplier + 2         ;

  fcall  Mul2424                ;

  movf   Product, w             ; Move result to dividend.
  movwf  Dividend               ;
  movf   Product + 1, w         ;
  movwf  Dividend + 1           ;
  movf   Product + 2, w         ;
  movwf  Dividend + 2           ;
  movf   Product + 3, w         ;
  movwf  Dividend + 3           ;
  movf   Product + 4, w         ;
  movwf  Dividend + 4           ;
  movf   Product + 5, w         ;
  movwf  Dividend + 5           ;

  clrf   Divisor                ; Perform a division with 1000.
  movlw  0x3                    ;
  movwf  Divisor + 1            ;
  movlw  0xe8                   ;
  movwf  Divisor + 2            ;

  call   Div4823                ;

  movlw  D'00'                  ; Perform a bias of 19.
  subwf  Multipland + 2, f      ;
  btfss  STATUS, C              ;
  decf   Multipland + 1, f      ;

  movf   Dividend + 4, w        ; Move result back to ADRES register.
  movwf  ADRESH                 ;
  movf   Dividend + 5, w        ;
  bsf    STATUS, RP0            ;
  movwf  ADRESL                 ;
  bcf    STATUS, RP0            ;



  return                        ;





  end


