 title  "LCD - Experimenteerbord"
;
;
;
;  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 asks the user for a pasword. After the user enters the
;   correct password (find this out yourself in the code) the program does
;   various things with the screen: on the left side
;   a temperature meter is shownn, on the right side the last button pressed
;   is shown and in the middle a 24 hour clock is shown.
;
;  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.
;
;
;
;  Hardware Notes for LCD:
;   Reset is tied directly to Vcc and PWRT is Enabled.
;   The PIC is a 16F873 Running at 4 MHz.
;   PortC.2 is the E line
;   PortC.3 is the RS line
;   PortC.4 -> 7 are the data lines D4 -> D7
;
;
;
;
; This program also makes use of the built-in AD converter of the
; PIC16F873.
; Voltage measurement: measures between 5.00V and 15.24V, precision 0.01V
; AD configuration: Vref- at 1.64V, Vref+ at 3.36V.
; Input must be divided by means of voltage divider, with a factor 3.048.
; 5.00 V is added to result after AD conversion.
;
; Temperature measurement: Vref- at 2.00V, Vref+ at 4.00V
;
;
;
;
;
;
;
#define NODEBUG
#define NOWATER

  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
DlayTemp                        ;
Temp                            ; Temporary Value Used When Sending Out Data
Temp_P1                         ;
Temp_P2                         ;
Temp2                           ;
NOTemp                          ; Temporary Value to "NybbleOutput"
GlobalCounter                   ;
LoopCounter                     ;
offset                          ;

;***********************************************************************
; variables for timer service

; parameters
Seconds                         ;
Minutes                         ;
Hours                           ;

; local variables
TimerL                          ;
TimerH                          ;

;***********************************************************************
; variables for ReadVoltage

;***********************************************************************
; variables for context saving during interrupt service
w_safe                          ;
pclath_safe                     ;
status_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 HexToAscii

; parameters
HexToAsciiResult_L              ;
HexToAsciiResult_H              ;

; local variables
HexTemp                         ;

;***********************************************************************
; variables for Ascii2Bin

;***********************************************************************
; variables for waterMeter
waterLevel
sensorCnt

;***********************************************************************
; variables for keyboard routine

; parameters
key                             ;

; local variables
cols                            ;
keypad                          ;

;***********************************************************************
; variables for InputString

; parameters
strA                            ;
strB                            ;
strC                            ;
strD                            ;
strE                            ;

;***********************************************************************
; variables for Mul1616

; parameters
n_4                             ;
n_3                             ;
n_2                             ;
n_1                             ;
q_4                             ;
q_3                             ;
q_2                             ;
q_1                             ;

;***********************************************************************
; variables for Div4823

; parameters
Divisor                         ; msb
Divisor_P1                      ;
Divisor_P2                      ;
Dividend                        ; msb
Dividend_P1                     ;
Dividend_P2                     ;
Dividend_P3                     ;
Dividend_P4                     ;
Dividend_P5                     ;

; local variables
BitCount                        ;

;***********************************************************************
; variables for beep

; parameters
freq                            ; passes frequency value to beep
duratn                          ; passes duration value to beep

; local variables
d_hi                            ; temporary counter (high byte of duration)
d_lo                            ; temporary counter (low byte of duration)
tgl                             ; temporary variable
f_temp                          ; temporary counter (frequency)
t_pat                           ; temporary variable

 ENDC



;**********************************************************************
;*                                                                    *
;*     Definitions                                                    *
;*                                                                    *
;**********************************************************************
#DEFINE LCD     PORTC
#DEFINE E       2
#DEFINE RS      3
z       equ     2               ;
RBPU    equ     7               ;



;**********************************************************************
;*                                                                    *
;*     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


 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              *
;*                                                                    *
;**********************************************************************
;
ServiceInterrupt

  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              ;

;
; Frequency = 4 Mhz, 4 cycles for 1 instruction = 1000000 counts for
; 1 second. Divide this by 256 (timer interrupt), and we have 3906.25
; counts before we reach 1 second.
;
; So this means that if TimerH:TimerL reaches 3906.25, 1 second has elapsed.
; Since we can't handle the .25 part, we will test on 3907 and then increment
; the seconds. Than we give the TimerL every 4 seconds a boost of 3
; counts, which results in a second corresponding to 3907 - (3/4) = 3906.25 counts.
  movlw  0x43                   ;
  subwf  TimerL, w              ;
  btfss  STATUS, Z              ;
  goto   SecTest_af             ;
  movlw  0x0f                   ;
  subwf  TimerH, w              ;
  btfss  STATUS, Z              ;
  goto   SecTest_af             ;
  clrf   TimerL                 ;
  clrf   TimerH                 ;
  incf   Seconds, f             ;

  btfsc  Seconds, 0             ; Are bit 0 and 1 of seconds cleared?
  goto   Correctie_af           ;
  btfsc  Seconds, 1             ;
  goto   Correctie_af           ;
  movlw  2                      ; Yes: boots low counter with 2.
  addwf  TimerL, f              ;

Correctie_af
  movlw  D'60'                  ; Now increment the Minutes and Hours if
  subwf  Seconds, w             ; necessary.
  btfss  STATUS, Z              ;
  goto   SecTest_af             ;
  clrf   Seconds                ;
  incf   Minutes, f             ;
  movlw  D'6'                   ;
  movwf  TimerL                 ;
  movlw  D'60'                  ;
  subwf  Minutes, w             ;
  btfss  STATUS, Z              ;
  goto   SecTest_af             ;
  clrf   Minutes                ;
  incf   Hours, f               ;
  movlw  D'24'                  ;
  subwf  Hours, w               ;
  btfss  STATUS, Z              ;
  goto   SecTest_af             ;
  clrf   Hours                  ;
SecTest_af


  swapf  status_safe, w         ; Restore context.
  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: scans the keypad connected on PORT KEYPORT and does  *
;*               debouncing.                                          *
;*                                                                    *
;*                                                                    *
;*     The keypad connected must be of matrix type, and arranged      *
;*     like this:                                                     *
;*                                                                    *
;*                                                                    *
;*         1   2   3   A                                              *
;*                                                                    *
;*         4   5   6   B                                              *
;*                                                                    *
;*         7   8   9   C                                              *
;*                                                                    *
;*         *   0   #   D                                              *
;*                                                                    *
;*                                                                    *
;*     The corresponding result in variable key will be like this:    *
;*                                                                    *
;*         0   4   8  12                                              *
;*                                                                    *
;*         1   5   9  13                                              *
;*                                                                    *
;*         2   6  10  14                                              *
;*                                                                    *
;*         3   7  11  15                                              *
;*                                                                    *
;*                                                                    *
;*                                                                    *
;*     return: key (0 - 15 represents the key pressed, 16 = no key    *
;*                  pressed)                                          *
;*                                                                    *
;**********************************************************************
;
;
;
; This routine checks which input is changed and stores it
; into variable 'key'.
; 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   Dlay5                  ; Debounce.
  movf   KEYPORT, w             ; Read keypad again.
  andlw  0xf0                   ; Only interested in high nibble.
  movwf  keypad                 ;

; Translate KEYPORT <7:4> into key.
  movlw  3                      ;
  btfss  keypad, 7              ;
  goto   TestPort_af            ;
  movlw  2                      ;
  btfss  keypad, 6              ;
  goto   TestPort_af            ;
  movlw  1                      ;
  btfss  keypad, 5              ;
  goto   TestPort_af            ;
  movlw  0                      ;
  btfss  keypad, 4              ;
  goto   TestPort_af            ;

  clrf   cols                   ; Indicate that all keys are released.
  goto   RB_int_af              ;

TestPort_af
  btfsc  cols, 0                ; Are all keys released?
  goto   RB_int_af              ; No, so do nothing.

  bsf    cols, 0                ; Indicate that a key is pressed.

  movwf  key                    ; Store last key pressed.

  bcf    PORTA, 4               ; Put on LED.
  call   Dlay20                 ;
  bsf    PORTA, 4               ; Put off LED.

  movlw  d'50'                  ;
  movwf  freq                   ;
  movlw  d'08'                  ;
  movwf  duratn                 ;
;  call   beep                   ;

; Now test on which column the incoming key was coming from.

  bsf    KEYPORT, 0             ; See if column 0 gives a difference.
  call   Dlay20                 ;
  movf   KEYPORT, w             ;
  andlw  0xf0                   ; Only interested in high nibble.
  subwf  keypad, w              ;
  btfss  STATUS, Z              ;
  goto   RB_int_af              ; Difference: column 0 is the right one!

  movlw  4                      ; Try next column.
  addwf  key, f                 ;
  bsf    KEYPORT, 1             ; See if column 1 gives a difference.
  call   Dlay20                 ;
  movf   KEYPORT, w             ;
  andlw  0xf0                   ; Only interested in high nibble.
  subwf  keypad, w              ;
  btfss  STATUS, Z              ;
  goto   RB_int_af              ; Difference: column 1 is the right one!

  movlw  4                      ; Try next column.
  addwf  key, f                 ;
  bsf    KEYPORT, 2             ; See if column 2 gives a difference.
  call   Dlay20                 ;
  movf   KEYPORT, w             ;
  andlw  0xf0                   ; Only interested in high nibble.
  subwf  keypad, w              ;
  btfss  STATUS, Z              ;
  goto   RB_int_af              ; Difference: column 2 is the right one!

  movlw  4                      ; Try next column.
  addwf  key, f                 ;
  bsf    KEYPORT, 3             ; See if column 3 gives a difference.
  call   Dlay20                 ;
  movf   KEYPORT, w             ;
  andlw  0xf0                   ; Only interested in high nibble.
  subwf  keypad, w              ;
  btfss  STATUS, Z              ;
  goto   RB_int_af              ; Difference: column 3 is the right one!



RB_int_af
  bcf    KEYPORT, 0             ; Make all columns low for next push.
  bcf    KEYPORT, 1             ;
  bcf    KEYPORT, 2             ;
  bcf    KEYPORT, 3             ;


  swapf  status_safe, w         ; Restore context.
  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                  ;


;  bsf    PORTA, 4               ; Put off LED.
;  call   Dlay50
;  bcf    PORTA, 4               ; Put on LED.
;  call   Dlay20
;  bsf    PORTA, 4               ; Put off LED.

  clrf   TimerL                 ;
  clrf   TimerH                 ;
  clrf   Seconds                ;
  clrf   Minutes                ;
  clrf   Hours                  ;
  clrf   waterLevel             ;

  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  B'00101111'            ; Enable RA0, 1, 2, 3 and 5 input, rest output.
  bsf    STATUS, RP0            ;
  movwf  TRISA ^ 0x080          ;
  bcf    STATUS, RP0            ;

  movlw  B'11110000'            ; Enable RB0..RB3 for output.
  bsf    STATUS, RP0            ;
  movwf  TRISB ^ 0x080          ;
  bcf    STATUS, RP0            ;

  movlw  B'00000000'            ; Enable RC for output.
  bsf    STATUS, RP0            ;
  movwf  TRISC ^ 0x080          ;
  bcf    STATUS, RP0            ;






; Set the timer.
  bsf    STATUS, RP0            ; Select page 1.
#ifdef DEBUG
  movlw  B'00000000'            ;
#else
  movlw  B'00001000'            ; No prescaler.
#endif
  movwf  OPTION_REG             ;
  bcf    OPTION_REG, RBPU       ; Enable pull up on RB port.
  bcf    STATUS, RP0            ; Select page 0.

#ifdef DEBUG
;  movlw  0xF0                   ;
;  movwf  PORTB                  ;
#endif



;  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                    ;


; Wait before reset.
  call   Dlay20                 ; Wait 20 msecs before Reset.


lll
;  movlw  B'00000000'
;  movwf  PORTB                  ; Put off LED.
;  call   Dlay50
;  movlw  B'00001111'
;  movwf  PORTB                  ; Put on LED.
;  call   Dlay50
;  goto lll


; Power-on self test.
  movlw  B'00001000'            ; Laat LED knipperen, evenals relais.
  movwf  PORTA                  ;
  call   Dlay250                ;
  movlw  B'00010000'            ;
  movwf  PORTA                  ;
  call   Dlay250                ;
  movlw  B'00001000'            ;
  movwf  PORTA                  ;
  call   Dlay250                ;
  movlw  B'00010000'            ;
  movwf  PORTA                  ;
  call   Dlay250                ;



; 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                ;

  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.
  btfss  FSR, 3                 ; At the End of the Font?
  goto   FontLoop               ;


  movlw  0x080                  ; Move cursor.
  call   SendINS                ;
  call   Dlay160                ; Note, can take up to 160 usecs.



  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     "Hello", 0
  dt    "Hello Ge                                "
  dt     "ertje...", 0

Font
  movwf  PCL                    ;
  DT 0, 0, 0, D'10', D'31', D'17', D'31', 0

skippy


; Leave the message for a short while on the screen.
  call   Dlay250                ;
  call   Dlay250                ;
  call   Dlay250                ;
  call   Dlay250                ;
;
  goto   MAIN_LOOP
#ifdef DEBUG
;  goto   MAIN_LOOP
#endif
; This demonstrates the use of the keypad as a means for entering
; strings, numbers and so on.
Istr
  call   InputString            ;
  movlw  0x38                   ;
  subwf  strA, w                ;
  btfss  STATUS, Z              ;
  goto   Istr                   ;
  movlw  0x36                   ;
  subwf  strB, w                ;
  btfss  STATUS, Z              ;
  goto   Istr                   ;
  movlw  0x36                   ;
  subwf  strC, w                ;
  btfss  STATUS, Z              ;
  goto   Istr                   ;
  movlw  0x36                   ;
  subwf  strD, w                ;
  btfss  STATUS, Z              ;
  goto   Istr                   ;

  movlw  d'70'                  ;
  movwf  freq                   ;
  movlw  d'11'                  ;
  movwf  duratn                 ;
;  call   beep                   ;



MAIN_LOOP
; Now the main loop is coming...
;
  clrf   GlobalCounter          ;
  movlw	 0x001                  ; Clear the Display RAM.
  call   SendINS                ;
  call   Dlay5                  ; Note, can take up to 4.1 msecs.



Loop                            ; Loop Forever.


;  bsf    PORTA, 4               ; Put off LED.
;  call   Dlay50
;  bcf    PORTA, 4               ; Put on LED.
;  call   Dlay50
;  bsf    PORTA, 4               ; Put off LED.

  call   ReadAD0                ; Get analog value from AD port RA0.
  call   AD2Voltage             ;
  movlw	 0x080			; Move cursor.
  call	 SendINS                ;
  call	 Dlay160                ; Note, can take up to 160 usecs.

  movf   Asc3, w                ; Show voltage on screen.
  call   SendCHAR               ;
  movf   Asc2, w                ;
  call   SendCHAR               ;
  movlw  D'46'                  ;
  call   SendCHAR               ;
  movf   Asc1, w                ;
  call   SendCHAR               ;
  movf   Asc0, w                ;
  call   SendCHAR               ;
  movlw  D'86'                  ;
  call   SendCHAR               ;




  movlw  D'1'                   ;
  movwf  LoopCounter            ; Inner loop for higher responsitivity to the keypad.
LLoop
  call   Dlay160                ;
  call   Dlay160                ;




  movf   GlobalCounter, w       ;
  call   SetCursor              ; Parameter in w.


; Handle the keyboard.
  btfsc  key, 4                 ;
  goto   keypadtest_af          ;


  movlw	 0x0C6                  ; Move cursor.
  call   SendINS                ;
  call   Dlay160                ; Note, can take up to 160 usecs.

  movf   key, w
  call   ByteToDec
  movf   Asc1, w                ;
  call   SendCHAR               ;
  movf   Asc0, w                ;
  call   SendCHAR               ;


  movf   key, f                 ;
  btfsc  STATUS, Z              ;
  incf   GlobalCounter, f       ;

  movlw  6                      ; Test for overflow.
  subwf  GlobalCounter, w       ;
  btfsc  STATUS, Z              ;
  clrf   GlobalCounter          ;
  btfss  key, 0                 ;
  goto   set_af                 ;
  movf   GlobalCounter, w       ;
  call   SetClock               ; Parameter in w.

set_af
;  decf   GlobalCounter, f       ;
keypadtest_af
  movlw  0x10                   ; Ready for next time.
  movwf  key                    ;


; Show things on the screen.

  movlw	 0x087                  ; Move cursor.
  call   SendINS                ;
  call   Dlay160                ; Note, can take up to 160 usecs.

  movf   Hours, w               ; Show hours on screen.
  call   ByteToDec              ;
  movf   Asc1, w                ;
  call   SendCHAR               ;
  movlw	 0x0C0                  ; Move cursor.
  call   SendINS                ;
  call   Dlay160                ; Note, can take up to 160 usecs.
  movf   Asc0, w                ;
  call   SendCHAR               ;

  movf   Minutes, w             ; Show minutes on screen.
  call   ByteToDec              ;
  movf   Asc1, w                ;
  call   SendCHAR               ;
  movf   Asc0, w                ;
  call   SendCHAR               ;

  movf   Seconds, w             ; Show seconds on screen.
  call   ByteToDec              ;
  movf   Asc1, w                ;
  call   SendCHAR               ;
  movf   Asc0, w                ;
  call   SendCHAR               ;





  movf   GlobalCounter, w       ;
  call   SetCursor              ; Parameter in w.



  decfsz LoopCounter, f         ;
  goto   LLoop                  ;

  goto   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                        ;

;**********************************************************************
;*                                                                    *
;*     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              ;
  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, 0              ;
  bcf    NOTemp, 1              ;
  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.

  call   Dlay160                ;

  return                        ;



;**********************************************************************
;*                                                                    *
;*     Dlay160                                                        *
;*                                                                    *
;*     Function: delays 160 usecs.                                    *
;*                                                                    *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
Dlay160                         ;  Delay 160 usecs

  movlw  D'40'                  ;
  movwf  Dlay                   ;

dlay_160
#ifdef DEBUG
  movlw  255                    ; Loop Until Carry Set.
#else
  movlw  256 - ( 160 / 4 )      ; Loop Until Carry Set.
#endif
dlay160
  addlw  1                      ;
  btfss  STATUS, C              ;
  goto   dlay160                ;

  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
  movlw  D'50'                  ;  Set up the Delay
  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 hours             *
;*                     2 cursor under low digit of hours              *
;*                     3 cursor under high digit of minutes           *
;*                     4 cursor under low digit of minutes            *
;*                     5 cursor under seconds                         *
;*                                                                    *
;*                                                                    *
;*     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  FSR                    ;
  movf   FSR, f                 ;
  btfsc  STATUS, Z              ;
  goto   csr0                   ;
  movlw  1                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  goto   csr1                   ;
  decf   FSR, f                 ;
  decf   FSR, f                 ;
  movlw  0xc0                   ;
  addwf  FSR, w                 ;
  goto   csr_on                 ;

csr0
  movlw  0x0c                   ; Cursor off.
  call   SendINS                ;
  call   Dlay160                ;
  goto   csr_af                 ;
csr1
  movlw	 0x087                  ; Move cursor.
;  call	 SendINS                ;
;  call	 Dlay160                ; Note, can take up to 160 usecs.
  goto   csr_on                 ;
csr2
;  movlw  0x0C0                  ; Move cursor.
;  call	 SendINS                ;
;  call	 Dlay160                ; Note, can take up to 160 usecs.
;  goto   csr_on                 ;
csr3
;  movlw	 0x0C1			; Move cursor.
;  call	 SendINS                ;
;  call	 Dlay160                ; Note, can take up to 160 usecs.
;  goto   csr_on                 ;
csr4
;  movlw	 0x0C2			; Move cursor.
;  call	 SendINS                ;
;  call	 Dlay160                ; Note, can take up to 160 usecs.
;  goto   csr_on                 ;
csr5
;  movlw	 0x0C3			; Move cursor.
;  call	 SendINS                ;
;  call	 Dlay160                ; Note, can take up to 160 usecs.
;  goto   csr_on                 ;

csr_on
  call	 SendINS                ;
  call	 Dlay160                ; Note, can take up to 160 usecs.
  movlw  0x0f                   ; Cursor on.
  call   SendINS                ;
  call   Dlay160                ;


csr_af
  return                        ;



;**********************************************************************
;*                                                                    *
;*     SetClock                                                       *
;*                                                                    *
;*     Function: sets the clock according to the current cursor       *
;*               position which must be in w.                         *
;*                 w = 1 advance with 10 hours                        *
;*                     2 advance with 1 hour                          *
;*                     3 advance with 10 minutes                      *
;*                     4 advance with 1 minute                        *
;*                     5 set seconds to zero                          *
;*                                                                    *
;*                                                                    *
;*     return: none.                                                  *
;*                                                                    *
;**********************************************************************
SetClock
  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                   ;
  movlw  4                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  goto   scl4                   ;
  movlw  5                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ;
  goto   scl5                   ;
  goto   scl_af                 ;  


scl1
  movlw  D'10'                  ;
  addwf  Hours, f               ;
  movlw  D'24'                  ;
  subwf  Hours, w               ;
  btfss  STATUS, C              ;
  goto   scl_af                 ;
  movlw  D'30'                  ;
  subwf  Hours, w               ;
  movlw  D'20'                  ;
  btfsc  STATUS, C              ;
  addlw  D'10'                  ;
  subwf  Hours, f               ;
  goto   scl_af                 ;

scl2
  incf   Hours, f               ;
  movlw  D'24'                  ;
  subwf  Hours, w               ;
  btfss  STATUS, Z              ;
  goto   scl2_2                 ;
  movlw  D'20'                  ;
  movwf  Hours                  ;
  goto   scl_af                 ;
scl2_2
  movlw  D'20'                  ;
  subwf  Hours, w               ;
  btfss  STATUS, Z              ;
  goto   scl2_3                 ;
  movlw  D'10'                  ;
  movwf  Hours                  ;
  goto   scl_af                 ;
scl2_3
  movlw  D'10'                  ;
  subwf  Hours, w               ;
  btfss  STATUS, Z              ;
  goto   scl_af                 ;
  clrf   Hours                  ;
  goto   scl_af                 ;

scl3
  movlw  D'10'                  ;
  addwf  Minutes, f             ;
  movlw  D'60'                  ;
  subwf  Minutes, w             ;
  btfss  STATUS, C              ;
  goto   scl_af                 ;
  movlw  D'60'                  ;
  subwf  Minutes, f             ;
  goto   scl_af                 ;

scl4
  movf   Minutes, w             ;
  call   ByteToDec              ;
  movlw  0x39                   ;
  subwf  Asc0, w                ;
  btfss  STATUS, Z              ;
  goto   scl4_1                 ;
  movlw  9                      ;
  subwf  Minutes, f             ;
  goto   scl_af                 ;
scl4_1
  incf   Minutes, f             ;
  goto   scl_af                 ;

scl5
  clrf   Seconds                ;
  clrf   TimerL                 ;
  clrf   TimerH                 ;
  goto   scl_af                 ;


scl_af
  return                        ;



;**********************************************************************
;*                                                                    *
;*     ReadAD0                                                        *
;*                                                                    *
;*     Function: reads the voltage from the RA port 0 (battery)       *
;*                                                                    *
;*     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'10001110'            ; 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.


  fcall  Dlay160                ; Wait the required acquisition time.


  bsf    ADCON0, 2              ; Start the conversion.

  nop                           ;
  btfsc  ADCON0, 2              ; Conversion done?
  goto   $-2                    ; No, keep polling.
  fcall  Dlay160                ; Yes, make ready for next time.
  fcall  Dlay160                ;
  bcf    ADCON0, 0              ; Turn off AD module.

ReadAD0A

  return                        ;

;**********************************************************************
;*                                                                    *
;*     ReadVoltage                                                    *
;*                                                                    *
;*     Function: reads the voltage from the RA port (port number      *
;*               indicated by w, which must be 0, 1 or 5).            *
;*                                                                    *
;*     return: ADRESH:ADRESL                                          *
;*                                                                    *
;*     Assumptions: Vref- 2.0V  (currently 1.990 V)                   *
;*                  Vref+ 4.0V  (currently 3.97 V)                    *
;*                                                                    *
;**********************************************************************
ReadVoltage

  clrf   ADRESH                 ;
  bsf    STATUS, RP0            ; Select bank 1.
  clrf   ADRESL                 ;
  bcf    STATUS, RP0            ; Select bank 0.

  bsf    STATUS, RP0            ; Select bank 1.
  movlw  B'00001000'            ; 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   Dlay5                  ; Yes, make ready for next time.
  bcf    ADCON0, 0              ; Turn off AD module.

  return                        ;



Prolog0
  movlw  B'00101111'            ; Enable RA0, 1, 2, 3 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            ;

  bsf    PORTC, 0               ;

  call   Dlay160                ;

  return                        ;


Epilog0
  bcf    PORTC, 0               ;

  movlw  B'00000011'            ; Enable RC for input.
  bsf    STATUS, RP0            ;
  movwf  TRISC ^ 0x080          ;
  bcf    STATUS, RP0            ;

  bsf    STATUS, RP0            ; Select bank 1.
  movlw  B'10000111'            ; Configure analog pins.
  movwf  ADCON1                 ;
  bcf    STATUS, RP0            ; Select bank 0.

  movlw  B'00101110'            ; Enable RA1, 2, 3 and 5 input, rest output.
  bsf    STATUS, RP0            ;
  movwf  TRISA ^ 0x080          ;
  bcf    STATUS, RP0            ;

  bsf    PORTA, 0               ;

  call   Dlay160                ;
  call   Dlay160                ;

  bcf    PORTA, 0               ;

  movlw  B'00101111'            ; Enable RA0, 1, 2, 3 and 5 input, rest output.
  bsf    STATUS, RP0            ;
  movwf  TRISA ^ 0x080          ;
  bcf    STATUS, RP0            ;

;  call   Dlay160                ;



  return                        ;


;**********************************************************************
;*                                                                    *
;*     readWaterLevel                                                 *
;*                                                                    *
;*     Function: reads the 8 water sensors                            *
;*                                                                    *
;*     return: waterLevel                                             *
;*                                                                    *
;**********************************************************************
readWaterLevel

  clrf   sensorCnt              ;
  clrf   waterLevel             ;


sensorLoop

; Do prolog.
  movlw  B'00101111'            ; Enable RA0, 1, 2, 3 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               ;
#ifndef NOWATER
  bcf    PORTC, 2               ;
  bcf    PORTC, 3               ;
  bcf    PORTC, 4               ;
  bcf    PORTC, 5               ;
  bcf    PORTC, 6               ;
  bcf    PORTC, 7               ;
#endif

  movf   sensorCnt, w           ;
  call   setPortC               ;

  call   Dlay160                ;



; 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'00001000'            ; 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             ;

  movf   sensorCnt, w           ;
  call   trisPortCinput         ;

  bsf    STATUS, RP0            ; Select bank 1.
  movlw  B'10000111'            ; Configure analog pins.
  movwf  ADCON1                 ;
  bcf    STATUS, RP0            ; Select bank 0.

  movlw  B'00101110'            ; Enable RA1, 2, 3 and 5 input, rest output.
  bsf    STATUS, RP0            ;
  movwf  TRISA ^ 0x080          ;
  bcf    STATUS, RP0            ;

  bsf    PORTA, 0               ;
  call   setAllButPortC         ;

  call   Dlay160                ;
  call   Dlay160                ;
  call   Dlay160                ;

  bcf    PORTA, 0               ;

  movlw  B'00101111'            ; Enable RA0, 1, 2, 3 and 5 input, rest output.
  bsf    STATUS, RP0            ;
  movwf  TRISA ^ 0x080          ;
  bcf    STATUS, RP0            ;


; Evaluate result.
  movf   sensorCnt, w           ;
  movf   ADRESH, f              ;
  btfss  STATUS, Z              ;
  call   setWaterBit            ;
  bsf    STATUS, RP0            ; Select bank 1.
  movf   ADRESL, f              ;
  bcf    STATUS, RP0            ; Select bank 0.
  btfss  STATUS, Z              ;
  call   setWaterBit            ;




; End the loop.

  incf   sensorCnt, f           ;
#ifdef NOWATER
  btfss  sensorCnt, 1           ; Sensor 2 is the last sensor.
#else
  btfss  sensorCnt, 3           ; Sensor 8 is the last sensor.
#endif
  goto   sensorLoop             ;


  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                        ;

;**********************************************************************
;*                                                                    *
;*     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               ;

#ifdef NOWATER
  goto   setAllButPortC_af      ;
#endif


  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                        ;

;**********************************************************************
;*                                                                    *
;*     ConvertAD2Temp                                                 *
;*                                                                    *
;*     Function: converts ADRESH:ADRESL to a format that is           *
;*               consistent with AD2Temperature routine.              *
;*               Output is written to the input location.             *
;*                                                                    *
;*               Formulae used: input * 5080 / 1024 - 2474 (before)   *
;*                              input * 2000 / 1024 - 474  (now)      *
;*                                                                    *
;*                                                                    *
;*                                                                    *
;*     return: ADRESH:ADRESL                                          *
;*                                                                    *
;*     Assumptions: Vref- at 2V, Vref+ at 4V.                         *
;*                                                                    *
;*                                                                    *
;*                                                                    *
;*                                                                    *
;*                                                                    *
;*                                                                    *
;**********************************************************************
ConvertAD2Temp
  bsf    STATUS, RP0            ;
  movf   ADRESL, w              ;
  bcf    STATUS, RP0            ;

  movwf  n_1                    ;
  movf   ADRESH, w              ;
  movwf  n_2                    ;

  movlw  0x7                    ;
  movwf  n_4                    ;
  movlw  0xd0                   ;
  movwf  n_3                    ;

  call   Mul1616                ;

  clrf   Dividend               ;
  clrf   Dividend + 1           ;
  movf   q_4, w                 ;
  movwf  Dividend + 2           ;
  movf   q_3, w                 ;
  movwf  Dividend + 3           ;
  movf   q_2, w                 ;
  movwf  Dividend + 4           ;
  movf   q_1, w                 ;
  movwf  Dividend + 5           ;

  clrf   Divisor                ;
  movlw  4                      ;
  movwf  Divisor + 1            ;
  clrf   Divisor + 2            ;

  call   Div4823                ;

  movlw  0xda                   ;
  subwf  Dividend + 5, f        ;
  btfss  STATUS, C              ;
  decf   Dividend + 4, f        ;
  movlw  1                      ;
  subwf  Dividend + 4, f        ;

  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          *
;*               and and does + 500                                   *
;*                                                                    *
;*     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                ;
  call   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                ;
  call   AddBCD                 ;
ByteToVoltage10


  clrf   BCD_A_0                ; Add BCD'500' to result.
  clrf   BCD_A_1                ;
  movlw  5                      ;
  movwf  BCD_A_2                ;
;  call   AddBCD                 ;

  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                        ;



;**********************************************************************
;*                                                                    *
;*     AD2Temp8bit                                                    *
;*                                                                    *
;*     Function: converts 8-bit value in w register to ascii          *
;*               according to the following table:                    *
;*                                                                    *
;*          input        output                                       *
;*          0            -280       (-28.0°)                          *
;*          1            -275       (-27.5°)                          *
;*          2            -270       (-27.0°)                          *
;*          .                                                         *
;*          .                                                         *
;*          55           -005       (-00.5°)                          *
;*          56           +000       (+00.0°)                          *
;*          57           +005       (+00.5°)                          *
;*          .                                                         *
;*          .                                                         *
;*          255          +995       (+99.5°)                          *
;*                                                                    *
;*                                                                    *
;*     return: Asc0, Asc1, Asc2 and Asc3                              *
;*                                                                    *
;*             Asc0: contains + or -                                  *
;*             Asc1: tens of temperature                              *
;*             Asc2: ones of temperature                              *
;*             Asc3: tenths of temperature                            *
;*                                                                    *
;*                                                                    *
;*                                                                    *
;**********************************************************************
AD2Temp8bit

  movwf  TempByte               ;
  movlw  D'56'                  ; If input >= 56, then temperature is
  subwf  TempByte, w            ; positive, else negative.
  btfsc  STATUS, C              ;
  goto   TempPositive           ;
  movlw  D'45'                  ;
  movwf  Asc3                   ;
  clrf   BCD_B_0                ; Perform 56 - input, result in BCD_B.
  movlw  D'56'                  ;
  movwf  BCD_B_0                ;
  movf   TempByte, w            ;
  subwf  BCD_B_0, f             ;
  goto   TempSamen              ;
TempPositive
  movlw  D'43'                  ;
  movwf  Asc3                   ;
  movf   TempByte, w            ; Perform input - 56, result in BCD_B.
  movwf  BCD_B_0                ;
  movlw  D'56'                  ;
  subwf  BCD_B_0, f             ;
TempSamen
  movlw  0x30                   ;
  btfsc  TempByte, 0            ; Test if half a degree.
  movlw  0x35                   ;
  movwf  Asc0                   ;

  movf   BCD_B_0, w             ;
  movwf  TempByte               ;
  bcf    STATUS, C              ;
  rrf    TempByte, f            ; TempByte = TempByte / 2.


; Input is in 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                     ;
ad2tm999a                       ; 9 cycles max
  addwf  BCD_B_0, f             ;
  decf   BCD_B_1, f             ;
  skpc                          ;
  goto   ad2tm999a              ;

ad2tm999b                       ; 6 cycles max
  addwf  BCD_B_1, f             ;
  decf   BCD_B_2, f             ;
  skpc                          ;
  goto   ad2tm999b              ;

ad2tm999c                       ; 3 cycles max
  addwf  BCD_B_2, f             ;
  skpc                          ;
  goto   ad2tm999c              ;



  movf   BCD_B_0, w             ;
  addlw  0x30                   ;
  movwf  Asc1                   ;
  movf   BCD_B_1, w             ;
  addlw  0x30                   ;
  movwf  Asc2                   ;


  return                        ;



;**********************************************************************
;*                                                                    *
;*     AD2Temperature                                                 *
;*                                                                    *
;*     Function: converts AD value in ADRESH:ADRESL to ascii          *
;*                                                                    *
;*          input        output                                       *
;*          0 -> 255     256 -> 001  (-25.6° -> -0.1°)                *
;*          256 -> 1023  0 -> 767    (+0° -> +76.7°)                  *
;*                                                                    *
;*                                                                    *
;*                                                                    *
;*     return: Asc0, Asc1, Asc2 and Asc3                              *
;*                                                                    *
;*             Asc0: contains + or -                                  *
;*             Asc1: tens of temperature                              *
;*             Asc2: ones of temperature                              *
;*             Asc3: tenths of temperature                            *
;*                                                                    *
;*                                                                    *
;*                                                                    *
;**********************************************************************
AD2Temperature
  movf   ADRESH, f              ; If input >= 256, then temperature is
  btfss  STATUS, Z              ; positive, else negative.
  goto   TempPOS                ;
  movlw  D'45'                  ;
  movwf  Asc3                   ;
  clrf   BCD_B_0                ; Perform 256 - AD, result in BCD_B.
  movlw  1                      ;
  movwf  BCD_B_1                ;
  bsf    STATUS, RP0            ;
  movf   ADRESL, w              ;
  bcf    STATUS, RP0            ;
  subwf  BCD_B_0, f             ;
  movf   ADRESH, w              ;
  btfss  STATUS, C              ;
  decf   BCD_B_1, f             ;
  subwf  BCD_B_1, f             ;
  goto   TempSAM                ;
TempPOS
  movlw  D'43'                  ;
  movwf  Asc3                   ;
  movf   ADRESH, w              ; Perform AD - 256, result in BCD_B.
  movwf  BCD_B_1                ;
  bsf    STATUS, RP0            ;
  movf   ADRESL, w              ;
  bcf    STATUS, RP0            ;
  movwf  BCD_B_0                ;
  decf   BCD_B_1, f             ;
TempSAM
  movf   BCD_B_1, w             ; Move BCD_B to AD.
  movwf  ADRESH                 ;
  movf   BCD_B_0, w             ;
  bsf    STATUS, RP0            ;
  movwf  ADRESL                 ;
  bcf    STATUS, RP0            ;


  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                     ;
ad2tem999a                      ; 9 cycles max
  addwf  BCD_B_0, f             ;
  decf   BCD_B_1, f             ;
  skpc                          ;
  goto   ad2tem999a             ;

ad2tem999b                      ; 6 cycles max
  addwf  BCD_B_1, f             ;
  decf   BCD_B_2, f             ;
  skpc                          ;
  goto   ad2tem999b             ;

ad2tem999c                      ; 3 cycles max
  addwf  BCD_B_2, f             ;
  skpc                          ;
  goto   ad2tem999c             ;

  btfss  ADRESH, 0              ;
  goto   AD2temp9               ;
  movlw  6                      ;
  movwf  BCD_A_0                ;
  movlw  5                      ;
  movwf  BCD_A_1                ;
  movlw  2                      ;
  movwf  BCD_A_2                ;
  clrf   BCD_A_3                ;
  call   AddBCD                 ;
AD2temp9
  btfss  ADRESH, 1              ;
  goto   AD2temp10              ;
  movlw  2                      ;
  movwf  BCD_A_0                ;
  movlw  1                      ;
  movwf  BCD_A_1                ;
  movlw  5                      ;
  movwf  BCD_A_2                ;
  call   AddBCD                 ;
AD2temp10


  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                   ;

  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                        ;


;**********************************************************************
;*                                                                    *
;*     HexToAscii                                                     *
;*                                                                    *
;*     Function: converts hex number in w into two ascii bytes        *
;*                                                                    *
;*     return: HexToAsciiResult_L, HexToAsciiResult_H                 *
;*                                                                    *
;**********************************************************************
HexToAscii

  movwf  HexTemp                ; Store w for later.

  andlw  0x0f                   ;
  sublw  0x09                   ;
  movf   HexTemp, w             ;
  andlw  0x0f                   ;
  btfss  STATUS, C              ;
  addlw  7                      ;
  addlw  0x30                   ;
  movwf  HexToAsciiResult_L     ;

  swapf  HexTemp, w             ; Process high nibble.
  andlw  0x0f                   ;
  sublw  0x09                   ;
  swapf  HexTemp, w             ;
  andlw  0x0f                   ;
  btfss  STATUS, C              ;
  addlw  7                      ;
  addlw  0x30                   ;
  movwf  HexToAsciiResult_H     ;
        
  return                        ;




;**********************************************************************
;*                                                                    *
;*     Mul1616                                                        *
;*                                                                    *
;*     Function: multiplies a 16 bit number with a 16 bit number.     *
;*                                                                    *
;*     n_2 : n1 * n_4 : n_3 -> q_4 : q_3 : q_2 : q_1                  *
;*                                                                    *
;*                                                                    *
;*                                                                    *
;*     return: q_4:q_3:q_2:q_1                                        *
;*                                                                    *
;**********************************************************************
Mul1616

  
  clrf   q_4                    ;
  clrf   q_3                    ;
  clrf   q_2                    ;
  clrf   q_1                    ;
  bsf    q_2, 7                 ;

m1
  rrf    n_2, f                 ;
  rrf    n_1, f                 ;
  skpc                          ;
  goto   m2                     ;
  movf   n_3, w                 ;
  addwf  q_3, f                 ;
  movf   n_4, w                 ;
  skpnc                         ;
  incfsz n_4, w                 ;
  addwf  q_4, f                 ;

m2
  rrf    q_4, f                 ;
  rrf    q_3, f                 ;
  rrf    q_2, f                 ;
  rrf    q_1, f                 ;
  skpc                          ;
  goto   m1                     ;


  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               ;

  clrf   Temp2                  ;

  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.


;**********************************************************************
;*                                                                    *
;*     beep                                                           *
;*                                                                    *
;*     Function: beeps a speaker which is connected between RC0 and   *
;*     RC1 (with 50 nF capacitor in between). Upon entry, the         *
;*     variables duratn and freq must be filled with duration and     *
;*     frequency.                                                     *
;*                                                                    *
;*                                                                    *
;*     params: duratn and freq, see description                       *
;*     return: none                                                   *
;*                                                                    *
;**********************************************************************
;
; The beep routine beeps a speaker which is connected between
; RC0 and RC1 (with 50nF capacitor in between). Upon entry,
; the variables duratn and freq must be filled with duration and
; frequency.
beep
  bcf    PORTC, 0               ; Start with alternating pattern.
  bsf    PORTC, 1               ;
  movlw  B'00000011'            ; All ones to invert all bits in port C.
  movwf  t_pat                  ;
  movf   freq, w                ;
  movwf  f_temp                 ;
  movf   freq, f                ;
  btfsc  STATUS, Z              ; If freq is zero, fill pattern with
                                ; zeros
  clrf   t_pat                  ; ..for a silent pause.
  movf   duratn, w              ; Variable duratn goes into the
  movwf  d_hi                   ; high byte
  clrf   d_lo                   ; ..of a 16-bit counter.
  movf   t_pat, w               ;
  movwf  tgl                    ;
beeplus
  movf   tgl, w                 ;
  xorwf  PORTC, f               ; XORing the speaker bits with 1s
                                ; inverts them.
  nop                           ; Zeros have no effect.
  nop                           ; Nops pad main loop to 20µs.
  nop                           ;
  decfsz f_temp, f              ; When f_temp reaches zero,
  goto   noRoll1                ;
  movf   freq, w                ; reload the freq. value and put
  movwf  f_temp                 ; tgl_pat into tgl in order to
  movf   t_pat, w               ; invert the speaker bits on the
  movwf  tgl                    ; next loop.
dur_lo
  movlw  1                      ; Decrement low byte of duration.
  subwf  d_lo, f                ;
  btfsc  STATUS, C              ; If no borrow, go to noRoll2.
  goto   noRoll2                ;
  decfsz d_hi, f                ; Decrement the high byte of duration
  goto   beeplus                ; and if overflow, routine is done.
  bcf    PORTC, 0               ; No volts on speaker when leaving..
  bcf    PORTC, 1               ;
  return                        ;
noRoll1
  clrf   tgl                    ; If f_temp is not zero, don't
  goto   dur_lo                 ; pluck the speaker.
noRoll2
  nop                           ; Waste time to ensure that all
  nop                           ; paths through the routine take 20µs.
  goto   beeplus                ;



;**********************************************************************
;*                                                                    *
;*     InputString                                                    *
;*                                                                    *
;*     Function: inputs a string of max. 5 characters from the        *
;*               keypad. Chars input can only by 0 - 9, A - B, and    *
;*               *. The # character ends the input (functions as      *
;*               enter key). The string is shown on the LCD as it is  *
;*               typed. The * character is interpreted as a decimal   *
;*               point (.).                                           *
;*                                                                    *
;*                                                                    *
;*     return: strA..strE                                             *
;*                                                                    *
;**********************************************************************
InputString

  movlw  D'32'                  ; Initialize string with spaces.
  movwf  strA                   ;
  movwf  strB                   ;
  movwf  strC                   ;
  movwf  strD                   ;
  movwf  strE                   ;

  movlw	 0x001			; Clear the Display RAM.
  call	 SendINS                ;
  call	 Dlay5			; Note, can take up to 4.1 msecs.

  movlw  67
  call   SendCHAR
  movlw  111
  call   SendCHAR
  movlw  100
  call   SendCHAR
  movlw  101
  call   SendCHAR
  movlw  58
  call   SendCHAR


  movlw  0x0f                   ; Cursor on.
  call   SendINS                ;
  call   Dlay160                ;


  movlw  strA                   ;
  movwf  FSR                    ;

InputStringLoop

  btfsc  key, 4                 ;
  goto   keyTestAf              ;


  movlw  D'11'                  ; Enter pressed?
  subwf  key, w                 ;
  btfsc  STATUS, Z              ;
  goto   EnterPressed           ;

  incf   key, f                 ;
  movlw  LOW lut                ; Get low 8 bits of table.
  addwf  key, f                 ; Do an 8-bit add operation.
  movlw  HIGH lut               ; 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   key, w                 ; Load computed offset in w register.

  call   lut                    ;
  movwf  INDF                   ;
  call   SendCHAR               ;
  incf   FSR, f                 ;

  movlw  strD
  subwf  FSR, w
  btfss  STATUS, Z
  goto   new_line_af
  movlw	 0x0C0			; Move cursor.
  call	 SendINS                ;
  call	 Dlay160                ; Note, can take up to 160 usecs.
new_line_af

  call   Dlay20
  call   Dlay20

  movlw  0x10                   ; Ready for next time.
  movwf  key                    ;


  movlw  strE                   ;
  addlw  1                      ;
  subwf  FSR, w                 ;
  btfsc  STATUS, Z              ; All done?
  goto   EnterPressed           ;


keyTestAf    

  goto   InputStringLoop        ;

EnterPressed

  movlw  0x10                   ; Ready for next time.
  movwf  key                    ;


  movlw  0x0c                   ; Cursor off.
  call   SendINS                ;
  call   Dlay160                ;

  return                        ; Return with value in key.


lut
  movwf  PCL                    ;
  DT "147*2580369#ABCD"






  end


