; ****************************************************************************
; * PIC-EL - Diagnostic                                                      *
; *  Version 1.5                                                             *
; *  February 26, 2006                                                       *
; *                                                                          *
; ****************************************************************************
; Author - Craig B. Johnson, AA0ZZ                                           *
;                                                                            *
; Description:                                                               *
;   LCD                                                                      *
;   Speaker (tone)                                                           *
;   pushbuttons                                                              *
;   LEDs                                                                     *
;   Encoder                                                                  *
;   Paddles                                                                  *
;   DDS_30                                                                   *
;   DDS_60                                                                   *
;                                                                            *
;*****************************************************************************
; Modification History
;    1/29/06 - v1.0  Initial Version 
;    2/2/06  - v1.1 - LCD, speaker, pushbutton tests work
;    2/4/06  - v1.2 - Encoder test works
;    2/7/06  - v1.3 - Fixes
;    2/16/06 - v1.4 - DDS_30, DDS_60, Transmitter Keying
;    2/26/06 - v1.5 - Fix minor bug in keying test      
;*****************************************************************************
;                                                                              
; Target Controller -      PIC16F628 in PIC-EL board                            
;                          __________                                          
;     PB_3-Speaker----RA2 |1       18| RA1---------ENCODER A                   
;     PB_2-Bandswitch-RA3 |2       17| RA0---------ENCODER B                   
;     PB_1-Tuning etc-RA4 |3       16| OSC1--------XTAL                        
;     +5V-----------!MCLR |4       15| OSC2--------XTAL                        
;     Ground----------Vss |5       14| VDD---------+5 V                        
;     LCD11-----------RB0 |6       13| RB7---------DDS_LOAD/Transmitter                   
;     LCD12-----------RB1 |7       12| RB6---------LCD_rs  (LCD Pin 4)         
;     LCD13/DDS_CLK---RB2 |8       11| RB5---------LCD_rw  (LCD Pin 5)           
;     LCD14/DDS_DATA--RB3 |9       10| RB4---------LCD_e   (LCD Pin 6)         
;                          ----------                                          
;                                                                              
; ****************************************************************************
; * Device type and options.                                                 *
; ****************************************************************************
;
        processor       PIC16F628
        radix           dec
;
; ****************************************************************************
; * Configuration fuse information for 16F628:                               *
; ****************************************************************************

_BODEN_ON                    EQU     H'3FFF'
_BODEN_OFF                   EQU     H'3FBF'
_CP_ALL                      EQU     H'03FF'
_CP_75                       EQU     H'17FF'
_CP_50                       EQU     H'2BFF'
_CP_OFF                      EQU     H'3FFF'
_PWRTE_OFF                   EQU     H'3FFF'
_PWRTE_ON                    EQU     H'3FF7'
_WDT_ON                      EQU     H'3FFF'
_WDT_OFF                     EQU     H'3FFB'
_LVP_ON                      EQU     H'3FFF'
_LVP_OFF                     EQU     H'3F7F'
_MCLRE_ON                    EQU     H'3FFF'
_MCLRE_OFF                   EQU     H'3FDF'
_ER_OSC_CLKOUT               EQU     H'3FFF'
_ER_OSC_NOCLKOUT             EQU     H'3FFE'
_INTRC_OSC_CLKOUT            EQU     H'3FFD'
_INTRC_OSC_NOCLKOUT          EQU     H'3FFC'
_EXTCLK_OSC                  EQU     H'3FEF'
_LP_OSC                      EQU     H'3FEC'
_XT_OSC                      EQU     H'3FED'
_HS_OSC                      EQU     H'3FEE'

 __config _CP_OFF&_LVP_OFF&_BODEN_OFF&_MCLRE_ON&_PWRTE_ON&_WDT_OFF&_XT_OSC  

;
; *************************************************************************** 
; Info for power-up display                                                   
MCODE_REV_0  equ  '1'     ; Current code version is 1.5                     
MCODE_REV_1  equ  '.'     ;                                                   
MCODE_REV_2  equ  '5'     ;                                                   
MCODE_REV_3  equ  ' '     ;
;                                                                             
; ****************************************************************************
; *                    Port and EEPROM Constants                             *
; ****************************************************************************
;
PortA   equ     0x05
PortB   equ     0x06
TRISA   equ     0x85          ;
TRISB   equ     0x86          ;
EEdata  equ     0x9A          ; Changed for 16F628
EEadr   equ     0x9B          ; Changed for 16F628
EECON1  equ     0x9C          ; New for 16F628
WREN    equ     0x02
WR      equ     0x01
RD      equ     0x00
CMCON   equ     0x1F
;
; ****************************************************************************
; * ID location information:                                                 *
; * (MPASM warns about DW here, don't worry)                                 *
; ****************************************************************************
;
        ORG     0x2000
        DATA    0x007F
        DATA    0x007F
        DATA    0x007F
        DATA    0x007F
;
;
; ****************************************************************************
; * Setup the initial constant, based on the frequency of the reference      *
; * oscillator.  This can be tweaked with the calibrate function.            *
; ****************************************************************************
; 
        ORG     0x2100
;       Clear unused EEPROM bytes (128 bytes for 16F628)
;
        DATA    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
        DATA    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0           
        DATA    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
        DATA    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0           
        DATA    0,0,0,0,0,0,0,0
;
; ****************************************************************************
; * RAM page independent file registers:                                     *
; ****************************************************************************
;
INDF    EQU     0x00
PCL     EQU     0x02
STATUS  EQU     0x03
FSR     EQU     0x04
PCLATH  EQU     0x0A
INTCON  EQU     0x0B
;
; *****************************************************************************
; * Bit numbers for the STATUS file register:                                 *
; *****************************************************************************
;
B_RP0   EQU     5
B_NTO   EQU     4
B_NPD   EQU     3
B_Z     EQU     2
B_DC    EQU     1
B_C     EQU     0
;
; ****************************************************************************
; * Assign names to IO pins.                                                 *
; ****************************************************************************
;
;   B register bits:
;
DDS_clk equ     2                 ; AD9850/AD9851 write clock
DDS_dat equ     3                 ; AD9850/AD9851 serial data input
LCD_busy equ    3                 ; LCD busy bit 
LCD_e   equ     4                 ; 0=disable, 1=enable
LCD_rw  equ     5                 ; 0=write, 1=read
LCD_rs  equ     6                 ; 0=instruction, 1=data
DDS_load equ    7                 ; Update pin on AD9850/AD9851

LED_1   equ     3                 ;
LED_2   equ     2                 ;
LED_3   equ     1                 ;

XMIT    equ     7                 ; Transmit Keying
; 
;   A register bits:
;
pb_1      equ   0x04              ; Tuning-increment/Calibrate Pushbutton      
pb_2      equ   0x03              ; Bandswitch Pushbutton,                     
pb_3      equ   0x02              ; PB also on this pin                        
speaker   equ   0x02              ; Speaker (always exit with a low output)    

; ****************************************************************************
; * General Equates                                                          *
; ****************************************************************************
OSC_100MHZ_3   equ  0x2A          ; Most significant osc byte
OSC_100MHZ_2   equ  0xF3          ; Next byte
OSC_100MHZ_1   equ  0x1D          ; Next byte
OSC_100MHZ_0   equ  0xC4          ; Least significant byte

; DDS_60 is 180 MHz (30 MHz clock and 6x multiplier)
OSC_180MHZ_3   equ  0x17          ; Most significant osc byte
OSC_180MHZ_2   equ  0xDC          ; Next byte
OSC_180MHZ_1   equ  0x65          ; Next byte
OSC_180MHZ_0   equ  0xDE          ; Least significant byte

; ****************************************************************************
; *           Allocate variables in general purpose register space           *
; ****************************************************************************
;
        CBLOCK  0x20              ; Start Data Block
;
        osc_0                     ; Display oscillator frequency 
          osc_1                   ;  (4 bytes) 
          osc_2
          osc_3         
        osc_temp_0                ; Display temporary oscillator bytes
          osc_temp_1              ;  (4 bytes) 
          osc_temp_2
          osc_temp_3       
        freq_0                    ; Display frequency (hex) 
          freq_1                  ;  (4 bytes) 
          freq_2
          freq_3         
        BCD_0                     ; Display frequency (BCD) 
          BCD_1                   ;  (5 bytes)
          BCD_2
          BCD_3
          BCD_4     
        fstep_0                   ; Frequency inc/dec 
          fstep_1                 ;  (4 bytes)
          fstep_2
          fstep_3
        BCD_count                 ; Used in bin2BCD routine
        BCD_temp                  ;   "
        mult_count                ; Used in calc_dds_word 
        bit_count                 ;   "
        byte2send                 ;
        LCD_char                  ; Character being sent to the LCD
        LCD_read                  ; Character read from the LCD
        timer1                    ; Used in delay routines
        timer2                    ;   "
        ren_timer_0               ; For variable rate tuning 
          ren_timer_1             ;  (2 bytes)
        ren_new                   ; New value of encoder pins A and B
        ren_old                   ; Old value of encoder pins A and B
        ren_read                  ; Encoder pins A and B and switch pin
        last_dir                  ; Indicates last direction of encoder
        next_dir                  ; Indicates expected direction
        count                     ; loop counter  (gets reused)
        rs_value                  ; The LCD rs line flag value
        PB_flags                  ; Pushbutton flags                          
        LoopCounter1              ; Loop counter 
        LoopCounter2              ; Loop counter 
        LoopCounter3              ; Loop counter 
        LoopCounter4              ; Loop counter 
        AD985X_0                  ; DDS frequency constants
        AD985X_1                  ;
        AD985X_2                  ;
        AD985X_3                  ;
        AD985X_4                  ;
        DDS_flag                  ; Flag - Bit 0 = 1 if AD9851, 0 if AD9850
;
        ENDC                      ; End of Data Block
; 
; ****************************************************************************
; * The 16F628 resets to 0x00.                                               * 
; * The Interrupt vector is at 0x04. (Unused)                                *
; ****************************************************************************             
;
        ORG     0x0000                
reset_entry
        goto    start             ; Jump around the band table to main program
;
; *****************************************************************************
; *                                                                           *
; * Purpose:  This is the start of the program.  It initializes the LCD       *
; *           writes the version on the screen.                               *
; *                                                                           *
; *****************************************************************************
;
start
        clrf    INTCON            ; No interrupts for now
        movlw   0x07              ; Code to turn off the analog comparitors
        movwf   CMCON             ; Turn off comparators
        call    wait_8ms          ; Wait for LCD to settle. 
        bsf     STATUS,B_RP0      ; Switch to bank 1
        bcf     0x01,7            ; Enable weak pullups                        
        movlw   0xFF              ; Tristate PortA 
        movwf   TRISA             ;
        clrf    TRISB             ; Set port B to all outputs
        bcf     STATUS,B_RP0      ; Switch back to bank 0
        call    init_LCD          ; Initialize the LCD
        call    display_version   ; Display title and version                  
;
; *****************************************************************************
; * Purpose:  Main Menu Loop                                                  *
; *****************************************************************************
Menu
        call    Test_LEDs_Menu        ; Test 1   
        call    wait_256ms
        call    Test_Pushbuttons_Menu ; Test 2
        call    wait_256ms
        call    Test_Speaker_Menu     ; Test 3
        call    wait_256ms
        call    Test_Encoder_Menu     ; Test 4
        call    wait_256ms
        call    Test_Paddles_Menu     ; Test 5
        call    wait_256ms
        call    Test_Transmitter_Menu ; Test 6
        call    wait_256ms
        call    Test_DDS_30_Menu      ; Test 7
        call    wait_256ms
        call    Test_DDS_60_Menu      ; Test 8
        call    wait_256ms
        goto    Menu              ; Repeat forever

; *****************************************************************************
; * Purpose:  Write_Menu_Line1                                                *
; *****************************************************************************
Write_Menu_Line1
        movlw   0x80              ; Point LCD at digit 1                
        call    cmnd2LCD          ;
        movlw   'M'               ; digit 1              
        call    data2LCD          ;
        movlw   'e'               ; digit 2                  
        call    data2LCD          ;
        movlw   'n'               ; digit 3                
        call    data2LCD          ;
        movlw   'u'               ; digit 4               
        call    data2LCD          ;
        movlw   ' '               ; digit 5               
        call    data2LCD          ;
        movlw   '('               ; digit 6              
        call    data2LCD          ;
        movlw   'U'               ; digit 7              
        call    data2LCD          ;        
        movlw   's'               ; digit 8              
        call    data2LCD          ;
        movlw   'e'               ; digit 9               
        call    data2LCD          ;
        movlw   ' '               ; digit 10              
        call    data2LCD          ;
        movlw   'P'               ; digit 11              
        call    data2LCD          ;
        movlw   'B'               ; digit 12              
        call    data2LCD          ;
        movlw   '3'               ; digit 13              
        call    data2LCD          ;
        movlw   ')'               ; digit 14              
        call    data2LCD          ;
        movlw   ' '               ; digit 15              
        call    data2LCD          ;
        movlw   ' '               ; digit 16              
        call    data2LCD          ;
        return 
;
; *****************************************************************************
; * Purpose:  Write_Menu_Line1                                                *
; *****************************************************************************
Write_Press_Message_Line2
        movlw   0xC0              ; Point LCD at second line digit 1                
        call    cmnd2LCD          ;
        movlw   'P'               ; digit 1              
        call    data2LCD          ;
        movlw   'r'               ; digit 2                  
        call    data2LCD          ;
        movlw   'e'               ; digit 3                
        call    data2LCD          ;
        movlw   's'               ; digit 4               
        call    data2LCD          ;
        movlw   's'               ; digit 5               
        call    data2LCD          ;
        movlw   ' '               ; digit 6              
        call    data2LCD          ;
        movlw   'P'               ; digit 7              
        call    data2LCD          ;        
        movlw   'B'               ; digit 8              
        call    data2LCD          ;
        movlw   '3'               ; digit 9               
        call    data2LCD          ;
        movlw   ' '               ; digit 10              
        call    data2LCD          ;
        movlw   't'               ; digit 11              
        call    data2LCD          ;
        movlw   'o'               ; digit 12              
        call    data2LCD          ;
        movlw   ' '               ; digit 13              
        call    data2LCD          ;
        movlw   'e'               ; digit 14              
        call    data2LCD          ;
        movlw   'n'               ; digit 15              
        call    data2LCD          ;
        movlw   'd'               ; digit 16              
        call    data2LCD          ;
        return 
;
; *****************************************************************************
; * Purpose:  Detect_Pushbutton_3                                             *
; *                                                                           *
; *****************************************************************************
Detect_Pushbutton_3
        clrf    LoopCounter1      ; Initialize test loop counter
; Wait for pb_3 for (256*256*13us) = .85 seconds
        clrf    LoopCounter2      ; Initialize test loop counter
        clrf    LoopCounter3      ; Initialize test loop counter
Detect_loop1
        call    wait_10us
        btfss   PortA,pb_3        ; pb_3 pressed? 
        goto    Detect_Release_Wait; Yes, go to wait
        incfsz  LoopCounter3,F    ; More loops needed for look time?
        goto    Detect_loop1      ; Yes, keep looking. Loop back and try again
        incfsz  LoopCounter2,F    ; More loops needed for look time?
        goto    Detect_loop1      ; Yes, keep looking. Loop back and try again
        goto    Detect_Exit_No_PB ; No, exit from this test
                                  ; Yes, fall through and wait for release
Detect_Release_Wait
        call    wait_200us        ; Avoid noise and contact bounce
Detect_Release_Wait_Loop ;                                                           
        btfss   PortA,pb_3        ; Is pb_3 still behing held?                 
        goto    Detect_Release_Wait_Loop; No, continue waiting for release (forever) 
        movlw   1                 ; Yes, set flag
        goto    Detect_Exit
Detect_Exit_No_PB
        clrw                      ; Flag - No Pushbutton detected
Detect_Exit
        iorlw   0x00              ; Set up Z flag from W 
        return
;
; *****************************************************************************
; * Purpose:  Test_LEDs                                                       *
; *                                                                           *
; *****************************************************************************
Test_LEDs_Menu
        call    Write_Menu_Line1 
;
        movlw   0xc0              ; Point LCD at second line digit 1                
        call    cmnd2LCD          ;
        movlw   '1'               ; digit 1              
        call    data2LCD          ;
        movlw   ')'               ; digit 2                  
        call    data2LCD          ;
        movlw   ' '               ; digit 3                
        call    data2LCD          ;
        movlw   'L'               ; digit 4               
        call    data2LCD          ;
        movlw   'E'               ; digit 5               
        call    data2LCD          ;
        movlw   'D'               ; digit 6              
        call    data2LCD          ;
        movlw   's'               ; digit 7              
        call    data2LCD          ;        
        movlw   ' '               ; digit 8              
        call    data2LCD          ;
        movlw   ' '               ; digit 9               
        call    data2LCD          ;
        movlw   ' '               ; digit 10              
        call    data2LCD          ;
        movlw   ' '               ; digit 11              
        call    data2LCD          ;
        movlw   ' '               ; digit 12              
        call    data2LCD          ;
        movlw   ' '               ; digit 13              
        call    data2LCD          ;
        movlw   ' '               ; digit 14              
        call    data2LCD          ;
        movlw   ' '               ; digit 15              
        call    data2LCD          ;
        movlw   ' '               ; digit 16              
        call    data2LCD          ;
;
        call    Detect_Pushbutton_3
        btfsc   STATUS,B_Z        ; Is detection flag set? (W=1,Z=0 if pushed)
        goto    Test_LEDs_Exit    ; (Z=0) button not pushed so exit     
                                  ; (Z=1) button pushed so start test
;
        movlw   0x80              ; Point LCD at first line digit 1                
        call    cmnd2LCD          ;
        movlw   'L'               ; digit 1              
        call    data2LCD          ;
        movlw   'E'               ; digit 2                  
        call    data2LCD          ;
        movlw   'D'               ; digit 3                
        call    data2LCD          ;
        movlw   ' '               ; digit 4               
        call    data2LCD          ;
        movlw   'T'               ; digit 5               
        call    data2LCD          ;
        movlw   'e'               ; digit 6              
        call    data2LCD          ;
        movlw   's'               ; digit 7              
        call    data2LCD          ;        
        movlw   't'               ; digit 8              
        call    data2LCD          ;
        movlw   ' '               ; digit 9               
        call    data2LCD          ;
        movlw   ' '               ; digit 10              
        call    data2LCD          ;
        movlw   ' '               ; digit 11              
        call    data2LCD          ;
        movlw   ' '               ; digit 12              
        call    data2LCD          ;
        movlw   ' '               ; digit 13              
        call    data2LCD          ;
        movlw   ' '               ; digit 14              
        call    data2LCD          ;
        movlw   ' '               ; digit 15              
        call    data2LCD          ;
        movlw   ' '               ; digit 16              
        call    data2LCD          ;

        call    Write_Press_Message_Line2
;
;
; Start LED test
; Blink the LEDs
        bcf     PortB,LED_1       ; Turn on 1
        bcf     PortB,LED_2       ; Turn on 2
        bcf     PortB,LED_3       ; Turn on 3
Test_LEDs

; Gets here 
        bsf     PortB,LED_1       ; Turn off 1
        bsf     PortB,LED_2       ; Turn off 2
        bsf     PortB,LED_3       ; Turn off 3
Test_LED_1
        bcf     PortB,LED_1       ; Turn ON LED_1
        call    wait_256ms   
        bsf     PortB,LED_1       ; Turn off LED_1
;
        call    Detect_Pushbutton_3
        btfss   STATUS,B_Z        ; Is detection flag set? (W=1,Z=0 if pushed)
        goto    Test_LEDs_Exit    ; (Z=1) Button pushed so exit
                                  ; (Z=0) Button not pushed so continue
Test_LED_2
        bcf     PortB,LED_2       ; Turn ON LED_2
        call    wait_256ms   
        bsf     PortB,LED_2       ; Turn off LED_2
;
        call    Detect_Pushbutton_3
        btfss   STATUS,B_Z        ; Is detection flag set? (W=1,Z=0 if pushed)
        goto    Test_LEDs_Exit    ; (Z=1) Button pushed so exit
                                  ; (Z=0) Button not pushed so continue
Test_LED_3
        bcf     PortB,LED_3       ; Turn ON LED_3
        call    wait_256ms   
        bsf     PortB,LED_3       ; Turn off LED_3
;
        call    Detect_Pushbutton_3
        btfss   STATUS,B_Z        ; Is detection flag set? (W=1,Z=0 if pushed)
        goto    Test_LEDs_Exit    ; (Z=1) Button pushed so exit
                                  ; (Z=0) Button not pushed so continue
Test_LED_ALL
        bcf     PortB,LED_1       ; Turn ON LED_1
        bcf     PortB,LED_2       ; Turn ON LED_2
        bcf     PortB,LED_3       ; Turn ON LED_3
        call    wait_256ms   
        bsf     PortB,LED_1       ; Turn off LED_1
        bsf     PortB,LED_2       ; Turn off LED_2
        bsf     PortB,LED_3       ; Turn off LED_3
;
        call    Detect_Pushbutton_3
        btfsc   STATUS,B_Z        ; Is detection flag set? (W=1,Z=0 if pushed)
        goto    Test_LED_1        ; (Z=0) Loop back to start of LED tests
                                  ; (Z=1) Fall through to exit
Test_LEDs_Exit
        return

; *****************************************************************************
; * Purpose:  Test_Pushbuttons                                                *
; *                                                                           *
; *****************************************************************************
Test_Pushbuttons_Menu
        call    Write_Menu_Line1 
;
        movlw   0xc0              ; Point LCD at second line digit 1                
        call    cmnd2LCD          ;
        movlw   '2'               ; digit 1              
        call    data2LCD          ;
        movlw   ')'               ; digit 2                  
        call    data2LCD          ;
        movlw   ' '               ; digit 3                
        call    data2LCD          ;
        movlw   'P'               ; digit 4               
        call    data2LCD          ;
        movlw   'u'               ; digit 5               
        call    data2LCD          ;
        movlw   's'               ; digit 6              
        call    data2LCD          ;
        movlw   'h'               ; digit 7              
        call    data2LCD          ;        
        movlw   'b'               ; digit 8              
        call    data2LCD          ;
        movlw   'u'               ; digit 9               
        call    data2LCD          ;
        movlw   't'               ; digit 10              
        call    data2LCD          ;
        movlw   't'               ; digit 11              
        call    data2LCD          ;
        movlw   'o'               ; digit 12              
        call    data2LCD          ;
        movlw   'n'               ; digit 13              
        call    data2LCD          ;
        movlw   's'               ; digit 14              
        call    data2LCD          ;
        movlw   ' '               ; digit 15              
        call    data2LCD          ;
        movlw   ' '               ; digit 16              
        call    data2LCD          ;
; 
        call    Detect_Pushbutton_3
        btfsc   STATUS,B_Z        ; Is detection flag set? (W=1,Z=0 if pushed)
        goto    Test_Pushbuttons_Exit ; (Z=0) button not pushed so exit     
                                  ; (Z=1) button pushed so start test

        movlw   0x80              ; Point LCD at first line digit 1                
        call    cmnd2LCD          ;
        movlw   'P'               ; digit 1              
        call    data2LCD          ;
        movlw   'u'               ; digit 2                  
        call    data2LCD          ;
        movlw   's'               ; digit 3                
        call    data2LCD          ;
        movlw   'h'               ; digit 4               
        call    data2LCD          ;
        movlw   'b'               ; digit 5               
        call    data2LCD          ;
        movlw   'u'               ; digit 6              
        call    data2LCD          ;
        movlw   't'               ; digit 7              
        call    data2LCD          ;        
        movlw   't'               ; digit 8              
        call    data2LCD          ;
        movlw   'o'               ; digit 9               
        call    data2LCD          ;
        movlw   'n'               ; digit 10              
        call    data2LCD          ;
        movlw   ' '               ; digit 11              
        call    data2LCD          ;
        movlw   'T'               ; digit 12              
        call    data2LCD          ;
        movlw   'e'               ; digit 13              
        call    data2LCD          ;
        movlw   's'               ; digit 14              
        call    data2LCD          ;
        movlw   't'               ; digit 15              
        call    data2LCD          ;
        movlw   ' '               ; digit 16              
        call    data2LCD          ;
;
        call    Write_Press_Message_Line2
;
; Start Pushbutton test
; 
Test_Pushbuttons
        bsf     PortB,LED_1       ; Turn off LED_1
        bsf     PortB,LED_2       ; Turn off LED_2
        bsf     PortB,LED_3       ; Turn off LED_3
        clrf    LoopCounter1      ; Initialize test loop counter
        clrf    LoopCounter2      ; Initialize test loop counter
        clrf    LoopCounter3      ; Initialize test loop counter
        clrf    LoopCounter4      ; Initialize test loop counter
test_pb_loop1
        call    wait_5us
        btfss   PortA,pb_1        ; pb_1 pressed? 
        goto    Detect_pb_1_Release_Wait; Yes, go to wait
        btfss   PortA,pb_2        ; pb_2 pressed? 
        goto    Detect_pb_2_Release_Wait; Yes, go to wait
        btfss   PortA,pb_3        ; pb_3 pressed? 
        goto    Detect_pb_3_Release_Wait; Yes, go to wait
        incfsz  LoopCounter4,F    ; More loops needed for look time?
        goto    test_pb_loop1     ; Yes, keep looking. Loop back and try again
        incfsz  LoopCounter3,F    ; More loops needed for look time?
        goto    test_pb_loop1     ; Yes, keep looking. Loop back and try again
        incfsz  LoopCounter2,F    ; More loops needed for look time?
        goto    test_pb_loop1     ; Yes, keep looking. Loop back and try again
        goto    Test_Pushbuttons_Exit ; No, exit from this test
;
Detect_pb_1_Release_Wait ;                                                           
        call    wait_50us
        bcf     PortB,LED_1       ; Turn on LED_1
Detect_pb_1_Release_Wait_Loop
        btfss   PortA,pb_1        ; Is pb_3 still behing held?                 
        goto    Detect_pb_1_Release_Wait_Loop ; No, continue waiting for release (forever) 
        bsf     PortB,LED_1       ; Yes, turn off LED_1
        goto    Test_Pushbuttons  ;  and go back to start
;
Detect_pb_2_Release_Wait ;                                                           
        call    wait_50us
        bcf     PortB,LED_2       ; Turn on LED_2
Detect_pb_2_Release_Wait_Loop
        btfss   PortA,pb_2        ; Is pb_3 still behing held?                 
        goto    Detect_pb_2_Release_Wait_Loop ; No, continue waiting for release (forever) 
        bsf     PortB,LED_2       ; Yes, turn off LED_1
        goto    Test_Pushbuttons  ;  and go back to start
;
Detect_pb_3_Release_Wait ;                                                           
        call    wait_50us
        bcf     PortB,LED_3       ; Turn on LED_3
Detect_pb_3_Release_Wait_Loop
        btfss   PortA,pb_3        ; Is pb_3 still behing held?                 
        goto    Detect_pb_3_Release_Wait_Loop ; No, continue waiting for release (forever) 
        bsf     PortB,LED_3       ; Yes, Turn off LED_1
                                  ; and fall through to exit
;
Test_Pushbuttons_Exit

        return

; *****************************************************************************
; *                                                                           *
; * Purpose:  Test Speaker                                                    *
; *           Plays scale of tones on the speaker                             *
; *    C4 - 261.63 Hz    (3822 us / cycle)                                    *
; *    D4 - 293.66 Hz    (3405 us / cycle)                                    *
; *    E4 - 329.63 Hz    (3034 us / cycle)                                    *
; *    F4 - 349.23 Hz    (2863 us / cycle)                                    *
; *    G4 - 392 Hz       (2551 us / cycle)                                    *
; *    A4 - 440 Hz       (2273 us / cycle)                                    *
; *    B4 - 493.88 Hz    (2025 us / cycle)                                    *
; *    C5 - 523.25 Hz    (1911 us / cycle)                                    *
; *                                                                           *
; *****************************************************************************
Test_Speaker_Menu
        call    Write_Menu_Line1 
;
        movlw   0xc0              ; Point LCD at second line digit 1                
        call    cmnd2LCD          ;
        movlw   '3'               ; digit 1              
        call    data2LCD          ;
        movlw   ')'               ; digit 2                  
        call    data2LCD          ;
        movlw   ' '               ; digit 3                
        call    data2LCD          ;
        movlw   'S'               ; digit 4               
        call    data2LCD          ;
        movlw   'p'               ; digit 5               
        call    data2LCD          ;
        movlw   'e'               ; digit 6              
        call    data2LCD          ;
        movlw   'a'               ; digit 7              
        call    data2LCD          ;        
        movlw   'k'               ; digit 8              
        call    data2LCD          ;
        movlw   'e'               ; digit 9               
        call    data2LCD          ;
        movlw   'r'               ; digit 10              
        call    data2LCD          ;
        movlw   ' '               ; digit 11              
        call    data2LCD          ;
        movlw   ' '               ; digit 12              
        call    data2LCD          ;
        movlw   ' '               ; digit 13              
        call    data2LCD          ;
        movlw   ' '               ; digit 14              
        call    data2LCD          ;
        movlw   ' '               ; digit 15              
        call    data2LCD          ;
        movlw   ' '               ; digit 16              
        call    data2LCD          ;

        call    Detect_Pushbutton_3
        btfsc   STATUS,B_Z        ; Is detection flag set? (W=1,Z=0 if pushed)
        goto    Test_Speaker_Exit ; (Z=0) button not pushed so exit     
                                  ; (Z=1) button pushed so start test
; 
        movlw   0x80              ; Point LCD at first line digit 1                
        call    cmnd2LCD          ;
        movlw   'S'               ; digit 1              
        call    data2LCD          ;
        movlw   'p'               ; digit 2                  
        call    data2LCD          ;
        movlw   'e'               ; digit 3                
        call    data2LCD          ;
        movlw   'a'               ; digit 4               
        call    data2LCD          ;
        movlw   'k'               ; digit 5               
        call    data2LCD          ;
        movlw   'e'               ; digit 6              
        call    data2LCD          ;
        movlw   'r'               ; digit 7              
        call    data2LCD          ;        
        movlw   ' '               ; digit 8              
        call    data2LCD          ;
        movlw   'T'               ; digit 9               
        call    data2LCD          ;
        movlw   'e'               ; digit 10              
        call    data2LCD          ;
        movlw   's'               ; digit 11              
        call    data2LCD          ;
        movlw   't'               ; digit 12              
        call    data2LCD          ;
        movlw   ' '               ; digit 13              
        call    data2LCD          ;
        movlw   ' '               ; digit 14              
        call    data2LCD          ;
        movlw   ' '               ; digit 15              
        call    data2LCD          ;
        movlw   ' '               ; digit 16              
        call    data2LCD          ;
;
        call    Write_Press_Message_Line2
;
Test_Speaker
;
; Start Speaker test
; 
;C4 - 3822 us / cycle   
        movlw   0xFB              ; Turn RA2 into 
        banksel TRISA             ; Switch to bank 1
        movwf   TRISA             ;   an output (speaker)
        banksel PortA             ; Back to Bank 0
; .5 second / 3822 us = 131 times.  
        movlw   131               ; Initialize - 131 times through
        movwf   LoopCounter1      ;
Loop_C4_On ; 
        bsf     PortA,speaker
        ; On for 1911 us
        call    wait_1ms
        call    wait_500us
        call    wait_200us
        call    wait_200us
        call    wait_10us         ; Short by 1
;
        bcf     PortA,speaker
        ; Off for 1911 us
        call    wait_1ms
        call    wait_500us
        call    wait_200us
        call    wait_200us
        call    wait_10us         ; Short by 1 
        decfsz  LoopCounter1,f    ; Done?
        goto    Loop_C4_On        ; No, back 
                                  ; Yes, see if it time to quit
        movlw   0x04
        movwf   PortA             ; Make sure it's high before leaving
        movlw   0xFF              ; Turn RA2 into an input
        banksel TRISA             ; Switch to Bank 1
        movwf   TRISA             ; (for pushbutton_3 detect)
        banksel PortA             ; Back to Bank 0
        btfss   PortA,pb_3        ; Pushbutton pressed?  
        goto    Test_Speaker_Exit ; Yes, exit
; 
;D4 - 3405 us / cycle   

        movlw   0xFB              ; Turn RA2 into 
        banksel TRISA             ; Switch to bank 1
        movwf   TRISA             ;   an output (speaker)
        banksel PortA             ; Back to Bank 0
; .5 second / 3405 us = 147 times. 
        movlw   147               ; Initialize - 147 times through
        movwf   LoopCounter1      ;
Loop_D4_On ; 
        bsf     PortA,speaker
        ; On for 1703 us
        call    wait_1ms
        call    wait_500us
        call    wait_200us
        nop
        nop
        nop
;
        bcf     PortA,speaker
        ; Off for 1703 us
        call    wait_1ms
        call    wait_500us
        call    wait_200us
        nop
        nop
        nop
        decfsz  LoopCounter1,f    ; Done?
        goto    Loop_D4_On        ; No, back 
        movlw   0x04
        movwf   PortA             ; Make sure it's high before leaving
        movlw   0xFF              ; Turn RA2 into an input
        banksel TRISA             ; Switch to Bank 1
        movwf   TRISA             ; (for pushbutton detect)
        banksel PortA             ; Back to Bank 0
        btfss   PortA,pb_3        ; Pushbutton pressed?  
        goto    Test_Speaker_Exit ; Yes, exit
;
;E4 - 3034 us / cycle   
        movlw   0xFB              ; Turn RA2 into 
        banksel TRISA             ; Switch to bank 1
        movwf   TRISA             ;   an output (speaker)
        banksel PortA             ; Back to Bank 0
; .5 second / 3034 us = 165 times.  
        movlw   165               ; Initialize - 165 times through
        movwf   LoopCounter1      ;
Loop_E4_On ; 
        bsf     PortA,speaker
        ; On for 1517 us
        call    wait_1ms
        call    wait_500us
        call    wait_10us         
        call    wait_5us          
        nop
        nop
;
        bcf     PortA,speaker
        ; Off for 1517 us
        call    wait_1ms
        call    wait_500us
        call    wait_10us         
        call    wait_5us          
        nop
        nop
        decfsz  LoopCounter1,f    ; Done?
        goto    Loop_E4_On        ; No, back 
        movlw   0x04
        movwf   PortA             ; Make sure RA4 is high before leaving
        movlw   0xFF              ; Turn RA2 into an input
        banksel TRISA             ; Switch to Bank 1
        movwf   TRISA             ; (for pushbutton detect)
        banksel PortA             ; Back to Bank 0
        btfss   PortA,pb_3        ; Pushbutton pressed?
        goto    Test_Speaker_Exit ; Yes, exit
; 
;F4 - 2863 us / cycle   
        movlw   0xFB              ; Turn RA2 into 
        banksel TRISA             ; Switch to bank 1
        movwf   TRISA             ;   an output (speaker)
        banksel PortA             ; Back to Bank 0
; .5 second / 2863 us = 175 times.  
        movlw   175               ; Initialize - 175 times through
        movwf   LoopCounter1      ;
Loop_F4_On ; 
        bsf     PortA,speaker
        ; On for 1431 us
        call    wait_1ms
        call    wait_200us
        call    wait_200us
        call    wait_25us         
        call    wait_5us         
        nop
;
        bcf     PortA,speaker
        ; Off for 1432 us
        call    wait_1ms
        call    wait_200us
        call    wait_200us
        call    wait_25us         
        call    wait_5us         
        nop
        nop
        decfsz  LoopCounter1,f    ; Done?
        goto    Loop_F4_On        ; No, back 
        movlw   0x04
        movwf   PortA             ; Make sure RA4 is high before leaving
        movlw   0xFF              ; Turn RA2 into an input
        banksel TRISA             ; Switch to Bank 1
        movwf   TRISA             ; (for pushbutton detect)
        banksel PortA             ; Back to Bank 0
        btfss   PortA,pb_3        ; Pushbutton pressed?
        goto    Test_Speaker_Exit ; Yes, exit
; 
;G4 - 2551 us / cycle   
        movlw   0xFB              ; Turn RA2 into 
        banksel TRISA             ; Switch to bank 1
        movwf   TRISA             ;   an output (speaker)
        banksel PortA             ; Back to Bank 0
; .5 second / 2551 us = 196 times. 
        movlw   196               ; Initialize - 196 times through
        movwf   LoopCounter1      ;
Loop_G4_On ; 
        bsf     PortA,speaker
        ; On for 1275 us
        call    wait_1ms
        call    wait_200us
        call    wait_50us
        call    wait_25us
;
        bcf     PortA,speaker
        ; Off for 1276 us
        call    wait_1ms
        call    wait_200us
        call    wait_50us
        call    wait_25us
        nop
        decfsz  LoopCounter1,f    ; Done?
        goto    Loop_G4_On        ; No, back 
        movlw   0x04
        movwf   PortA             ; Make sure RA4 is high before leaving
        movlw   0xFF              ; Turn RA2 into 
        banksel TRISA             ; Switch to Bank 1
        movwf   TRISA             ;   an input (for pushbutton detect)
        banksel PortA             ; Back to Bank 0
        btfss   PortA,pb_3        ; Pushbutton pressed?
        goto    Test_Speaker_Exit ; Yes, exit
; 
;A4 - 2273 us / cycle   
        movlw   0xFB              ; Turn RA2 into 
        banksel TRISA             ; Switch to bank 1
        movwf   TRISA             ;   an output (speaker)
        banksel PortA             ; Back to Bank 0
; .5 second / 2273 us = 220 times. 
        movlw   220               ; Initialize - 220 times through
        movwf   LoopCounter1      ;
Loop_A4_On ; 
        bsf     PortA,speaker
        ; On for 1136 us
        call    wait_1ms
        call    wait_100us
        call    wait_25us
        call    wait_10us         
        nop
;
        bcf     PortA,speaker
        ; Off for 1137 us
        call    wait_1ms
        call    wait_100us
        call    wait_25us
        call    wait_10us         
        nop
        nop
        decfsz  LoopCounter1,f    ; Done?
        goto    Loop_A4_On        ; No, back 
        movlw   0x04
        movwf   PortA             ; Make sure RA4 is high before leaving
        movlw   0xFF              ; Turn RA2 into 
        banksel TRISA             ; Switch to Bank 1
        movwf   TRISA             ;   an input (for pushbutton detect)
        banksel PortA             ; Back to Bank 0
        btfss   PortA,pb_3        ; Pushbutton pressed?
        goto    Test_Speaker_Exit ; Yes, exit
; 
;B4 - 2025 us / cycle   
        movlw   0xFB              ; Turn RA2 into 
        banksel TRISA             ; Switch to bank 1
        movwf   TRISA             ;   an output (speaker)
        banksel PortA             ; Back to Bank 0
; .5 second / 2025 us = 247 times.  
        movlw   247               ; Initialize - 247 times through
        movwf   LoopCounter1      ;
Loop_B4_On ; 
        bsf     PortA,speaker
        ; On for 1012 us
        call    wait_1ms
        call    wait_10us         
        nop
        nop
;
        bcf     PortA,speaker
        ; Off for 1013 us
        call    wait_1ms
        call    wait_10us         
        nop
        nop
        nop
        decfsz  LoopCounter1,f    ; Done?
        goto    Loop_B4_On        ; No, back 
        movlw   0x04
        movwf   PortA             ; Make sure RA4 is high before leaving
        movlw   0xFF              ; Turn RA2 into 
        banksel TRISA             ; Switch to Bank 1
        movwf   TRISA             ;   an input (for pushbutton detect)
        banksel PortA             ; Back to Bank 0
        btfss   PortA,pb_3        ; Pushbutton pressed?
        goto    Test_Speaker_Exit ; Yes, exit
; 
;C5 - 1911 us / cycle   
        movlw   0xFB              ; Turn RA2 into 
        banksel TRISA             ; Switch to bank 1
        movwf   TRISA             ;   an output (speaker)
        banksel PortA             ; Back to Bank 0
; .5 second / 1911 us =  262 times.   (Use 256)
        clrf    LoopCounter1      ; Initialize - 256 times through
Loop_C5_On ; 
        bsf     PortA,speaker
        ; On for 955 us
        call    wait_500us
        call    wait_200us
        call    wait_200us
        call    wait_50us        
        call    wait_5us        
;
        bcf     PortA,speaker
        ; Off for 956 us
        call    wait_500us
        call    wait_200us
        call    wait_200us
        call    wait_50us        
        call    wait_5us        
        nop
        decfsz  LoopCounter1,f    ; Done?
        goto    Loop_C5_On        ; No, back 
        movlw   0x04
        movwf   PortA             ; Make sure RA4 is high before leaving
        movlw   0xFF              ; Turn RA2 into 
        banksel TRISA             ; Switch to Bank 1
        movwf   TRISA             ;   an input (for pushbutton detect)
        banksel PortA             ; Back to Bank 0
        btfsc   PortA,pb_3        ; Pushbutton pressed?
        goto    Test_Speaker      ; No, back to start of speaker test
                                  ; Yes, fall through to exit
;
Test_Speaker_Exit
        return
;
; *****************************************************************************
; *                                                                           *
; * Purpose:  Test Encoder                                                    *
; *           Displays number on screen. Incremented/Decremented via encoder. *
; *                                                                           *
; *****************************************************************************
Test_Encoder_Menu
        call    Write_Menu_Line1 
;
        movlw   0xc0              ; Point LCD at second line digit 1                
        call    cmnd2LCD          ;
        movlw   '4'               ; digit 1              
        call    data2LCD          ;
        movlw   ')'               ; digit 2                  
        call    data2LCD          ;
        movlw   ' '               ; digit 3                
        call    data2LCD          ;
        movlw   'E'               ; digit 4               
        call    data2LCD          ;
        movlw   'n'               ; digit 5               
        call    data2LCD          ;
        movlw   'c'               ; digit 6              
        call    data2LCD          ;
        movlw   'o'               ; digit 7              
        call    data2LCD          ;        
        movlw   'd'               ; digit 8              
        call    data2LCD          ;
        movlw   'e'               ; digit 9               
        call    data2LCD          ;
        movlw   'r'               ; digit 10              
        call    data2LCD          ;
        movlw   ' '               ; digit 11              
        call    data2LCD          ;
        movlw   ' '               ; digit 12              
        call    data2LCD          ;
        movlw   ' '               ; digit 13              
        call    data2LCD          ;
        movlw   ' '               ; digit 14              
        call    data2LCD          ;
        movlw   ' '               ; digit 15              
        call    data2LCD          ;
        movlw   ' '               ; digit 16              
        call    data2LCD          ;
;
        call    Detect_Pushbutton_3
        btfsc   STATUS,B_Z        ; Is detection flag set? (W=1,Z=0 if pushed)
        goto    Test_Speaker_Exit ; (Z=0) button not pushed so exit     
                                  ; (Z=1) button pushed so start test

        movlw   0x80              ; Point LCD at first line digit 1                
        call    cmnd2LCD          ;
        movlw   'E'               ; digit 1              
        call    data2LCD          ;
        movlw   'n'               ; digit 2                  
        call    data2LCD          ;
        movlw   'c'               ; digit 3                
        call    data2LCD          ;
        movlw   'o'               ; digit 4               
        call    data2LCD          ;
        movlw   'd'               ; digit 5               
        call    data2LCD          ;
        movlw   'e'               ; digit 6              
        call    data2LCD          ;
        movlw   'r'               ; digit 7              
        call    data2LCD          ;        
        movlw   ' '               ; digit 8              
        call    data2LCD          ;
        movlw   'T'               ; digit 9               
        call    data2LCD          ;
        movlw   'e'               ; digit 10              
        call    data2LCD          ;
        movlw   's'               ; digit 11              
        call    data2LCD          ;
        movlw   't'               ; digit 12              
        call    data2LCD          ;
        movlw   ' '               ; digit 13              
        call    data2LCD          ;
        movlw   ' '               ; digit 14              
        call    data2LCD          ;
        movlw   ' '               ; digit 15              
        call    data2LCD          ;
        movlw   ' '               ; digit 16              
        call    data2LCD          ;
;
        clrf    freq_0            ; Initialize starting frequency
        clrf    freq_1            ; Initialize starting frequency
        clrf    freq_2            ; Initialize starting frequency
        clrf    freq_3            ; Initialize starting frequency
        call    bin2BCD           ; Convert the frequency to BCD
        call    show_freq         ; Display the frequency on the LCD

Test_Encoder
        call    poll_encoder      ; Check for knob movement (wait there!)      
                                  ; Return here when encoder change detected   
        btfsc   STATUS,B_Z        ; Is it time to exit test (End if W=0, Z=1)
        goto    Encoder_Test_Exit ; Yes, Exit test
                                  ; No, continue
        clrf    fstep_3           ; Guess that we want 1 Hz steps by 
        clrf    fstep_2           ;   setting fstep to one.
        clrf    fstep_1           ; 
        movlw   0x01              ;
        movwf   fstep_0           ; 
;
;       Based on the knob direction, either add or subtract the increment, 
;       then update the LCD and DDS.
; 
        btfsc   last_dir,1        ; Is the knob going up?
        goto    up                ; Yes, then add the increment
down
        call    sub_step          ; Subtract fstep from freq
        goto    update            ;   and go to update
up
        call    add_step          ; Add fstep to freq
                                  ; Fall through to update
update 
        call    bin2BCD           ; Convert the frequency to BCD
        call    show_freq         ; Display the frequency on the LCD
        goto    Test_Encoder      ; Loop back
;
Encoder_Test_Exit
        return                    ; Exit
;
; *****************************************************************************
; * Purpose:  Test_Paddles                                                    *
; *                                                                           *
; *****************************************************************************
Test_Paddles_Menu
        call    Write_Menu_Line1 
;
        movlw   0xc0              ; Point LCD at second line digit 1                
        call    cmnd2LCD          ;
        movlw   '5'               ; digit 1              
        call    data2LCD          ;
        movlw   ')'               ; digit 2                  
        call    data2LCD          ;
        movlw   ' '               ; digit 3                
        call    data2LCD          ;
        movlw   'P'               ; digit 4               
        call    data2LCD          ;
        movlw   'a'               ; digit 5               
        call    data2LCD          ;
        movlw   'd'               ; digit 6              
        call    data2LCD          ;
        movlw   'd'               ; digit 7              
        call    data2LCD          ;        
        movlw   'l'               ; digit 8              
        call    data2LCD          ;
        movlw   'e'               ; digit 9               
        call    data2LCD          ;
        movlw   's'               ; digit 10              
        call    data2LCD          ;
        movlw   ' '               ; digit 11              
        call    data2LCD          ;
        movlw   ' '               ; digit 12              
        call    data2LCD          ;
        movlw   ' '               ; digit 13              
        call    data2LCD          ;
        movlw   ' '               ; digit 14              
        call    data2LCD          ;
        movlw   ' '               ; digit 15              
        call    data2LCD          ;
        movlw   ' '               ; digit 16              
        call    data2LCD          ;
; 
        call    Detect_Pushbutton_3
        btfsc   STATUS,B_Z        ; Is detection flag set? (W=1,Z=0 if pushed)
        goto    Test_Pushbuttons_Exit ; (Z=0) button not pushed so exit     
                                  ; (Z=1) button pushed so start test

        movlw   0x80              ; Point LCD at first line digit 1                
        call    cmnd2LCD          ;
        movlw   'P'               ; digit 1              
        call    data2LCD          ;
        movlw   'a'               ; digit 2                  
        call    data2LCD          ;
        movlw   'd'               ; digit 3                
        call    data2LCD          ;
        movlw   'd'               ; digit 4               
        call    data2LCD          ;
        movlw   'l'               ; digit 5               
        call    data2LCD          ;
        movlw   'e'               ; digit 6              
        call    data2LCD          ;
        movlw   's'               ; digit 7              
        call    data2LCD          ;        
        movlw   ' '               ; digit 8              
        call    data2LCD          ;
        movlw   'T'               ; digit 9               
        call    data2LCD          ;
        movlw   'e'               ; digit 10              
        call    data2LCD          ;
        movlw   's'               ; digit 11              
        call    data2LCD          ;
        movlw   't'               ; digit 12              
        call    data2LCD          ;
        movlw   ' '               ; digit 13              
        call    data2LCD          ;
        movlw   ' '               ; digit 14              
        call    data2LCD          ;
        movlw   ' '               ; digit 15              
        call    data2LCD          ;
        movlw   ' '               ; digit 16              
        call    data2LCD          ;
;
        call    Write_Press_Message_Line2
;
; Start Paddles test
; 
Test_Paddles
        bsf     PortB,LED_1       ; Turn off LED_1
        bsf     PortB,LED_2       ; Turn off LED_2
        bsf     PortB,LED_3       ; Turn off LED_3
        clrf    LoopCounter1      ; Initialize test loop counter
        clrf    LoopCounter2      ; Initialize test loop counter
        clrf    LoopCounter3      ; Initialize test loop counter
        clrf    LoopCounter4      ; Initialize test loop counter
test_pad_loop1
        call    wait_5us
        btfss   PortA,pb_1        ; pb_1 pressed? (Same as Dit)
        goto    Detect_pad_1_Release_Wait; Yes, go to wait
        btfss   PortA,pb_2        ; pb_2 pressed?  (Same as Dah)
        goto    Detect_pad_2_Release_Wait; Yes, go to wait
        btfss   PortA,pb_3        ; pb_3 pressed? (Exit)
        goto    Detect_pad_3_Release_Wait; Yes, go to wait
        incfsz  LoopCounter4,F    ; More loops needed for look time?
        goto    test_pad_loop1    ; Yes, keep looking. Loop back and try again
        incfsz  LoopCounter3,F    ; More loops needed for look time?
        goto    test_pad_loop1    ; Yes, keep looking. Loop back and try again
        incfsz  LoopCounter2,F    ; More loops needed for look time?
        goto    test_pad_loop1    ; Yes, keep looking. Loop back and try again
        goto    Test_Paddles_Exit ; No, exit from this test
;
Detect_pad_1_Release_Wait ;                                                           
        call    wait_50us
        bcf     PortB,LED_1       ; Turn on LED_1
Detect_pad_1_Release_Wait_Loop
        btfss   PortA,pb_1        ; Is pb_3 still behing held?                 
        goto    Detect_pad_1_Release_Wait_Loop ; No, continue waiting for release (forever) 
        bsf     PortB,LED_1       ; Yes, turn off LED_1
        goto    Test_Paddles      ;  and go back to start
;
Detect_pad_2_Release_Wait ;                                                           
        call    wait_50us
        bcf     PortB,LED_2       ; Turn on LED_2
Detect_pad_2_Release_Wait_Loop
        btfss   PortA,pb_2        ; Is pb_3 still behing held?                 
        goto    Detect_pad_2_Release_Wait_Loop ; No, continue waiting for release (forever) 
        bsf     PortB,LED_2       ; Yes, turn off LED_1
        goto    Test_Paddles      ;  and go back to start
;
Detect_pad_3_Release_Wait ;                                                           
        call    wait_50us
        bcf     PortB,LED_3       ; Turn on LED_3
Detect_pad_3_Release_Wait_Loop
        btfss   PortA,pb_3        ; Is pb_3 still behing held?                 
        goto    Detect_pad_3_Release_Wait_Loop ; No, continue waiting for release (forever) 
        bsf     PortB,LED_3       ; Yes, Turn off LED_1
                                  ; and fall through to exit
;
Test_Paddles_Exit

        return
; *****************************************************************************
; * Purpose:  Test_Transmitter_Keying                                         *
; *                                                                           *
; *****************************************************************************
Test_Transmitter_Menu
        call    Write_Menu_Line1 
;
        movlw   0xc0              ; Point LCD at second line digit 1                
        call    cmnd2LCD          ;
        movlw   '6'               ; digit 1              
        call    data2LCD          ;
        movlw   ')'               ; digit 2                  
        call    data2LCD          ;
        movlw   ' '               ; digit 3                
        call    data2LCD          ;
        movlw   'X'               ; digit 4               
        call    data2LCD          ;
        movlw   'M'               ; digit 5               
        call    data2LCD          ;
        movlw   'I'               ; digit 6              
        call    data2LCD          ;
        movlw   'T'               ; digit 7              
        call    data2LCD          ;        
        movlw   ' '               ; digit 8              
        call    data2LCD          ;
        movlw   'K'               ; digit 9               
        call    data2LCD          ;
        movlw   'e'               ; digit 10              
        call    data2LCD          ;
        movlw   'y'               ; digit 11              
        call    data2LCD          ;
        movlw   'i'               ; digit 12              
        call    data2LCD          ;
        movlw   'n'               ; digit 13              
        call    data2LCD          ;
        movlw   'g'               ; digit 14              
        call    data2LCD          ;
        movlw   ' '               ; digit 15              
        call    data2LCD          ;
        movlw   ' '               ; digit 16              
        call    data2LCD          ;
; 
        call    Detect_Pushbutton_3
        btfsc   STATUS,B_Z        ; Is detection flag set? (W=1,Z=0 if pushed)
        goto    Test_Transmitter_Exit ; (Z=0) button not pushed so exit     
                                  ; (Z=1) button pushed so start test

        movlw   0x80              ; Point LCD at first line digit 1                
        call    cmnd2LCD          ;
        movlw   'X'               ; digit 1              
        call    data2LCD          ;
        movlw   'M'               ; digit 2                  
        call    data2LCD          ;
        movlw   'I'               ; digit 3                
        call    data2LCD          ;
        movlw   'T'               ; digit 4               
        call    data2LCD          ;
        movlw   ' '               ; digit 5               
        call    data2LCD          ;
        movlw   'K'               ; digit 6              
        call    data2LCD          ;
        movlw   'e'               ; digit 7              
        call    data2LCD          ;        
        movlw   'y'               ; digit 8              
        call    data2LCD          ;
        movlw   'i'               ; digit 9               
        call    data2LCD          ;
        movlw   'n'               ; digit 10              
        call    data2LCD          ;
        movlw   'g'               ; digit 11              
        call    data2LCD          ;
        movlw   ' '               ; digit 12              
        call    data2LCD          ;
        movlw   'T'               ; digit 13              
        call    data2LCD          ;
        movlw   'e'               ; digit 14              
        call    data2LCD          ;
        movlw   's'               ; digit 15              
        call    data2LCD          ;
        movlw   't'               ; digit 16              
        call    data2LCD          ;
;
        call    Write_Press_Message_Line2
;
; Start Transmiter Keying test
; 
Test_Transmitter
        bsf     PortB,XMIT        ; Turn on XMIT Keying
        bcf     PortB,LED_1       ; Turn on LED_1 (Visual indicator of XMIT)
        call    Detect_Pushbutton_3 ; Look for PB3 to see if it's time to end
        btfss   STATUS,B_Z        ; Is detection flag set? (W=1,Z=0 if pushed)
        goto    Test_Transmitter_Exit ; (Z=1) button pushed so exit
                                  ; (Z=0) button not pushed so keep going
        bcf     PortB,XMIT        ; Turn off XMIT keying
        bsf     PortB,LED_1       ; Turn off LED_1 (Visual indicator of XMIT)
        call    Detect_Pushbutton_3 ; Look for PB3 to see if it's time to end
        btfsc   STATUS,B_Z        ; Is detection flag set? (W=1,Z=0 if pushed)
        goto    Test_Transmitter  ; (Z=1) button not pushed so keep going on test
                                  ; (Z=0) button pushed so fall through to exit     
Test_Transmitter_Exit
        return 
;
; *****************************************************************************
; *                                                                           *
; * Purpose:  Test_DDS_30                                                     *
; *           Test AmQRP DDS_30 DDS Daughtercard                              *
; *                                                                           *
; *****************************************************************************
Test_DDS_30_Menu
        call    Write_Menu_Line1 
;
        movlw   0xc0              ; Point LCD at second line digit 1                
        call    cmnd2LCD          ;
        movlw   '7'               ; digit 1              
        call    data2LCD          ;
        movlw   ')'               ; digit 2                  
        call    data2LCD          ;
        movlw   ' '               ; digit 3                
        call    data2LCD          ;
        movlw   'D'               ; digit 4               
        call    data2LCD          ;
        movlw   'D'               ; digit 5               
        call    data2LCD          ;
        movlw   'S'               ; digit 6              
        call    data2LCD          ;
        movlw   '_'               ; digit 7              
        call    data2LCD          ;        
        movlw   '3'               ; digit 8              
        call    data2LCD          ;
        movlw   '0'               ; digit 9               
        call    data2LCD          ;
        movlw   ' '               ; digit 10              
        call    data2LCD          ;
        movlw   ' '               ; digit 11              
        call    data2LCD          ;
        movlw   ' '               ; digit 12              
        call    data2LCD          ;
        movlw   ' '               ; digit 13              
        call    data2LCD          ;
        movlw   ' '               ; digit 14              
        call    data2LCD          ;
        movlw   ' '               ; digit 15              
        call    data2LCD          ;
        movlw   ' '               ; digit 16              
        call    data2LCD          ;
;
        call    Detect_Pushbutton_3
        btfsc   STATUS,B_Z        ; Is detection flag set? (W=1,Z=0 if pushed)
        goto    Test_DDS_30_Exit  ; (Z=0) button not pushed so exit     
                                  ; (Z=1) button pushed so start test

        movlw   0x80              ; Point LCD at first line digit 1                
        call    cmnd2LCD          ;
        movlw   'D'               ; digit 1              
        call    data2LCD          ;
        movlw   'D'               ; digit 2                  
        call    data2LCD          ;
        movlw   'S'               ; digit 3                
        call    data2LCD          ;
        movlw   '_'               ; digit 4               
        call    data2LCD          ;
        movlw   '3'               ; digit 5               
        call    data2LCD          ;
        movlw   '0'               ; digit 6              
        call    data2LCD          ;
        movlw   ' '               ; digit 7              
        call    data2LCD          ;        
        movlw   'T'               ; digit 8              
        call    data2LCD          ;
        movlw   'e'               ; digit 9               
        call    data2LCD          ;
        movlw   's'               ; digit 10              
        call    data2LCD          ;
        movlw   't'               ; digit 11              
        call    data2LCD          ;
        movlw   ' '               ; digit 12              
        call    data2LCD          ;
        movlw   ' '               ; digit 13              
        call    data2LCD          ;
        movlw   ' '               ; digit 14              
        call    data2LCD          ;
        movlw   ' '               ; digit 15              
        call    data2LCD          ;
        movlw   ' '               ; digit 16              
        call    data2LCD          ;
;
; Set up DDS oscillator bytes for 100 MHz oscillator and frequency = 7040 kHz
        movlw   OSC_100MHZ_3      ;
        movwf   osc_3             ;
        movlw   OSC_100MHZ_2      ;
        movwf   osc_2             ;
        movlw   OSC_100MHZ_1      ;
        movwf   osc_1             ;
        movlw   OSC_100MHZ_0      ;
        movwf   osc_0             ;
;
        bcf     DDS_flag,0        ; Clear flag - it's an AD9850 so NO multiplier   
; 
DDS_30_Loop
; Set up frequency in freq words for 7,040.000 kHz
        movlw   0x00
        movwf   freq_3
        movlw   0x6B
        movwf   freq_2
        movlw   0x6C
        movwf   freq_1
        movlw   0x00
        movwf   freq_0
; Display frequency on LCD - Line 1
        call    bin2BCD           ; Convert the frequency to BCD               
        call    show_freq         ; Display the frequency on the LCD           
; Calculate DDS words by multiplying freq bytes by osc bytes.
        call    calc_dds_word     ; Calculate words for DDS
; Send DDS bytes to DDS
        call    send_dds_word     ; Send words to DDS
        call    wait_256ms        ; Wait for 256 ms
;
; Set up frequency in freq words for 7,041.000 kHz
        movlw   0x00
        movwf   freq_3
        movlw   0x6B
        movwf   freq_2
        movlw   0x6F
        movwf   freq_1
        movlw   0xE8
        movwf   freq_0
; Display frequency on LCD - Line 1
        call    bin2BCD           ; Convert the frequency to BCD               
        call    show_freq         ; Display the frequency on the LCD           
; Calculate DDS words by multiplying freq bytes by osc bytes.
        call    calc_dds_word     ; Calculate words for DDS
; Send DDS bytes to DDS
        call    send_dds_word     ; Send words to DDS
        call    wait_256ms        ; Wait for 256 ms
;
; Set up frequency in freq words for 7,042.000 kHz
        movlw   0x00
        movwf   freq_3
        movlw   0x6B
        movwf   freq_2
        movlw   0x73
        movwf   freq_1
        movlw   0xD0
        movwf   freq_0
; Display frequency on LCD - Line 1
        call    bin2BCD           ; Convert the frequency to BCD               
        call    show_freq         ; Display the frequency on the LCD           
; Calculate DDS words by multiplying freq bytes by osc bytes.
        call    calc_dds_word     ; Calculate words for DDS
; Send DDS bytes to DDS
        call    send_dds_word     ; Send words to DDS
;
        call    Detect_Pushbutton_3
        btfsc   STATUS,B_Z        ; Is detection flag set? (W=1,Z=0 if pushed)
        goto    DDS_30_Loop       ; (Z=0) Loop back to start of DDS_60 test
                                  ; (Z=1) Fall through to exit
Test_DDS_30_Exit
        return 
;

; *****************************************************************************
; *                                                                           *
; * Purpose:  Test_DDS_60                                                     *
; *           Test AmQRP DDS_60 DDS Daughtercard                              *
; *                                                                           *
; *****************************************************************************
Test_DDS_60_Menu
        call    Write_Menu_Line1 
;
        movlw   0xc0              ; Point LCD at second line digit 1                
        call    cmnd2LCD          ;
        movlw   '8'               ; digit 1              
        call    data2LCD          ;
        movlw   ')'               ; digit 2                  
        call    data2LCD          ;
        movlw   ' '               ; digit 3                
        call    data2LCD          ;
        movlw   'D'               ; digit 4               
        call    data2LCD          ;
        movlw   'D'               ; digit 5               
        call    data2LCD          ;
        movlw   'S'               ; digit 6              
        call    data2LCD          ;
        movlw   '_'               ; digit 7              
        call    data2LCD          ;        
        movlw   '6'               ; digit 8              
        call    data2LCD          ;
        movlw   '0'               ; digit 9               
        call    data2LCD          ;
        movlw   ' '               ; digit 10              
        call    data2LCD          ;
        movlw   ' '               ; digit 11              
        call    data2LCD          ;
        movlw   ' '               ; digit 12              
        call    data2LCD          ;
        movlw   ' '               ; digit 13              
        call    data2LCD          ;
        movlw   ' '               ; digit 14              
        call    data2LCD          ;
        movlw   ' '               ; digit 15              
        call    data2LCD          ;
        movlw   ' '               ; digit 16              
        call    data2LCD          ;
;
        call    Detect_Pushbutton_3
        btfsc   STATUS,B_Z        ; Is detection flag set? (W=1,Z=0 if pushed)
        goto    Test_DDS_60_Exit  ; (Z=0) button not pushed so exit     
                                  ; (Z=1) button pushed so start test

        movlw   0x80              ; Point LCD at first line digit 1                
        call    cmnd2LCD          ;
        movlw   'D'               ; digit 1              
        call    data2LCD          ;
        movlw   'D'               ; digit 2                  
        call    data2LCD          ;
        movlw   'S'               ; digit 3                
        call    data2LCD          ;
        movlw   '_'               ; digit 4               
        call    data2LCD          ;
        movlw   '6'               ; digit 5               
        call    data2LCD          ;
        movlw   '0'               ; digit 6              
        call    data2LCD          ;
        movlw   ' '               ; digit 7              
        call    data2LCD          ;        
        movlw   'T'               ; digit 8              
        call    data2LCD          ;
        movlw   'e'               ; digit 9               
        call    data2LCD          ;
        movlw   's'               ; digit 10              
        call    data2LCD          ;
        movlw   't'               ; digit 11              
        call    data2LCD          ;
        movlw   ' '               ; digit 12              
        call    data2LCD          ;
        movlw   ' '               ; digit 13              
        call    data2LCD          ;
        movlw   ' '               ; digit 14              
        call    data2LCD          ;
        movlw   ' '               ; digit 15              
        call    data2LCD          ;
        movlw   ' '               ; digit 16              
        call    data2LCD          ;
;
; Set up DDS oscillator bytes for 180MHz oscillator and frequency = 7040 kHz
        movlw   OSC_180MHZ_3      ;
        movwf   osc_3             ;
        movlw   OSC_180MHZ_2      ;
        movwf   osc_2             ;
        movlw   OSC_180MHZ_1      ;
        movwf   osc_1             ;
        movlw   OSC_180MHZ_0      ;
        movwf   osc_0             ;
;
        bsf     DDS_flag,0        ; Set flag - it's an AD9851 so USE multiplier   
; 
DDS_60_Loop
; Set up frequency in freq words for 7,040.000 kHz
        movlw   0x00
        movwf   freq_3
        movlw   0x6b
        movwf   freq_2
        movlw   0x6C
        movwf   freq_1
        movlw   0x00
        movwf   freq_0
; Display frequency on LCD - Line 1
        call    bin2BCD           ; Convert the frequency to BCD               
        call    show_freq         ; Display the frequency on the LCD           
; Calculate DDS words by multiplying freq bytes by osc bytes.
        call    calc_dds_word     ; Calculate words for DDS
; Send DDS bytes to DDS
        call    send_dds_word     ; Send words to DDS
        call    wait_256ms        ; Wait for 256 ms
;
; Set up frequency in freq words for 7,041.000 kHz
        movlw   0x00
        movwf   freq_3
        movlw   0x6B
        movwf   freq_2
        movlw   0x6F
        movwf   freq_1
        movlw   0xE8
        movwf   freq_0
; Display frequency on LCD - Line 1
        call    bin2BCD           ; Convert the frequency to BCD               
        call    show_freq         ; Display the frequency on the LCD           
; Calculate DDS words by multiplying freq bytes by osc bytes.
        call    calc_dds_word     ; Calculate words for DDS
; Send DDS bytes to DDS
        call    send_dds_word     ; Send words to DDS
        call    wait_256ms        ; Wait for 256 ms
;
; Set up frequency in freq words for 7,042.000 kHz
        movlw   0x00
        movwf   freq_3
        movlw   0x6B
        movwf   freq_2
        movlw   0x73
        movwf   freq_1
        movlw   0xD0
        movwf   freq_0
; Display frequency on LCD - Line 1
        call    bin2BCD           ; Convert the frequency to BCD               
        call    show_freq         ; Display the frequency on the LCD           
; Calculate DDS words by multiplying freq bytes by osc bytes.
        call    calc_dds_word     ; Calculate words for DDS
; Send DDS bytes to DDS
        call    send_dds_word     ; Send words to DDS
;
        call    Detect_Pushbutton_3
        btfsc   STATUS,B_Z        ; Is detection flag set? (W=1,Z=0 if pushed)
        goto    DDS_60_Loop       ; (Z=0) Loop back to start of DDS_60 test
                                  ; (Z=1) Fall through to exit
Test_DDS_60_Exit
        return 
;
; *****************************************************************************
; *                                                                           *
; * Purpose:  This routine adds the 32 bit value of fstep to the 32 bit       *
; *           value in freq.  When incrementing, the fstep value is a         *
; *           positive integer.  When decrementing, fstep is the complement   *
; *           of the value being subtracted.                                  *
; *                                                                           *
; *   Input:  The 32 bit values in fstep and freq                             *
; *                                                                           *
; *  Output:  The sum of fstep and freq is stored in freq.  When incrementing *
; *           this value may exceed the maximum.  When decrementing, it may   *
; *           go negative.                                                    *
; *                                                                           *
; *****************************************************************************
add_step
        movf    fstep_0,w         ; Get low byte of the increment
        addwf   freq_0,f          ; Add it to the low byte of freq
        btfss   STATUS,B_C        ; Any carry?
        goto    add1              ; No, add next byte
        incfsz  freq_1,f          ; Ripple carry up to the next byte
        goto    add1              ; No new carry, add next byte
        incfsz  freq_2,f          ; Ripple carry up to the next byte
        goto    add1              ; No new carry, add next byte
        incf    freq_3,f          ; Ripple carry up to the highest byte
add1
        movf    fstep_1,w         ; Get the next increment byte
        addwf   freq_1,f          ; Add it to the next higher byte
        btfss   STATUS,B_C        ; Any carry?
        goto    add2              ; No, add next byte
        incfsz  freq_2,f          ; Ripple carry up to the next byte
        goto    add2              ; No new carry, add next byte
        incf    freq_3,f          ; Ripple carry up to the highest byte
add2
        movf    fstep_2,w         ; Get the next to most significant increment
        addwf   freq_2,f          ; Add it to the freq byte
        btfss   STATUS,B_C        ; Any carry?
        goto    add3              ; No, add last byte
        incf    freq_3,f          ; Ripple carry up to the highest byte
add3
        movf    fstep_3,w         ; Get the most significant increment byte
        addwf   freq_3,f          ; Add it to the most significant freq
        return                    ; Return to the caller
;
; *****************************************************************************
; *                                                                           *
; * Purpose:  Subtract the increment step from freq, checking that it does    *
; *           not go below zero.                                              *
; *                                                                           *
; *   Input:  The values in fstep and freq.                                   *
; *                                                                           *
; *  Output:  The updated value in freq.                                      *
; *                                                                           *
; *****************************************************************************
;
sub_step
        comf    fstep_0,f         ; Subtraction of fstep from
        comf    fstep_1,f         ;   freq is done by adding the
        comf    fstep_2,f         ;   twos compliment of fstep to
        comf    fstep_3,f         ;   freq.
        incfsz  fstep_0,f         ; Increment last byte
        goto    comp_done         ; Non-zero, continue
        incfsz  fstep_1,f         ; Increment next byte
        goto    comp_done         ; Non-zero, continue
        incfsz  fstep_2,f         ; Increment next byte
        goto    comp_done         ; Non-zero, continue
        incf    fstep_3,f         ; Increment the high byte
comp_done
        call    add_step          ; Add the compliment to do the subtraction
;
;       If the frequency has gone negative, clear it to zero.
;
        btfss   freq_3,7          ; Is high order frequency byte "negative"?   
        goto    exit2             ; No, keep going
set_min
        clrf    freq_0            ; Yes, set the frequency to zero
        clrf    freq_1            ; 
        clrf    freq_2            ; 
        clrf    freq_3            ; 
exit2
        return                    ; Return to the caller
;
; *****************************************************************************
; *                                                                           *
; * Purpose:  This routine does the following:                                *
; *             1.  Records how long it took for the knob to move a notch     *
; *                 in ren_timer.                                             *
; *             2.  Clears the watchdog timer.                                *
; *             3.  Reads the encoder bits until a change is detected, then   *
; *                 determines the direction the knob was moved.              *
; *                                                                           *
; *   Input:  Knob input read from port A                                     *
; *           ren_old -> the last encoder bits read                           *
; *           last_dir -> the last direction moved                            *
; *                                                                           *
; *  Output:  ren_timer -> an indication the speed of the knob.               *
; *           ren_new -> the current encoder bits                             *
; *           last_dir -> the last direction (0 = down, 2 = up)               *
; *                                                                           *
; *****************************************************************************
;
poll_encoder
        clrf    ren_timer_1       ; Put starting values in ren_timer cells     
        movlw   0x40              ; Start with the high bit set                
        movwf   ren_timer_0       ;   in ren_timer_0                           
read_encoder
        ; See if it's time to end test
        btfsc   PortA,pb_3        ; Is pb_3 pressed?
        goto    ok_to_poll        ; No, OK to poll 
encoder_release_wait
        call    wait_200us        ; Avoid noise and contact bounce
encoder_release_wait_loop;                                                           
        btfss   PortA,pb_3        ; Is pushbutton released?
        goto    encoder_release_wait_loop ; No, wait (forever)
        goto    poll_exit_and_end ; Yes, exit test
ok_to_poll
        ; Keep polling   
        btfsc   ren_timer_1,7     ; Has the bit floated to top of ren_timer_1? 
        goto    no_inc            ; Yes, don't move it any further
        movlw   0x08              ; No, keep going                             
        addwf   ren_timer_0,f     ; Add constant to ren_timer_0                
        btfsc   STATUS,B_C        ; Did the add force a carry?
        incf    ren_timer_1,f     ; Yes, then add one to ren_timer_1
no_inc                            ; 
        movf    PortA,w           ; Get the current encoder value
        movwf   ren_read          ; Save it
        movlw   0x03              ; Get encoder mask (to isolate RA0 and RA1)  
        andwf   ren_read,w        ; Isolated encoder bits into W               
        movwf   ren_new           ; Save new value
        xorwf   ren_old,w         ; Has it changed?
        btfsc   STATUS,B_Z        ; Check zero-flag (zero if no change)        
        goto    read_encoder      ; No change, keep looking until it changes   
;                                 ; Zero-flag is not set, so continue on        
; It changed. Now determine which direction the encoder turned.                
;============================================================================= 
;   Encoder bits are on RA0 and RA1 - the two low order bits of ren_new          
;   A and B are "gray code" - 90 degrees out of phase (quadrature)             
;         ___     ___                                                          
;        |   |   |   |                                                         
; A  ____|   |___|   |___                                                      
;           ___     ___                                                        
;          |   |   |   |                                                       
; B     ___|   |___|   |___                                                    
;       ^ ^ ^ ^ ^ ^ ^ ^                                                        
;       a b c d a b c d                                                        
;                                                                              
;              A B                                                             
; At point a:  0 0                                                             
; At point b:  1 0                                                             
; At point c:  1 1                                                             
; At point d:  0 1                                                             
;                                                                              
; Going UP, the sequence is a,b,c,d,a,b,c,d, etc. so the sequence is:          
;     00, 10, 11, 01, 00, 10, 11, 01, etc.                                     
;                                                                              
; Going DOWN, the sequence is d,c,b,a,d,c,b,a, etc. so the sequence is:        
;     01, 11, 10, 00, 01, 11, 10, 00, etc.                                     
;                                                                              
; To determine if the sequence is UP or DOWN:                                  
;   1) Take the "Right-Bit" of any pair.                                       
;   2) XOR it with the "Left-Bit" of the next pair in the sequence.            
;   3) If the result is 1 it is UP                                             
;      If the result is 0 it is DOWN                                           
;                                                                              
; The direction flag is 0 (DOWN) or 2 (UP) because of bit positioning          
;============================================================================= 
        bcf     STATUS,B_C        ; Clear the carry bit to prepare for rotate  
        rlf     ren_old,f         ; Rotate old bits left to align "Right-Bit"  
        movf    ren_new,w         ; Set up new bits in W                       
        xorwf   ren_old,f         ; XOR old (left shifted) with new bits       
        movf    ren_old,w         ; Put XOR results into W also                
        andlw   0x02              ; Mask to look at only "Left-Bit" of pair    
        movwf   next_dir          ; Save result (in W) as direction (bit=UP)   
        xorwf   last_dir,w        ; See if direction is same as before         
;
;       Prevent encoder slip from giving a false change in direction.
;
        btfsc   STATUS,B_Z        ; Zero flag set? (i.e, is direction same?)   
        goto    pe_continue       ; Yes, same direction so no slip; keep going 
        movf    next_dir,w        ; No Zero-flag, so direction changed         
        movwf   last_dir          ; Update the direction indicator             
        movf    ren_new,w         ; Save the current encoder bits (now in W)   
        movwf   ren_old           ;   for next time                            
        goto    read_encoder      ; Try again
pe_continue
        clrf    last_dir          ; Clear last_dir (default is DN)             
        btfss   ren_old,1         ; Are we going UP?                           
        goto    exit3             ; No, exit3                                  
up2 
        movlw   0x02              ; Get UP value                               
        movwf   last_dir          ;   and set in last_dir                      
exit3 
        movf    ren_new,w         ; Get the current encoder bits
        movwf   ren_old           ; Save them in ren_old for the next time
        movlw   1                 ; Flag - keep going
        goto    poll_exit 
poll_exit_and_end 
        clrw   
poll_exit
        iorlw   0x00              ; Set up Z flag from W 
        return                    ; Return to the caller
;
; *****************************************************************************
; *                                                                           *
; * Purpose:  This subroutine converts a 32 bit binary number to a 10 digit   *
; *           BCD number.  The input value taken from freq(0 to 3) is         *
; *           preserved.  The output is in BCD(0 to 4), each byte holds =>    *
; *           (hi_digit,lo_digit), most significant digits are in BCD_4.      *
; *           This routine is a modified version of one described in          *
; *           MicroChip application note AN526.                               *
; *                                                                           *
; *   Input:  The value in freq_0 ... freq_3                                  *
; *                                                                           *
; *  Output:  The BCD number in BCD_0 ... BCD_4                               *
; *                                                                           *
; *****************************************************************************
;
bin2BCD
        movlw   0x20              ; Set loop counter
        movwf   BCD_count         ;   to 32
        clrf    BCD_0             ; Clear output
        clrf    BCD_1             ;   "     "
        clrf    BCD_2             ;   "     "
        clrf    BCD_3             ;   "     "
        clrf    BCD_4             ;   "     "
bin_loop
        bcf     STATUS,B_C        ; Clear carry bit in STATUS
;
; Rotate bits in freq bytes.  Move from LS byte (freq_0) to next byte (freq_1).
; Likewise, move from freq_1 to freq_2 and from freq_2 to freq_3.
;
        rlf     freq_0,f          ; Rotate left, 0 -> LS bit, MS bit -> Carry
        rlf     freq_1,f          ; Rotate left, Carry->LS bit, MS bit->Carry
        rlf     freq_2,f          ; Rotate left, Carry->LS bit, MS bit->Carry
        rlf     freq_3,f          ; Rotate left, Carry->LS bit, MS bit->Carry
        btfsc   STATUS,B_C        ; Is Carry clear? If so, skip next instruction
        bsf     freq_0,0          ; Carry is set so wrap and set bit 0 in freq_0
;
; Build BCD bytes. Move into LS bit of BCD bytes (LS of BCD_0) from MS bit of
; freq_3 via the Carry bit.  
;
        rlf     BCD_0,f           ; Rotate left, Carry->LS bit, MS bit->Carry
        rlf     BCD_1,f           ; Rotate left, Carry->LS bit, MS bit->Carry
        rlf     BCD_2,f           ; Rotate left, Carry->LS bit, MS bit->Carry
        rlf     BCD_3,f           ; Rotate left, Carry->LS bit, MS bit->Carry
        rlf     BCD_4,f           ; Rotate left, Carry->LS bit, MS bit->Carry
        decf    BCD_count,f       ; Decrement loop count
        btfss   STATUS,B_Z        ; Is loop count now zero?
        goto    adjust            ; No, go to adjust
        return                    ; Yes, EXIT 
; ============================================================================
adjust  ; Internal subroutine, called by bin2BCD main loop only
; 
; As BCD bytes are being built, make sure the nibbles do not grow larger than 9. 
; If a nibble gets larger than 9, increment to next higher nibble.  
; (If the LS nibble of a byte overflows, increment the MS nibble of that byte.)
; (If the MS nibble of a byte overflows, increment the LS nibble of next byte.)
;
        movlw   BCD_0             ; Get pointer to BCD_0
        movwf   FSR               ; Put pointer in FSR for indirect addressing
        call    adj_BCD           ; 
        incf    FSR,f             ; Move indirect addressing pointer to BCD_1
        call    adj_BCD           ; 
        incf    FSR,f             ; Move indirect addressing pointer to BCD_2
        call    adj_BCD           ; 
        incf    FSR,f             ; Move indirect addressing pointer to BCD_3
        call    adj_BCD           ; 
        incf    FSR,f             ; Move indirect addressing pointer to BCD_4
        call    adj_BCD           ; 
        goto    bin_loop          ; Back to main loop of bin2BCD
; ============================================================================
adj_BCD  ; Internal subroutine, called by adjust only
        movlw   3                 ; Add 3
        addwf   INDF,w            ;   to LS digit
        movwf   BCD_temp          ; Save in temp
        btfsc   BCD_temp,3        ; Is LS digit + 3 > 7  (Bit 3 set)
        movwf   INDF              ; Yes, save incremented value as LS digit
        movlw   0x30              ; Add 3
        addwf   INDF,w            ;   to MS digit
        movwf   BCD_temp          ; Save as temp
        btfsc   BCD_temp,7        ; Is MS digit + 3 > 7  (Bit 7 set)
        movwf   INDF              ; Yes, save incremented value as MS digit
        return                    ; Return to adjust subroutine
;
; *****************************************************************************
; *                                                                           *
; * Purpose:  Display the frequency setting on the LCD.                       *
; *           2x16 LCD display so display freq kHz - e.g  14,025.000 kHz      *
; *                                                                           *
; *   Input:  The values in BCD_4 ... BCD_0                                   *
; *                                                                           *
; *  Output:  The number displayed on the LCD                                 *
; *                                                                           *
; *  When using a 16x2 LCD:                                                   *
; *    Line 1 addresses are  0x00 to 0x0F   (0x80 to 0x8F)                    *
; *    Line 2 addresses are  0x40 to 0x4F   (0xC0 to 0xCF)                    *
; *                                                                           *
; *****************************************************************************
;
show_freq
        movlw   0xC0              ; Point LCD at second line digit 1                
        call    cmnd2LCD          ; Send starting digit location to LCD
;
; Running 4-bit mode, so need to send Most Significant Nibble first.
;
; Extract and send "XXXX" from byte containing "XXXXYYYY"
;  - Swap halves to get YYYYXXXX
;  - Mask with 0x0F to get 0000XXXX
;  - Add ASCII bias (0030XXXX)
;
        swapf   BCD_3,w           ; Swap 10MHz BCD digit into lower nibble of W
        andlw   0x0F              ; Mask for lower nibble only       (0000XXXX)
        addlw   0x30              ; Add offset for ASCII char set    (0030XXXX)
        call    data2LCD          ; Send byte in W to LCD
;
; Extract and send "YYYY" from byte containing "XXXXYYYY"
;   - Mask with 0x0F to get 0000YYYY
;   - Add offset for ASCII character set in LCD  (0030YYYY)
;
        movf    BCD_3,w           ; Put 1MHz BCD digit into lower nibble of W
        andlw   0x0F              ; Mask for lower nibble only       (0000YYYY)
        addlw   0x30              ; Add offset for ASCII char set    (0030YYYY)
        call    data2LCD          ; Send byte in W to LCD
;
        swapf   BCD_2,w           ; Swap 100KHz BCD digit into lower nibble of W
        andlw   0x0F              ; Mask for lower nibble only       (0000XXXX)
        addlw   0x30              ; Add offset for ASCII char set    (0030XXXX)
        call    data2LCD          ; Send byte in W to LCD
;
        movf    BCD_2,w           ; Put 10KHz BCD digit into lower nibble of W
        andlw   0x0F              ; Mask for lower nibble only       (0000YYYY)
        addlw   0x30              ; Add offset for ASCII char set    (0030YYYY)
        call    data2LCD          ; Send byte in W to LCD
;
        swapf   BCD_1,w           ; Swap 1KHz BCD digit into lower nibble of W
        andlw   0x0F              ; Mask for lower nibble only       (0000XXXX)
        addlw   0x30              ; Add offset for ASCII char set    (0030XXXX)
        call    data2LCD          ; Send byte in W to LCD
;
        movf    BCD_1,w           ; Put 100 Hz BCD digit into lower nibble of W
        andlw   0x0F              ; Mask for lower nibble only       (0000YYYY)
        addlw   0x30              ; Add offset for ASCII char set    (0030YYYY)
        call    data2LCD          ; Send data byte in W to LCD
;
        swapf   BCD_0,w           ; Swap 10 Hz BCD digit into lower nibble of W
        andlw   0x0F              ; Mask for lower nibble only       (0000XXXX)
        addlw   0x30              ; Add offset for ASCII char set    (0030XXXX)
        call    data2LCD          ; Send data byte in W to LCD
;
        movf    BCD_0,w           ; Put 1 Hz BCD digit into lower nibble of W
        andlw   0x0F              ; Mask for lower nibble only       (0000YYYY)
        addlw   0x30              ; Add offset for ASCII char set    (0030YYYY)
        call    data2LCD          ; Send byte in W to LCD
;
        movlw   ' '               ; Send a space
        call    data2LCD          ;   to position 9 of LCD
        movlw   'P'
        call    data2LCD          ;   to position 10 of LCD
        movlw   'B'
        call    data2LCD          ;   to position 11 of LCD
        movlw   '3'                                  
        call    data2LCD          ;   to position 12 of LCD
        movlw   ' '
        call    data2LCD          ;   to position 13 of LCD
        movlw   'E'
        call    data2LCD          ;   to position 14 of LCD
        movlw   'n'
        call    data2LCD          ;   to position 15 of LCD
        movlw   'd'
        call    data2LCD          ;   to position 16 of LCD

        return                    ; 
;
; *****************************************************************************
; *                                                                           *
; * Purpose:  Check if LCD is done with the last operation.                   *
; *           This subroutine polls the LCD busy flag to determine if         *
; *           previous operations are completed.                              *
; *                                                                           *
; *   Input:  None                                                            *
; *                                                                           *
; * On exit:  PortB set as:  RB3          input                               *
; *                          all others   outputs                             *
; *****************************************************************************
; 
busy_check
        clrf    PortB             ; Clear all outputs on PortB
        bsf     STATUS,B_RP0      ; Switch to bank 1 for Tristate operation    
        movlw   b'00001000'       ; Set RB3 input, others outputs              
        movwf   TRISB             ;   via Tristate
        bcf     STATUS,B_RP0      ; Switch back to bank 0
        bcf     PortB,LCD_rs      ; Set up LCD for Read Busy Flag (RS = 0) 
        bsf     PortB,LCD_rw      ; Set up LCD for Read (RW = 1)  
        movlw   0xFF              ; Set up constant 255
        movwf   timer1            ;   for timer loop counter
LCD_is_busy
        bsf     PortB,LCD_e       ; Set E high
        movf    PortB,w           ; Read PortB into W
        movwf   LCD_read          ; Save W for later testing
        bcf     PortB,LCD_e       ; Drop E again
        nop                       ; Wait a
        nop                       ;   while
        bsf     PortB,LCD_e       ; Pulse E high (dummy read of lower nibble),
        nop                       ;   wait,
        bcf     PortB,LCD_e       ;   and drop E again
        decf    timer1,f          ; Decrement loop counter
        btfsc   STATUS,B_Z        ; Is loop counter down to zero?
        goto    not_busy          ; If yes, return regardless
;OLD     btfsc   LCD_read,7        ; Is Busy Flag (RB7) in save byte clear?       
        btfsc   LCD_read,LCD_busy ; Busy Flag (RB3) in save byte clear?        
        goto    LCD_is_busy       ; If not, it is busy so jump back
not_busy
        return                    ; 
;
; *****************************************************************************
; * Purpose:  Send Command or Data byte to the LCD                            *
; *           Entry point cmnd2LCD:  Send a Command to the LCD                *
; *           Entry Point data2LCD:  Send a Data byte to the LCD              *
; *                                                                           *
; *   Input:  W has the command or data byte to be sent to the LCD.           *
; *                                                                           *
; *  Output:  None                                                            *
; *****************************************************************************
;
cmnd2LCD   ; ****** Entry point ******
        movwf   LCD_char          ; Save byte to write to LCD
        clrf    rs_value          ; Remember to clear RS  (clear rs_value)   
        bcf     PortB,LCD_rs      ; Set RS for Command to LCD
        goto    write2LCD         ; Go to common code
data2LCD   ; ****** Entry point ********
        movwf   LCD_char          ; Save byte to write to LCD
        bsf     rs_value,0        ; Remember to set RS (set bit 0 of rs_value)
        bsf     PortB,LCD_rs      ; Set RS for Data to LCD
write2LCD
        call    busy_check        ; Check to see if LCD is ready for new data
        clrf    PortB             ; Clear all of Port B (inputs and outputs)
        bsf     STATUS,B_RP0      ; Switch to bank 1 for Tristate operation
        movlw   0x00              ; Set up to enable PortB data pins
        movwf   TRISB             ; All pins (RB7..RB0) are back to outputs
        bcf     STATUS,B_RP0      ; Switch to bank 0
        bcf     PortB,LCD_rw      ; Set LCD back to Write mode  (RW = 0)
        bcf     PortB,LCD_rs      ; Guess RS should be clear              
        btfsc   rs_value,0        ; Should RS be clear?  (is bit 0 == 0?) 
        bsf     PortB,LCD_rs      ; No, set RS                            
;
; Transfer Most Significant nibble  (XXXX portion of XXXXYYYY)
;

        movlw   0xF0              ; Set up mask                                        
        andwf   PortB,f           ; Keep RB7..RB4 but clear old RB3..RB0          
        swapf   LCD_char,w        ; Put byte into W (reverse nibbles)          
        andlw   0x0F              ; Mask to give 0000XXXX in W                 
        iorwf   PortB,f           ; To RB3..RB0 with RB7..RB4 unchanged        
        bsf     PortB,LCD_e       ; Pulse the E line high,
        nop                       ;   wait, 
        bcf     PortB,LCD_e       ;   and drop it again
;
; Transfer Least Significant nibble  (YYYY portion of XXXXYYYY)
;
        movlw   0xF0              ; Set up mask                                        
        andwf   PortB,f           ; Clear old RB3..RB0                         
        movf    LCD_char,w        ; Move LS nibble of into W                   
        andlw   0x0F              ; Mask to give 0000YYYY in W                 
        iorwf   PortB,f           ; To RB3..RB0 with RB7..RB4 unchanged        
        bsf     PortB,LCD_e       ; Pulse the E line high,
        nop                       ;   wait, 
        bcf     PortB,LCD_e       ;   and drop it again
        return

; *****************************************************************************
; *                                                                           *
; * Purpose:  Multiply the 32 bit number for oscillator frequency times the   *
; *           32 bit number for the displayed frequency.                      *
; *                                                                           *
; *                                                                           *
; *   Input:  The reference oscillator value in osc_3 ... osc_0 and the       *
; *           current frequency stored in freq_3 ... freq_0.  The reference   *
; *           oscillator value is treated as a fixed point real, with a 24    *
; *           bit mantissa.                                                   *
; *                                                                           *
; *  Output:  The result is stored in AD985X_3 ... AD985X_0.                  *
; *                                                                           *
; *****************************************************************************
;
calc_dds_word
        clrf    AD985X_0          ; Clear the AD9850/AD9851 control word bytes
        clrf    AD985X_1          ; 
        clrf    AD985X_2          ; 
        clrf    AD985X_3          ; 
        clrf    AD985X_4          ; 
        movlw   0x20              ; Set count  to 32   (4 osc bytes of 8 bits)
        movwf   mult_count        ; Keep running count
        movf    osc_0,w           ; Move the four osc bytes
        movwf   osc_temp_0        ;   to temporary storage for this multiply
        movf    osc_1,w           ; (Don't disturb original osc bytes)
        movwf   osc_temp_1        ; 
        movf    osc_2,w           ; 
        movwf   osc_temp_2        ; 
        movf    osc_3,w           ; 
        movwf   osc_temp_3        ; 
mult_loop
        bcf     STATUS,B_C        ; Start with Carry clear
        btfss   osc_temp_0,0      ; Is bit 0 (Least Significant bit) set?
        goto    noAdd             ; No, don't need to add freq term to total
        movf    freq_0,w          ; Get the "normal" freq_0 term
        addwf   AD985X_1,f        ;   and add it in to total
        btfss   STATUS,B_C        ; Does this addition result in a carry?
        goto    add7              ; No, continue with next freq term
        incfsz  AD985X_2,f        ; Yes, add one and check for another carry
        goto    add7              ; No, continue with next freq term
        incfsz  AD985X_3,f        ; Yes, add one and check for another carry
        goto    add7              ; No, continue with next freq term
        incf    AD985X_4,f        ; Yes, add one and continue
add7
        movf    freq_1,w          ; Get the "normal" freq_0 term
        addwf   AD985X_2,f        ; Add freq term to total in correct position
        btfss   STATUS,B_C        ; Does this addition result in a carry?
        goto    add8              ; No, continue with next freq term
        incfsz  AD985X_3,f        ; Yes, add one and check for another carry
        goto    add8              ; No, continue with next freq term
        incf    AD985X_4,f        ; Yes, add one and continue
add8
        movf    freq_2,w          ; Get the "normal" freq_2 term
        addwf   AD985X_3,f        ; Add freq term to total in correct position
        btfss   STATUS,B_C        ; Does this addition result in a carry?
        goto    add9              ; No, continue with next freq term
        incf    AD985X_4,f        ; Yes, add one and continue
add9
        movf    freq_3,w          ; Get the "normal" freq_3 term
        addwf   AD985X_4,f        ; Add freq term to total in correct position
noAdd
        rrf     AD985X_4,f        ; Shift next multiplier bit into position
        rrf     AD985X_3,f        ; Rotate bits to right from byte to byte
        rrf     AD985X_2,f        ; 
        rrf     AD985X_1,f        ; 
        rrf     AD985X_0,f        ; 
        rrf     osc_temp_3,f      ; Shift next multiplicand bit into position
        rrf     osc_temp_2,f      ; Rotate bits to right from byte to byte
        rrf     osc_temp_1,f      ; 
        rrf     osc_temp_0,f      ; 
        decfsz  mult_count,f      ; One more bit has been done.  Are we done?
        goto    mult_loop         ; No, go back to use this bit
; See if we have to turn on clock multiplier
        btfsc   DDS_flag,0        ; Is AD9850 flag set?
        goto    calc_DDS_AD9851   ; Yes, go to calc_AD9851
        movlw   0x00              ; No, no clock multiplier (AD9850)             
        goto    calc_DDS_OK       ; Goto calc_DDS_OK
calc_DDS_AD9851
        movlw   0x01              ; Turn on 6x clock multiplier (AD9851)      
calc_DDS_OK            
        movwf   AD985X_4          ; Last byte to be sent                      
                                  ; Mult answer is in bytes _3 .. _0          
        return                    ; Done.
;
; *****************************************************************************
; *                                                                           *
; * Purpose:  This routine sends the AD9850/AD9851 control word to the DDS    *
; *           using a serial data transfer.                                   *
; *                                                                           *
; *   Input:  AD985X_4 ... AD985X_0                                           *
; *                                                                           *
; *  Output:  The DDS chip register is updated.                               *
; *                                                                           *
; *****************************************************************************
;
send_dds_word
        movlw   AD985X_0          ; Point FSR at Least Significant Byte       
        movwf   FSR               ; 
next_byte
        movf    INDF,w            ; 
        movwf   byte2send         ; 
        movlw   0x08              ; Set counter to 8
        movwf   bit_count         ; 
next_bit
        rrf     byte2send,f       ; Test if next bit is 1 or 0
        btfss   STATUS,B_C        ; Was it zero?
        goto    send0             ; Yes, send zero
        bsf     PortB,DDS_dat     ; No, send one                               
        bsf     PortB,DDS_clk     ; Toggle write clock                         
        bcf     PortB,DDS_clk     ;                                            
        goto    break             ; 
send0
        bcf     PortB,DDS_dat     ; Send zero                                  
        bsf     PortB,DDS_clk     ; Toggle write clock                         
        bcf     PortB,DDS_clk     ;                                            
break
        decfsz  bit_count,f       ; Has the whole byte been sent?
        goto    next_bit          ; No, keep going.
        incf    FSR,f             ; Start the next byte unless finished
        movlw   AD985X_4+1        ; Next byte (past the end)
        subwf   FSR,w             ; 
        btfss   STATUS,B_C        ;
        goto    next_byte         ;
        bsf     PortB,DDS_load    ; Send load signal to the AD9850/AD9851             
        bcf     PortB,DDS_load    ;                                            
        return                    ;
;
; *****************************************************************************
; *                                                                           *
; * Purpose:  Power on initialization of Liquid Crystal Display.  The LCD     *
; *           controller chip must be equivalent to an Hitachi 44780.  The    *
; *           LCD is assumed to be a 8x1 or a 16x1 display.                   *
; *                                                                           *
; *   Input:  None                                                            *
; *                                                                           *
; *  Output:  None                                                            *
; *                                                                           *
; *****************************************************************************
;
init_LCD
        call    wait_64ms         ; Wait for LCD to power up
;        Put 4-bit command in RB3..RB0                                         
;        PIC's RB3..RB0 lines connect to LCD's DB7..DB4 (pins 14-11)            
        movlw   0x03              ; LCD init instruction (First)               
        movwf   PortB             ; Send to LCD via RB3..RB0                   
        bsf     PortB,LCD_e       ; Set the LCD E line high,
        call    wait_64ms         ;   wait a "long" time,
        bcf     PortB,LCD_e       ;   and then Clear E 
        movlw   0x03              ; LCD init instruction (Second)              
        movwf   PortB             ; Send to LCD via RB3..RB0                   
        bsf     PortB,LCD_e       ; Set E high,
        call    wait_32ms         ;   wait a while,
        bcf     PortB,LCD_e       ;   and then Clear E 
        movlw   0x03              ; LCD init instruction (Third)               
        movwf   PortB             ; Send to LCD via RB3..RB0                   
        bsf     PortB,LCD_e       ; Set E high,
        call    wait_32ms         ;   wait a while,
        bcf     PortB,LCD_e       ;   and then Clear E
        movlw   0x02              ; 4-bit mode instruction                     
        movwf   PortB             ; Send to LCD via RB3..RB0                   
        bsf     PortB,LCD_e       ; Set E high,
        call    wait_16ms         ;   wait a while,
        bcf     PortB,LCD_e       ;   and then Clear E
        movlw   0x28              ; 1/16 duty cycle, 5x8 matrix
        call    cmnd2LCD          ; Send command in w to LCD
        movlw   0x08              ; Display off, cursor and blink off 
        call    cmnd2LCD          ; Send command to LCD
        movlw   0x01              ; Clear and reset cursor
        call    cmnd2LCD          ; Send command in w to LCD
        movlw   0x06              ; Set cursor to move right, no shift
        call    cmnd2LCD          ; Send command in w to LCD
        movlw   0x0C              ; Display on, cursor and blink off
        call    cmnd2LCD          ; Send command in w to LCD
        return                    ; 
;
; ****************************************************************************P
; *                                                                           P
; * Purpose:  Display version and other info on LCD for 2 seconds             P
; *           upon power-up                                                   P
; *                                                                           P
; *   Input:  MCODE_REV_0 through MCODE_REV_4 set up                          P
; *                                                                           P
; *  Output:  LCD displays debug info                                         P
; *                                                                           P
; ****************************************************************************P
;
display_version
        movlw   0x80              ; Point LCD at digit 1                
        call    cmnd2LCD          ;
        movlw   'P'               ; digit 1              
        call    data2LCD          ;
        movlw   'I'               ; digit 2                  
        call    data2LCD          ;
        movlw   'C'               ; digit 3                
        call    data2LCD          ;
        movlw   '-'               ; digit 4               
        call    data2LCD          ;
        movlw   'E'               ; digit 5               
        call    data2LCD          ;
        movlw   'L'               ; digit 6              
        call    data2LCD          ;        
        movlw   ' '               ; digit 7              
        call    data2LCD          ;
        movlw   'D'               ; digit 8               
        call    data2LCD          ;
        movlw   'i'               ; digit 9               
        call    data2LCD          ;
        movlw   'a'               ; digit 10              
        call    data2LCD          ;
        movlw   'g'               ; digit 11              
        call    data2LCD          ;
        movlw   ' '               ; digit 12              
        call    data2LCD          ;
        movlw   'v'               ; digit 13              
        call    data2LCD          ;
        movlw   MCODE_REV_0       ; Get mcode rev byte
        call    data2LCD          ;   and display it (digit 9)
        movlw   MCODE_REV_1       ; Get mcode rev byte
        call    data2LCD          ;   and display it (digit 10)
        movlw   MCODE_REV_2       ; Get mcode rev byte
        call    data2LCD          ;   and display it (digit 11)
        movlw   MCODE_REV_3       ; Get mcode rev byte
;
        movlw   0xC0              ; Point LCD at digit 1 of second line               
        call    cmnd2LCD          ;
        movlw   'A'               ; digit 1              
        call    data2LCD          ;
        movlw   'A'               ; digit 2                  
        call    data2LCD          ;
        movlw   '0'               ; digit 3                
        call    data2LCD          ;
        movlw   'Z'               ; digit 4               
        call    data2LCD          ;
        movlw   'Z'               ; digit 5              
        call    data2LCD          ;        
        movlw   ' '               ; digit 6              
        call    data2LCD          ;
        movlw   '/'               ; digit 7               
        call    data2LCD          ;
        movlw   ' '               ; digit 8               
        call    data2LCD          ;
        movlw   'K'               ; Space in digit 9
        call    data2LCD          ;
        movlw   'a'               ; digit 10             
        call    data2LCD          ;
        movlw   'n'               ; digit 11                 
        call    data2LCD          ;
        movlw   'g'               ; digit 12               
        call    data2LCD          ;
        movlw   'a'               ; digit 13              
        call    data2LCD          ;
        movlw   ' '               ; digit 14              
        call    data2LCD          ;
        movlw   'U'               ; digit 15             
        call    data2LCD          ;        
        movlw   'S'               ; digit 16             
        call    data2LCD          ;        
;
        call    wait_a_sec        ; Wait one second
;
        return
;
; *****************************************************************************
; * beep_speaket                                                              *
; * Purpose:  Short beep for diagnostic purposes                              *
; *                                                                           *
; *****************************************************************************
;
beep_speaker
        movlw   0xFB              ; Turn RA2 into 
        banksel TRISA             ; Switch to bank 1
        movwf   TRISA             ;   an output (speaker)
        banksel PortA             ; Back to Bank 0
;
        movlw   0x40
        movwf   LoopCounter1      ; 64 times through
beep_speaker_loop ; 
        bsf     PortA,speaker
        ; On for 955 us
        call    wait_500us
        call    wait_200us
        call    wait_200us
        call    wait_50us        
        call    wait_5us        
;
        bcf     PortA,speaker
        ; Off for 956 us
        call    wait_500us
        call    wait_200us
        call    wait_200us
        call    wait_50us        
        call    wait_5us        
        nop
        decfsz  LoopCounter1,f    ; Done?
        goto    beep_speaker_loop ; No, back 
; Clean up 
        movlw   0x04
        movwf   PortA             ; Make sure it's high before leaving
        movlw   0xFF              ; Turn RA2 into an input
        banksel TRISA             ; Switch to Bank 1
        movwf   TRISA             ; (for pushbutton detect)
        banksel PortA             ; Back to Bank 0
;
        return
;
; *****************************************************************************
; *                                                                           *
; * Purpose:  Wait for a specified number of milliseconds.                    *
; *                                                                           *
; *           Entry point wait_a_sec:  Wait for 1 second                      *
; *           Entry point wait_a_sec:  Wait for 1/2 second                    *
; *           Entry point wait_256ms:  Wait for 256 msec                      *
; *           Entry point wait_128ms:  Wait for 128 msec                      *
; *           Entry point wait_64ms :  Wait for 64 msec                       *
; *           Entry point wait_32ms :  Wait for 32 msec                       *
; *           Entry point wait_16ms :  Wait for 16 msec                       *
; *           Entry point wait_8ms  :  Wait for 8 msec                        *
; *           Entry point wait_4ms  :  Wait for 8 msec                        *
; *           Entry point wait_2ms  :  Wait for 2 msec                        *
; *           Entry point wait_1ms  :  Wait for 1 msec                        *
; *           Entry point wait_500us:  Wait for 500 usec                      *
; *           Entry point wait_200us:  Wait for 200 usec                      *
; *           Entry point wait_100us:  Wait for 100 usec                      *
; *           Entry point wait_50us :  Wait for 50 usec                       *
; *           Entry point wait_25us :  Wait for 25 usec                       *
; *           Entry point wait_10us :  Wait for 10 usec                       *
; *           Entry point wait_5us  :  Wait for 5 usec                        *
; *                                                                           *
; *   Input:  None                                                            *
; *                                                                           *
; *  Output:  None                                                            *
; *                                                                           *
; *****************************************************************************
;
wait_a_sec  ; ****** Entry point ******    
        call    wait_256ms        ;       
        call    wait_256ms        ;       
        call    wait_256ms        ;       
        call    wait_256ms        ;       
        return
wait_half_sec  ; ****** Entry point ******    
        call    wait_256ms        ;       
        call    wait_256ms        ;       
wait_256ms  ; ****** Entry point ******    
        call    wait_128ms        ;
        call    wait_128ms        ;
        return
wait_128ms  ; ****** Entry point ******    
        movlw   0xFF              ; Set up outer loop 
        movwf   timer1            ;   counter to 255
        goto    outer_loop        ; Go to wait loops
wait_64ms  ; ****** Entry point ******     
        movlw   0x80              ; Set up outer loop
        movwf   timer1            ;   counter to 128
        goto    outer_loop        ; Go to wait loops
wait_32ms   ; ****** Entry point ******    
        movlw   0x40              ; Set up outer loop
        movwf   timer1            ;   counter to 64
        goto    outer_loop        ; Go to wait loops
wait_16ms   ; ****** Entry point ******    
        movlw   0x20              ; Set up outer loop
        movwf   timer1            ;   counter to 32  
        goto    outer_loop        ; Go to wait loops
wait_8ms   ; ****** Entry point ******     
        movlw   0x10              ; Set up outer loop
        movwf   timer1            ;   counter to 16
        goto    outer_loop        ;
wait_4ms   ; ****** Entry point ******     
        movlw   0x8               ; Set up outer loop
        movwf   timer1            ;   counter to 8
        goto    outer_loop        ;

wait_5us    ; ****** Entry point ******     
        nop
        return
wait_10us 