;----------------------------------------------------------------------;
;ALPHA4M.ASM  Sends and receives characters serially 4800 baud with PC ;   
;----------------------------------------------------------------------;

;  A terminal program runs on the PC set to 4800 baud, 8 bit, no parity
;  1 stop bit no handshaking.  When a character is typed on the keyboard
;  it is sent to the PIC and the PIC returns the next 3 ASCII characters

;                            .-----------.
;                           -|RA2     RA1|--------[DB9S pin 2]       
;                           -|RA3     RA0|----{R}--[DB9S pin 3]       
;                           -|RA4    OSC1|--|X|___ gnd    
;                      V+ ---|MCLR   OSC2|--|X|  
;                     gnd ---|Vss     Vdd|--- V+  -{R}- = 22 K resistor
;                           -|RB0     RB7|-      X = 4 MHz cer. res.
;                           -|RB1     RB6|-      V+ = 4.5 or 5 Volts
;                           -|RB2     RB5|-       
;                           -|RB3     RB4|-        
;                            '-----------'         
;                               PIC16F84      

;  DB9S female com port connections:
;      pins 1, 4 and 6 connected together  (DCD,DTR & DSR)
;      pins 7 and 8 connected together     (RTS & CTS)
;      pin 5 to gnd
;      pin 2 to PIC pin 18 (RA1)
;      pin 3 to 22 K resistor to PIC pin 17 (RA0)


        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 incom PORTA, 0     ;  input port
        #DEFINE outcom PORTA, 1    ;  output port
               

         CBLOCK H'0C'
           txreg              ;  holds byte to be transmitted
           rxreg              ;  holds byte received 
           char               ;  holds character to be transmitted
           bitcount           ;  holds count of bits when transmitting
           cntmsec            ;  holds counter for milliseconds
         ENDC

           ORG 0              ;  start a program memory location zero
           goto main          ;  skip over subroutines

;----------------------------------------------------------------------;
;          initialization - set up ports and timer options             ;
;----------------------------------------------------------------------;
init:
         movlw B'00000001'    ;  RA0 to input
         tris PORTA           ;  contents of W copied to PORT A ...
         movlw B'0000000'     ;  all of PORT B outputs
         tris PORTB           
         return

;----------------------------------------------------------------------;
;                        time delay routines                           ;
;----------------------------------------------------------------------;
bitdelay   movlw D'51'                ;  one bit period at 4800 baud
                                      ;  50 * 4 + 5 + 1 + 2 = 208 usec
                                      ;  for 'call bitdelay'
    ;  Timing is determined by counting instruction cycles. 
    ;  micro4 is a loop that take 4 microseconds each time through,
    ;  (4 mhz crystal).  By using W, you save a general register.
    ;  The last time through take 5 microseconds, including the return.
    ;  If W is 248 on entry the total time is 247 * 4 + 5 = 993 usec.
    ;  An additional 2 usec for the call gives 995 microseconds.
    ;  The instruction 'call micro4' in this case represents 995 usec.

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 ***
msec250:    movlw D'250'               ;  250 millisecond delay
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                     

;----------------------------------------------------------------------;
;                     the main program                                 ;
;----------------------------------------------------------------------;
main:                         ; this is the main program
         call init            ; set up ports
         call msec250         ; let things settle 
loop:
         call rx
         movwf char
         incf char, f
         movf char, W
         call tx
         incf char, f
         movf char, W
         call tx
         incf char, f
         movf char, W
         call tx
         goto loop

;----------------------------------------------------------------------;
;                 transmit byte in W at 4800 baud to PC                ;
;----------------------------------------------------------------------;
; normal rs232 is -V for a high, +V for a low
; this would translate to 0V for high +5 for low
; a bit length at 4800 baud is 208 microseconds
; this is made up of a delay of 199 microseconds, (call micro4), plus 
; 9 or 10 microseconds taken up with instructions in each txloop
 
tx:         movwf txreg                ; put W into transmit register
            movlw D'08'                ; eight bits of data
            movwf bitcount             ; a counter for bits
            bsf outcom                 ; start bit (flipped remember) 
txloop:     movlw D'49'                ; delay time
            call micro4                ; wait 48*4+5+2 = 199 microsec
            rrf txreg, f               ; roll rightmost bit into carry
            btfsc STATUS, C            ; if carry 0,  set bit (a low)
            goto clrbit                ; else clear bit, (a high)
            bsf outcom                 ; +5V on output pin
            goto testdone              ; are we finished?
clrbit:     bcf outcom                 ; 0 volts on output pin
testdone:   decfsz bitcount, f         ; one less data bit, skip when 0
            goto txloop                ; more bits left, delay this one
            call bitdelay              ; delay for last data bit
            bcf outcom                 ; 0V, ( a high ) for stop bits
            call bitdelay              ; 2 stop bits
            call bitdelay
            return                     

;----------------------------------------------------------------------;
;            receive byte  at 4800 baud from PC, put in W              ;
;----------------------------------------------------------------------;
rx:                       
startbit:
            btfss incom                ; goes high for start, (reversed)
            goto startbit              ; not yet wait some more
            movlw D'24'                ; wait half a bit time
            call micro4                ; 
            btfss incom                ; check if still high
            goto startbit              ; no, start again
            movlw D'8'                 ; 8 bits
            movwf bitcount             ; into counter
            clrf rxreg                 ; clear out register
receive:
            movlw D'49'                ; makes call micro4 = 199 usec
            call micro4                ; wait one bit length (- instr.)
            bsf STATUS, C              ; start with high to shift in
            btfsc incom                ; if pin low, shift in high (rev)
            bcf STATUS, C              ; else change to low
            rrf rxreg, f               ; shift bit in
            decfsz bitcount, f         ; last bit collected?
            goto receive               ; not yet, get more, 8 usec+call
            call bitdelay              ; stop bit
            movf rxreg, W              ; result into W
            return

         end