
;********************** Stopwatch  Program ******************************
;
; Counts in hundredths seconds and also outputs serial out signal at rc.0.
; Display is standard LCD module

;Note that this is in Parallax 'dialect' which groups several commands into 
;one. There is a translation supplied in the Parallax assembler manual, now
;distributed by Tech Tools at www.tech-tools.com. A program to convert to  
;the Microchip 'dialect' is available from either Tech Tools as above or from 
;Advanced Transdata at www.adv-transdata.com. Assemblers that handle this
;dialect are also available from the above sources (eg. SPASM). The object 
;code, serinsw.obj, should run on any programmer.

;*********************** Flags Used: ********************************
;
;  Flag.0 = Lap flag, setting it avoids the display routine (lcd)
;  Flag.2 = Initialisation - sends initial values to display on reset
;  Flag.5 = Refresh flag - allows only one display refresh
;  Flag.7 = Not a flag, used for temp storage of RS bit
;  See also below for more flags


; Notes 1. The single gate operation uses only the stop gate

;       2. The software automatically determines whether the radio module
;       is normally low or normally high when the micro is reset. If you
;       are using isolating switches for the radio module inputs, make sure
;       they are SHUT before resetting the stopwatch.



;******************** Assembler Directives ********************


		device pic16c55,xt_osc,wdt_off,protect_off
		reset start



lcd_pwr          =     ra.0    ;LCD is powered by the micro!
RS               =     ra.1    ;These are LCD commands
RW               =     ra.2
E                =     ra.3
data             =     rb
startradio       =     rc.7
startbutton      =     rc.3
lapbutt          =     rc.2
lapstart         =     rc.1
stopman          =     rc.4
stopradio        =     rc.6
one_gate         =     rc.5


clkout           =     1Dh.0     ;Or alternately, put onto output pin



delay_cntr      =      0Bh             ;Counter for serial delay routines
bit_cntr        =      0Ch             ;Number of transmitted bits
				       ;Offset in string
xmt_byte        =      0Eh             ;The transmitted byte
module          =      0Fh

jump1           =      10h.0           ;Jump table to allow update of
jump2           =      10h.1           ; LCD and serial display
jump3           =      10h.2
jump4           =      10h.3
jump5           =      10h.4
jump6           =      10h.5
jump7           =      10h.6
jump8           =      10h.7

up100           =      1Bh.0      ;Causes hundredths update
norm_high       =      1Bh.1
send_8          =      1Bh.2      ;Sends an 8 to hundredths
disp_done       =      1Bh.3      ;Shows that display has finished update
norestart       =      1Bh.4      ;One gate, allows only one start per event
stop_delay      =      1Bh.5      ;Prevents immediate stop on single gate ops
lap_update      =      1Bh.6      ;Allows one update for lap stop
lapstopped      =      1Bh.7      ;Allows only one update per button push
lapout          =      pa2        ;Prevents LCD update during LAP 

hrs             =      1Ch        ;Registers containing the time
hundths         =      16h        ; in seconds, minutes, etc.
tenths          =      15h
sec             =      14h
tensec          =      13h
min             =      12h
tenmin          =      11h
count           =      17h
flag            =      18h                                          
temp            =      19h
temp2           =      1Ah
inhibit_cnt     =      1Eh        ;Inhibits stop gate operation


bit_K           =      19            ;For 9600-baud operation @ 3.2768 MHz
serial_out      =      rc.0



;********************** Program starts here *******************



start           clr     flag
		clr     count
		clr     temp
		clr     temp2
		clr     module
		clr     10h
		clr     1Bh


;******* Subroutines (these must be in the first page of memory) ************

		jmp     avoid               ;Jump over the top until called

lapstop         jb      lapstopped,a6
		setb    lapout              ;Timer runs, no display update
		setb    flag.0              ;Display avoid
		clrb    flag.5              ;Allow refresh
		setb    up100               ;Allow update hundredths
		clrb    disp_done
		setb    lap_update          ;Otherwise display is no update
		setb    lapstopped
a6              ret

stopped         mov     option,#00100011b        ;External source

		clrb    RS                       ;Update hundredths
		mov     module,#10h              ;Module address
		mov     temp2,#8Ch               ;Hundredths address
		call    lcd                                      
		setb    RS
		mov     temp2,hundths            ;Output 0.01sec
		call    lcd
		
test            setb    stop_delay
		clr     inhibit_cnt

		jb      startbutton,restore    ;Restart pressed
		jb      norm_high,reverse3
		jb      startradio,restore   ;Restart pressed
		jmp     reverse3a
reverse3        jnb     startradio,restore
reverse3a       nop
gate1           jmp     test                 ;Keep testing

restore         mov     option,#00000011b    ;Internal source
		setb    send_8               ;Set hundredths to 8
		setb    norestart            ;Don't want restart
		jmp     wait
							     
refresh         jb      flag.5,nofresh      ;No refresh
		clrb    lapstopped          ;Allow lap stop again
		clrb    lapout              ;Start after lap stop
		sb      flag.2
		setb    send_8
		clrb    disp_done
		clrb    flag.0              ;Restart display
		setb    flag.5              ;Refresh done once
		jb      flag.2,a1           ;Initialisation
		jmp     hr1                 ;Refresh display
a1              jmp     colon

bit_delay       mov     delay_cntr,#bit_K 
:loop           nop
		djnz    delay_cntr, :loop
		ret

delay           mov     temp2,#200        

:loop           djnz    temp,:loop
		djnz    temp2,:loop                             
		ret

lcd             jb      lap_update,a5     ;Have to update hundredths
		jb      flag.0,nodisp     ;Lap flag set? Yes, no display 
				  
a5              movb    flag.7,RS        ;Save RS                         
		clrb    RS               ;Instruction mode
		setb    RW               ;Set for read
		mov     !rb,#255         ;Rb = output

:loop           setb    E         ;Enable the LCD
		nop            ;Wait for it                  
		nop            ; to settle
		mov temp,data  ;Rb info into temp
		clrb E         ;Finished read
		snb temp.7     ;Busy bit set?
		jmp :loop      ;Yes, wait 
		movb RS,flag.7  ;No, return RS
		clrb RW        ;Set for write
		mov !rb,#0     ;Rb an output
		mov data,temp2  ;Send data or inst
		setb E         ;PIC version                 
		nop            ; of enter
		nop            ; command
		clrb E         ; finished
		jmp serial       ;Serial output routine
serialdone      nop

lcdtest         nop
nodisp          nop
		ret


serial          jnb     RS,notyet    ;temp2 contains data at this time
                sub     temp2,#30h   ;Change back from ASCII
                OR      module,temp2 ;Combine number and module address
                mov     xmt_byte,module  ;Prepare for serial xmit 


:again          mov     bit_cntr,#8     ;Eight bits in a byte. 
		setb    serial_out      ;Change to setb serial_out for direct
					;connection.

		call    bit_delay       ;Start bit. 

:xmit           rr      xmt_byte        ;Rotate right moves data bits into
					;carry, starting with bit 0. 

		movb    serial_out,/c    ;Change to movb serial_out,/c for
					;direct connection. 

		call    bit_delay       ;Data bit. 
		djnz    bit_cntr,:xmit  ;Not eight bits yet? Send next data bit

		clrb    serial_out      ;Change to clrb serial_out for direct
					;connection

		call    bit_delay       ;Stop bit. 
		
notyet          jmp     serialdone

avoid           nop


;******************************End subroutines****************


		mov ra,#0       ;Fill buffers
		mov rb,#0       ;with zeros
		mov rc,#0
							     
		mov !ra,#0h     ;Initialise ports
		mov !rb,#0h
		mov !rc,#11111110b ;Make rc an input port
							     
		setb lcd_pwr  ;Turn on LCD
		call delay
		clrb RS
		mov temp2,#00001100b ;Display on
		call lcd
		mov temp2,#00110000b ;8 bit 1 line            
		call lcd
		mov temp2,#00000001b ;Clear disp
		call lcd

		mov     hundths,#30h
		mov     tenths,#30h 
		mov     sec,#30h            ;Initial values
		mov     tensec,#30h         ;corresp with
		mov     min,#30h            ;0 in ASCII                   
		mov     tenmin,#30h
		mov     hrs,#30h

		jb      startradio,highpol  ;Is radio polarity normally high?
		jmp     lowpol              ; no it is low
highpol         setb    norm_high           ; yes, set flag
		
lowpol          setb    flag.2
		mov     option,#00100011b      ;Halt the RTCC
		mov     RTCC,#5                ; Allows intialisation
		jmp     refresh                                   
hskeep          clrb    flag.2

		mov option,#00000011b ;Prescale by 16

hold            setb    stop_delay
		clr     inhibit_cnt
		jb      startbutton,run    ;Run button pressed?
		jb      norm_high,reverse1
		jb      startradio,run     ;Radio start?
		jmp     reverse1a
reverse1        jnb     startradio,run     ;Radio start?
reverse1a       nop
		jnb     one_gate,hold      ;Single gate operation?
		jb      norestart,hold      ;Event over, no restart
		jb      norm_high,reverse4
		jb      stopradio,run      ; Yes, start on stop gate
		jmp     reverse4a
reverse4        jnb     stopradio,run
reverse4a       nop
		jmp     hold               ;No, wait for run


run             mov     RTCC,#1            ;Load initial count 
		clrb    RS
		mov     module,#10h     ;Module address
		mov     temp2,#8Ch      ;Hundredths address
		call    lcd                                      
		setb    RS
		mov     temp2,#38h  ;Put '8' into hundredths position
		call    lcd


wait            mov     w,RTCC               ;Has 0.005 sec passed?
		jz      go                   ;Yes, jump to go
		jnb     disp_done,hr1        ;Finished update of digits?
		jmp     wait                 ;No, not passed .005 sec

freeze          jmp     stopped              ;Stop routine

go              jb      stopman,freeze       ;Manual stop?
		jb      norm_high,reverse2
		jb      stop_delay,gate2     ;Used for single gate ops
		jb      stopradio,freeze     ;Radio stop? 
gate2           jmp     reverse2a
reverse2        jb      stop_delay,gate3
		jnb     stopradio,freeze
gate3           nop                      ;Single gate ops (avoids stopradio)
reverse2a       nop


		jb      lapbutt,lap         ;Lap pushed?
		skip
lap             call    lapstop             ;Yes, set flag.0              

		jb      lapstart,refresh     ;Start after lap
nofresh         nop                          ;Refresh already done
	       

		inc     count                ;0.005 second counter
		cje     count,#1,down      ;0.005 sec passed?
		skip                       ;No
down            clrb    clkout             ;Yes, drop clock out       

		cje     count,#2,tick  ;0.01 sec has passed
		jmp     wait

tick            setb    clkout
		clr     count
		inc     hundths                   ;Increments every cycle

		cje     hundths,#3Ah,distenths    ;0.1 sec passed?
		jmp     wait                      ;No       
		
distenths       mov     hundths,#30h   ;Clear hundredths           
		inc     tenths
		clrb    disp_done            ;Allow display update
		cje     tenths,#3Ah,dispsec  ;1 sec passed?
		jmp     secths    ;No display tenths

dispsec         mov     tenths,#30h           ;Clear tenths
		inc     sec                   ;Yes, increment seconds
		inc     inhibit_cnt
		cjb     inhibit_cnt,#3,delay_on ;2 second count passed?
		clr     inhibit_cnt             ; Yes, clear the counter
		clrb    stop_delay            ; and the delay flag

delay_on        clr     count                 ;Clear 0.01 sec count
		setb    clkout                ;Raise clock out
		cje     sec,#3Ah,disp10sec    ;10 sec passed?       
					;No, display seconds
		jmp     sec1

disp10sec       mov sec,#30h     ;Yes, clear sec count
		inc tensec       ;Inc 10 seconds
		cje tensec,#36h,dispmin ;Minute passed?
			  ;No, display 10secs and secs
		jmp sec10

dispmin         mov     tensec,#30h           ;Clear 10 secs              
		inc     min                   ;Increment mins
		cje     min,#3Ah,d10min       ;10 min pass?
		jmp     min1                  ;Min disp routine

d10min          mov     min,#30h              ;Clear minutes
		inc     tenmin                ;Inc 10 mins
		cje     tenmin,#36h,dhrs
		jmp     min10                 ;Display

dhrs            mov     tenmin,#30h           ;Clear ten minutes
		inc     hrs
		jmp     hr1

		
colon           clrb    RS
		mov     temp2,#84h   ;Colon address              
		call    lcd
		setb    RS
		mov     temp2,#3Ah   ;Colon ASCII
		call    lcd

		clrb    RS
		mov     temp2,#87h   ;Colon address              
		call    lcd
		setb    RS
		mov     temp2,#3Ah   ;Colon ASCII
		call    lcd


		clrb RS
		mov temp2,#8Ah   ;DP address
		call lcd
		setb RS
		mov temp2,#2Eh   ;DP ASCII
		call lcd

hr1             cjae    RTCC,#250,wait
		jb      jump1,min10
		clrb    RS
		mov     module,#70h
		mov     temp2,#83h
		call    lcd
		setb    RS
		mov     temp2,hrs
		call    lcd
		setb    jump1
							      
min10           cjae    RTCC,#250,wait      ;Enough time?
		jb      jump2,min1          ;Already done?
		clrb    RS
		mov     module,#60h         ;Module address
		mov     temp2,#85h          ;Address 10 mins
		call    lcd
		setb    RS
		mov     temp2,tenmin        ;Send digit
		call    lcd
		setb    jump2               ;Operation finished
	       
min1            cjae    RTCC,#250,wait
		jb      jump3,sec10
		clrb    RS                  ;Set for write
		mov     module,#50h         ;Module address
		mov     temp2,#86h          ;Address for mins
		call    lcd                 ;Send to lcd
		setb    RS
		mov     temp2,min           ;Load min digit              
		call    lcd                 ;Send to lcd
		setb    jump3

sec10           cjae    RTCC,#250,wait
		jb      jump4,sec1
		clrb    RS
		mov     module,#40h  ;Module address
		mov     temp2,#88h   ;Load address 10secs
		call    lcd         ;Send to lcd
		setb    RS
		mov     temp2,tensec ;Load 10seconds
		call    lcd         ;Send to lcd
		setb    jump4
		
sec1            cjae    RTCC,#250,wait
		jb      jump5,secths
		clrb    RS          ;Set for write
		mov     module,#30h  ;Module address
		mov     temp2,#89h   ;Load address secs        
		call    lcd         ;Send to lcd
		setb    RS
		mov     temp2,sec    ;Load seconds 
		call    lcd         ;Send to lcd
		setb    jump5

secths          cjae    RTCC,#250,wait
		jb      jump6,hunsec
		clrb    RS
		mov     module,#20h  ;Module address
		mov     temp2,#8Bh   ;Tenths address
		call    lcd
		setb    RS
		mov     temp2,tenths  ;Out tenths
		call    lcd
		setb    jump6
							     
hunsec          jb      flag.2,a2      ;Initialisation flag
		jnb     up100,put8

a2              cjae    RTCC,#250,wait
		clrb    RS
		mov     module,#10h ;Module address
		mov     temp2,#8Ch  ;Hundredths address
		call    lcd                                      
		setb    RS
		mov     temp2,hundths  ;Output 0.01sec
		call    lcd
		clrb    lap_update
		clrb    up100

put8            cjae    RTCC,#250,wait
		jnb     send_8,terminate
		clrb    RS               ;Puts 8 in hundredths posiion
		mov     module,#10h      ;Module address
		mov     temp2,#8Ch       ;Hundredths address
		call    lcd                                      
		setb    RS
		mov     temp2,#38h       ;Output 0.01sec
		call    lcd
		clrb    send_8

terminate       setb    disp_done
		clr     10h            ;Jump flag register

		jb      flag.2,hskeep    ;Finish initialise

		jb flag.2,hskeep ;Finish initialise
		jmp wait         ;Wait

							     



