;===========================================================================
	title		"proto.ASM file for use with PIC16C84"
;	Created by Baluncore October 1997 -  April 2000
;
; Assemble with    " <path>\mpasm.exe /C- /E- /P16F84A /X-  <path>\filename.asm "
;
;===========================================================================

;---------------------------------------------------------------------------
; Assembler directives and defaults
;---------------------------------------------------------------------------
	; b=4 column tab size for output listing
	; r=dec, change numeric radix to decimal for output listing
	; n=0, set zero lines per page to prevent page headers in listing
	list b=8, r=dec, n=0		; output listing only
	radix	dec			; decimal is now default input radix
	processor	pic16F84A	; Processor type is an assembler directive
;
;---------------------------------------------------------------------------
; Configuration Register Fuse Bits
;---------------------------------------------------------------------------
	; Top 9 bits are not used, they read as all ones, writing as all zeros is OK
	; Foscillator     0 = LP,    1 = XT,    2 = HS,    3 = RC
	; Watchdog timer	Disable = 0	Enable = 4
	; Power up timer	Disable = 0	Enable = 8
	; Code	Protected = 0	Unprotected = 16		( reversed in the pic16F84 ? )
	__config	16+8+0+1		; yes, it is a ( double underscore config )
	; turns CodeProtect off, PowerUpTimer on, watchdog off, select xtal oscillator mode
;
;---------------------------------------------------------------------------
; Memory Bounds	( again use the double underscore )
;---------------------------------------------------------------------------
;	__maxram	h'2F'	; highest register file address used in pic16c84
;	__badram	h'07'	; register 7 does not exist
;
;---------------------------------------------------------------------------
; Definitions and the naming of bits and registers goes in here
;---------------------------------------------------------------------------
	#define	w	0	; destination is W reg if dest = 0
	#define	f	1	; destination is RegisterFile if dest = 1
	#define	c	0	; Carry flag is status bit zero
	#define	dc	1	; Digit Carry flag is status bit one
	#define	z	2	; Zero flag is status bit two
;
	cblock	0	; Bank 0 special register file names
	indf, tmr0, pcl, status, fsr, porta, portb, undef, eedata, eeaddr, pclath, intcon
	endc
;
	cblock	0	; Bank 1 special register file names
	indf, optreg , pcl, status, fsr, trisa, trisb, undef, eecon1, eecon2, pclath, intcon
	endc
;
;===========================================================================
; Macro code for later use goes in here
;===========================================================================
bank0	macro
		bcf	status,5	; clear bit 5 in status reg to select bank zero
	endm
;
;---------------------------------------------------------------------------
bank1	macro
		bsf	status,5	; set bit 5 in status reg to select bank one 
	endm
;
;---------------------------------------------------------------------------
skipz	macro
		btfss	status,z	; test and skip if zero
	endm
;
;---------------------------------------------------------------------------
skipnz	macro
		btfsc	status,z	; test and skip if non-zero
	endm
;
;---------------------------------------------------------------------------
skipc	macro
		btfss	status,c	; test and skip if carry is set
	endm
;
;---------------------------------------------------------------------------
skipnc	macro
		btfsc	status,c	; test and skip if no carry
	endm
;
;---------------------------------------------------------------------------
; Variables are stored in the register file, starting at location  0C hex
;---------------------------------------------------------------------------
	; Your user variables follow, along with those needed for included routines
	cblock	0CH		; start of 36 available bytes of ram in register file 
		; uservar1	; users variables here please
	endc			; note that a total of only 36 bytes of ram are available
	; don't forget to initialise critical variables before enabling interupts
;
;===========================================================================
; Power up code starts here following reset of chip
;===========================================================================

	org	0	; Reset vector
			; note, three spare instruction locations available here
	goto	startup
;
;---------------------------------------------------------------------------
; Main interupt handling code goes here, save the status and w registers
;---------------------------------------------------------------------------
	cblock			; assign variables to next place in register file
		temp_wreg	; used during interupts to protect w register
		temp_stat	; used during interupts to protect status register
	endc
	org	4		; Interupt Vector
	movwf	temp_wreg	; save w reg to temporary 
	swapf	status,w	; nibble swap status into w reg
	movwf	temp_stat	; save status to temporary
;		
;---------------------------------------------------------------------------
; Identify source of interupt as T0_ovflo, INTPIN or RBdelta
;---------------------------------------------------------------------------
	btfss	intcon,2	; test if T0 overflowed flag is set
	goto	intpin		; no, so go and test external intpin flag
				; flag was set so handle real time interupt
;		
;---------------------------------------------------------------------------
; Real time clock interupt and task scheduling is handled here
;---------------------------------------------------------------------------
	; Ignore the reload of tmr0 if you do not need a specific interupt rate
	; as tmr0 will just roll over and continue to generate an interupt each roll
	; select the best interupt rate with the option register prescaler value
; this code is commented out because it is not normally needed
	; first reload tmr0 with next tick period if needed, it counts up
	; DataToLoad = 255 - ((OscHz / (4 * PreScale * IntRateHz )) - 12)	????
	; bank0		; tmr0 is in bank0
	; movlw	255	; DataToLoad
	; movwf	tmr0	; loads tmr0 and resets the prescaler to zero
	; warning, loading tmr0 may not be reliable if other interupts are also enabled
	; note that the prescaler is also reset to zero when tmr0 is loaded
;
;---------------------------------------------------------------------------
; this chain of tasks is executed every time an interupt is generated by a tmr0 overflow
;---------------------------------------------------------------------------
task_1	; Your multi-line action block for task_1 goes in here
;
task_2	; Your multi-line action block for task_2 goes in here
		; etc
;
;---------------------------------------------------------------------------
; schedules are executed after the delay count reaches zero
; if counter is zero then execution of that schedule is skipped and left at zero
; delete or replicate the schedule code as you need it, change labels if you replicate it
;---------------------------------------------------------------------------
; first example is an 8 bit down-counter, max delay 255 interupts	( about 2 seconds )
	cblock			; assign variables to next place in register file
		dc_1		; none, one or more down counters
	endc
	movf	dc_1,f		; test for zero
	btfss	status,z	; (loading dc_? with a tick count schedules the task)
	decfsz	dc_1,f		; (loading dc_? with 0 cancels a scheduled task)
	goto	xit_sch1	; this instruction is destination of two skip sources
	;
sched_1	; Your handler for sched_1 once only action block goes in here
	;
xit_sch1
	;
;---------------------------------------------------------------------------
; second example is a 16 bit up-counter, max delay 65,288 interupts ( about 10 minutes )
	cblock			; assign variables to next place in register file
		uc_lo		; for scheduling later events
		uc_hi		; high byte of 16 bit up-counter
	endc
	movf	uc_hi,f		; test if high byte is zero, if zero ignore this schedule
	btfsc	status,z	; if msb is zero, schedule is inactive, cancelled or expired  
	goto xit_sch2		; load the two byte up-counter with complement of count wanted
	incfsz	uc_lo,f		; to start the delay up-counter load lsb first, then msb last
	goto xit_sch2		; maximum time is when uc_hi = 01 hex and uc_lo = 00 hex
	incfsz	uc_hi,f		; with 109 Hz interupt this gives about 10 minutes delay
	goto xit_sch2		; it executes once when all bytes reach zero at timeout
	;
sched_2	; Your handler for sched_2 once only action block goes here
	;
xit_sch2
	;
;---------------------------------------------------------------------------
XitTmr
	bcf	intcon,2	; we have handled tmr0 int so finally clear the flag
;---------------------------------------------------------------------------
intpin
	btfss	intcon,1	; test if the external int pin flag is set
	goto	RBdelta		; no so jump it to next flag test
;---------------------------------------------------------------------------
	;
	; Your code to handle the ext interupt from RB0/INT pin goes here
	;
;---------------------------------------------------------------------------
	bcf	intcon,1	; clear its flag and test next
;---------------------------------------------------------------------------
RBdelta
	btfss	intcon,0	; test if portb bits change flag is set
	goto	interexit	; finished handling the interupts		
;---------------------------------------------------------------------------
	;
	; Your code to handle an interupt due to a change of portb goes here
	;
;---------------------------------------------------------------------------
	bcf	intcon,0	; finished handling all interupts, all flags are now clear
;---------------------------------------------------------------------------
; Restore the status and W registers, then return from interupt
;---------------------------------------------------------------------------
interexit
	swapf	temp_stat,w	; nibble swap the status back to w reg
	movwf	status	; restore the status reg
	swapf	temp_wreg,f	; nibble swap back through w reg
	swapf	temp_wreg,w	; to avoid changing zero status
	retfie		; return from interupt, re-enable global interupt flag
;
;===========================================================================
startup  ; Main program gets to continue here, chained from goto instruction at location zero
;===========================================================================
; Initialise variables ( move the first three instructions to 000 hex if you need space )
;---------------------------------------------------------------------------
	clrf	dc_1	; disable all down-counters for scheduled tasks
	clrf	uc_lo
	clrf	uc_hi
;
;---------------------------------------------------------------------------
; load the Option Register, Real Time Interupts, ( RB pull-ups, TMR0 source, prescaler )
;---------------------------------------------------------------------------
;   Oscillator frequency and prescaler modulus determines interupt rate from TMR0, 
;     option register bits      000     001     010     011     100     101     110     111
;Crystal   Crystal   TMR0out         
; basis       kHz    Rate Hz     /2     /4      /8      /16     /32     /64     /128    /256
;2^15        32.768    32.00   16.00   8.000   4.000   2.000   1.000   0.500   0.250   0.125
;2^15*100  3276.800  3200.00 1600.00 800.000 400.000 200.000 100.000 50.0000 25.0000 12.5000
;NTSC TV   3579.545  3495.65 1747.82 873.912 436.956 218.478 109.239 54.6195 27.3098 13.6549
;2^12*900  3686.400  3600.00 1800.00 900.000 450.000 225.000 112.500 56.2500 28.1250 14.0625
;4 MHz     4000.000  3906.25 1953.12 976.562 488.281 244.141 122.070 61.0352 30.5176 15.2588 
;2^12*kHz  4096.000  4000.00 2000.00 1000.00 500.000 250.000 125.000 62.5000 31.2500 15.6250
;2^22	   4194.304  4096.00 2048.00 1024.00 512.000 256.000 128.000 64.0000 32.0000 16.0000
;PAL TV    4433.619  4329.70 2164.85 1082.42 541.213 270.607 135.303 67.6516 33.8258 16.9129
;BaudRate  4915.200  4800.00 2400.00 1200.00 600.000 300.000 150.000 75.0000 37.5000 18.7500
;
;prescaler value sets interupt rate only when internal TMR0 is used with prescaler
	bank1
	movlw	b'00000100'	; internal tmr0 with prescale 1/32, portB soft pull-ups enabled
	movwf	optreg		; 3.579545MHz / ( 4 * 32 * 256 ) = 109.239 Hz int rate
;
;---------------------------------------------------------------------------
; Registers Port A & B direction   ( still in bank1 )
;---------------------------------------------------------------------------
;	floating inputs should be internally pulled up or externally terminated when not driven
;	unused outputs should be left open
	movlw	b'00011111'	; 0 is output, 1 is input, port A default to inputs
	movwf	trisa		; there is no internal pull-up of portA inputs 
	movlw	b'11111111'	; default port B to all inputs
	movwf	trisb		; internal pull-up is controlled by option register bit 7
;
;---------------------------------------------------------------------------
; Register Port A & B initial data values where used as outputs
;---------------------------------------------------------------------------
	bank0			; return to bank 0
	movlw	b'00011111'	; porta has only 5 bits
	movwf	porta
	movlw	b'11111111'	; portb has 8 bits
	movwf	portb
;
;---------------------------------------------------------------------------
; Enable interupts to set the time bomb ball rolling
;---------------------------------------------------------------------------
	; real time clock T0 interupt can be stretched if (IntPin or RBdelta interupts)
	;	 are enabled and T0 is loaded each timeout with new value
	movlw	b'10100000'	; enable global and T0 interupt flag only
	movwf	intcon		; intcon reg is mapped into both banks
;
;===========================================================================
;   --  We Have Lift Off  -- ,   code here is main program
;===========================================================================
maincode
;
;
;		Your code goes here
;
;
	goto	maincode
;
;===========================================================================
; Subroutines follow in this last block
;===========================================================================
; Compact universal 16 bit forground delay timer
;---------------------------------------------------------------------------
; at 32.768 kHz -> 610.4 usec per inner loop, .15625 sec per outer loop, max = 40.0 sec
; at 3.2768 MHz -> 6.104 usec per inner loop, 15.6 msec per outer loop, max = 0.400 sec
; at 3.5795 MHz -> 5.587 usec per inner loop, 1.43 msec per outer loop, max = 0.366 sec
; at 4.0000 MHz -> 5.000 usec per inner loop, 1.28 msec per outer loop, max = 0.327 sec
; at 4.0960 MHz -> 4.883 usec per inner loop, 1.25 msec per outer loop, max = 0.320 sec
; at 4.1943 MHz -> 4.768 usec per inner loop, 1.22 msec per outer loop, max = 0.312 sec
; at 4.4336 MHz -> 4.511 usec per inner loop, 1.15 msec per outer loop, max = 0.295 sec
; at 4.9152 MHz -> 4.069 usec per inner loop, 1.04 msec per outer loop, max = 0.266 sec
; at 8.0000 MHz -> 2.500 usec per inner loop, 0.64 msec per outer loop, max = 0.163 sec
; at 10.000 MHz -> 2.000 usec per inner loop, 512. usec per outer loop, max = 0.128 sec
; at 20.000 MHz -> 1.000 usec per inner loop, 256. usec per outer loop, max = 0.065 sec
;---------------------------------------------------------------------------
; call delay with inner loop count in the w register, (zero gives 256 cycles)
; 	 	          outer loop count in delay_cnt,  (1 gives w register count only)
; note that times may be stretched by background interupt handler overheads
	cblock			; assign variable to next place in register file
		delay_cnt	; outer loop counter used in delay routine
	endc
delay
	addlw	255			; subtract one from w reg
	btfsc	status,z	; have we reached zero yet
	decfsz	delay_cnt,f	; decrement the outer loop counter, w is zero
	goto	delay		; 20 oscillator cycles loop period
	return				; exit with zero in the w reg and zero in delay_cnt
;---------------------------------------------------------------------------

;===========================================================================
; End of program
;===========================================================================

	end
