;----------------------------------------------------------------------;
; MORSE4M.ASM       Send numbers 0-9 in morse code to speaker and LEDs ;
;----------------------------------------------------------------------;

; -[spkr]- = piezo speaker   .-----------.
;                           -|RA2     RA1|-       V+ = 4.5 or 5 Volts
;         gnd --[spkr]--[R]--|RA3     RA0|-       X = 4 MHz cer. res.
;   -[R]- = 100 ohm         -|RA4    OSC1|--|X|___ gnd
;   -{r}- = 470 ohm    V+ ---|MCLR   OSC2|--|X|  
;   -|<- = LED        gnd ---|Vss     Vdd|--- V+
;            gnd ---|<--{r}--|RB0     RB7|-         
;            gnd ---|<--{r}--|RB1     RB6|-         
;            gnd ---|<--{r}--|RB2     RB5|-       
;            gnd ---|<--{r}--|RB3     RB4|---[PB]--- gnd        
;                            '-----------'         
;                               PIC16F84      -[PB]- pushbutton

        LIST P=16F84           ;  tells which processor is used
        INCLUDE "p16f84.inc"   ;  defines various registers etc. Look 
        ERRORLEVEL -224        ;  suppress annoying message from tris
        __CONFIG _PWRTE_ON & _XT_OSC & _WDT_OFF   ;  config. switches

        #DEFINE pushbutton PORTB, 4    ;  pushbutton on RB4 to ground
        #DEFINE speaker    PORTA, 3    ;  piezo speaker RA3 thru 100 ohm
                                       ;  to ground 

            CBLOCK     H'C'
                temp            ; a temporary variable
                bitcount        ; counter for bits
                nbr             ; holds current number to send
                cntmsec         ; used in generating msec delays
                sndcnt          ; used in gerating sound
            ENDC
          
            ORG 0               ; start at location 0

            goto main           ; jump over to main routine       

;----------------------------------------------------------------------;
;     Use W to convert number in W to pattern needed to send #         ;
;----------------------------------------------------------------------;
pattern:
            addwf PCL, f    ; PCL points to the first entry in the table

       dt H'1F',H'0F',H'07',H'03',H'01',H'00',H'10',H'18',H'1C',H'1E'
       ;     0    1     2     3     4     5     6     7     8     9

;----------------------------------------------------------------------;
;           Sound routine lasting about 100 milliseconds               ;
;----------------------------------------------------------------------;
snd1: 
             movlw D'50'          ; 50 on - off cycles 
             movwf sndcnt
sndloop:                              
             bsf speaker          ;  RA3 high
             call msec1           ;  1 msec high
             bcf speaker          ;  RA3 low
             call msec1           ;  1 msec low
             decfsz sndcnt, f     ;  finished?
             goto sndloop         ;  no
             return               ;  yes 


;----------------------------------------------------------------------;
;    Output number in W to LEDs on Port B and to spkr on  RA3          ;
;----------------------------------------------------------------------;
sendnbr:
             movwf PORTB         ; display number on LEDs 
             call pattern        ; get pattern of dits and dahs
             movwf temp          ; save it 
             movlw 5             ; total of 5 dits or dahs ...
             movwf bitcount      ; into a counter
bitloop:     btfss temp, 4       ; check 5th bit, if it is 1, send dah
             call dit            ; else it is 0, send dit
             btfsc temp, 4       ; and skip next instruction
             call dah            ; get here only if bit 5 is 1
             rlf temp, f         ; rotate left once giving new bit 5 
             decfsz bitcount, f  ; are we finished?
             goto bitloop        ; no, send new bit 5
             clrf PORTB          ; yes, turn display off
             return

;----------------------------------------------------------------------;
;                               Dit routine                            ;
;----------------------------------------------------------------------;
dit          
             call snd1               ; 100 msec of tone
             movlw D'100'            ; followed by 100 msec of silence
             call nmsec
             return

;----------------------------------------------------------------------;
;                               Dah routine                            ;
;----------------------------------------------------------------------;
dah:         
             call snd1               ; 100 msec of tone
             call snd1               ; stretch it to 300 msec
             call snd1
             movlw D'100'            ; and 100 msec of silence
             call nmsec
             return
             
;----------------------------------------------------------------------;
;            Wait until button on RB4 is released                      ;
;----------------------------------------------------------------------;
waitup:    
            btfss pushbutton         ; test RB4
            goto $ -1                ; ck again if pressed
            movlw D'10'
            call nmsec               ; wait 10 msec for debounce
            btfss pushbutton         ; check again, still up?
            goto waitup              ; no start over
            return                   ; yes, finished

;----------------------------------------------------------------------;
;                       Initialization Subroutine                      ;
;----------------------------------------------------------------------;
init:
            movlw 0                    ; RA0 - RA4 outputs
            tris PORTA                 
            movlw H'10'                ; all outputs except RB4 input
            tris PORTB                 ; on port B
            movlw H'0'                 ; all outputs low (off)
            movwf PORTB
            movwf PORTA
            option                     ; pullups enabled
            return               
 
;----------------------------------------------------------------------;
;       Main routine, sends a new number each time button pressed      ;
;----------------------------------------------------------------------;
main:    
            call init                 ; set up ports etc
start:      clrf nbr                  ; start with nbr = 0
mainloop:   call waitup
            btfsc pushbutton          ; wait on button press
            goto $ -1
            movf nbr, W               ; get number into W
            call sendnbr              ; and output it
            incf nbr, f               ; set up for next number
            movlw H'0A'               ; reached 10?
            subwf nbr, W
            btfss STATUS, Z           ; yes start again at 0
            goto mainloop             ; no, wait for next button press
            goto start

;----------------------------------------------------------------------;
;                        time delay routines                           ;
;----------------------------------------------------------------------;
micro4      addlw H'FF'                ;  subtract 1 from 'W'
            btfss STATUS,Z             ;  skip when you reach zero
            goto micro4                ;  more loops
            return                     

                ;*** N millisecond delay routine ***
msec1:      movlw 1                    ;  delay for one millisecond
nmsec:      movwf cntmsec              ;  delay for N (in W) millisec
msecloop:   movlw D'248'               ;  1 usec for load
            call micro4                ;  this instruction is 995 usec
            nop                        ;  1 usec 
            decfsz cntmsec, f          ;  1 usec, (2 if skip taken)
            goto msecloop              ;  2 usec, loop = 995+5 = 1 msec
            return 

            end