;============================================================================================
title "proto.ASM file for use with PIC16C84"
; Created by VK7ZID in October 1997 - April 2000
;
; Assemble with " <path>\mpasm.exe /C- /E- /P16c84 /X- <path>\filename.asm "
;
;============================================================================================
;--------------------------------------------------------------------------------------------
; Assembler directives and defaults
;--------------------------------------------------------------------------------------------
; b=8 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 pic16c84 ; 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 interrupt 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 interrupt 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 interrupt and task scheduling is handled here
;--------------------------------------------------------------------------------------------
; Ignore the reload of tmr0 if you do not need a specific interrupt rate
; as tmr0 will just roll over and continue to generate an interrupt each roll
; select the best interrupt 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 interrupt 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, canceled 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 interrupt 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 interrupt 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 interrupt 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 interrupt 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 interrupt 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 interrupt 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 interrupt ball rolling
;--------------------------------------------------------------------------------------------
; real time clock T0 interrupt 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 interrupt 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
;--------------------------------------------------------------------------------------------
; 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)
; 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
;--------------------------------------------------------------------------------------------
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
;note that times may be stretched by background high priority interrupt handler overheads
;--------------------------------------------------------------------------------------------
;============================================================================================
; End of program
;============================================================================================
end