;*******************************************************************
;
; "Digital" Frequency display with /64 prescaler & no offsets
;
; Crystal freq. = 4.000MHz +/- a bit
;
;*******************************************************************
;
; First, let us choose our weapon - 16F84 or 16F628
;
; Comment out the next line [;#define F84] if using a 16F628
#define F84
#ifndef F84
#define F628
#endif
;*******************************************************************
;
; Some Testing Stuff(tm)
;
;#define testing 1 ; Comment out when testing finished
;#define Two_Line 1 ; Un-comment for two line displays
;************************ REVISION HISTORY *************************
;
; FM1.000 Originally from FM3/4 9:39pm 14 May 2002
; As implemented in experimental 3.5MHz receiver
;
;*******************************************************************
;
; FM1.003 Fixed? major silliness in LO-IF code
; Re-wrote USB/LSB suffix code
; Added #defines for crook displays
; Added #defines for two line displays
; Wrapped #ifdef ... endif around debugging code
;
;*******************************************************************
;
; FM1.004 Added code to allow user to fix crook display
; Deleted #defines for crook displays
; Pin 18 is now input. 1 = good display, 0 = crook
;
;*******************************************************************
;
; FM2.000 New Hardware! Deleted external counter & gating
; Now uses the same scheme as the LC Meter, with the
; third byte of the count implemented in the PIC.
; Basically, the "output" of the timer register is
; counted within the gate timing loop.
;
;*******************************************************************
;
; FM2.001 Discovered that I don't need to use RA0 as a gate
; cos RA4 can be used as a timer input, even when
; defined as an output - all that is required is to
; set it high to count or low to inhibit.
; Jeez, Microchip are smart arses.
; I dunno why I didn't spot this long ago.
; (Can't be used on the LC Meter, cos its oscillator
; needs to be clamped HIGH, not low as in this case).
;
;*******************************************************************
;
; FM2.002 Added 9600 baud serial output via RA0
;
;*******************************************************************
;
; FM2.003 Rewrote RollOver subroutine to use INTCON,T0IF bit.
; Incorporated two bits from OvrFlow counter
; to extend range to over 80MHz.
;
;*******************************************************************
;
; FM2.004 Changed to 32 bit counting.
;
;*******************************************************************
;
; FM2.005 Added "Calibrate" mode.
;
;*******************************************************************
;
; FM2.006 Moved "divide by 4" to increase resolution of
; the stored IF offsets
;
;*******************************************************************
;
; FM2.007 Moved "check for rollover" out of the inner MS400
; timing loop and adjusted loop count appropriately
; The aim - to improve the resolution of the software
; calibration by a factor of around 13 to 15 times.
;
;*******************************************************************
;
; fm2b.007 Ported to 16F628
; FM2c.007 Introduced macros
; fm2.008 Renumbered
;
;*******************************************************************
;
; fm2.009 Cleaned up AM IF Offset calculation
; Converted some inline code to subroutines
; Created new 32 bit "copy" macro
; Adjusted calibration slightly
; Added a "Processor =" message
; Removed advertising.
;
;*******************************************************************
;
; ghzfm.000 Added multiply by 64
; Rendered offsets ineffective
; changed display format to
; xxxx.xxxxxx MHz
; Gate time now 1.000 Second
;
;
;
;*******************************************************************
;o-----o-----o-----o-----o-----o-----o-----o-----o-----o-----o-----o
;*******************************************************************
;
; Some frequently used code fragments
; Use macros to make mistreaks consistently.
;
;-------------------------------------------------------------------
; Select Register Bank 0
bank0 macro
errorlevel +302 ; Re-enable bank warning
bcf STATUS,RP0 ; Select Bank 0
endm
;-------------------------------------------------------------------
; Select Register Bank 1
bank1 macro
bsf STATUS,RP0 ; Select Bank 1
errorlevel -302 ; disable warning
endm
;-------------------------------------------------------------------
; Copy a 32 bit thing from one place to another
copy macro from,to
movf from+0,W
movwf to+0
movf from+1,W
movwf to+1
movf from+2,W
movwf to+2
movf from+3,W
movwf to+3
endm
;*******************************************************************
;
; CPU configuration
;
#ifdef F84
MESSG "Processor = 16F84"
#define RAMStart 0x0C ; by VK3BHR
processor 16f84
include <p16f84.inc>
__config _HS_OSC & _PWRTE_ON & _WDT_OFF
#endif
#ifdef F628
MESSG "Processor = 16F628"
#define RAMStart 0x20
processor 16f628
include <p16f628.inc>
__config _HS_OSC & _PWRTE_ON & _WDT_OFF & _CP_OFF & _BODEN_ON & _LVP_OFF
#endif
;*******************************************************************
;
; I/O configuration
;
#define S_out PORTA,0x00 ; 9600 baud serial out
#define PUFF PORTA,0x00 ; Testing counter out
;#define FIXIT PORTA,0x01 ; 1 = "good display"
; 0 = do CRLF at "chr 8"
#define PSC PORTA,0x01 ; 1 = multiply by 64
#define ENA PORTA,0x02 ; Display "E"
#define RS PORTA,0x03 ; Display "RS"
#define CLAMP PORTA,0x04 ; Pull-down the timer input
#define Store PORTB,0x04 ; Pin 10, 0 = Measure BFO
#define Add_LO PORTB,0x05 ; Pin 11, 0 = RF := LO + IF
; 1 = RF := | LO + (-IF) |
#define BFO_Lo PORTB,0x06 ; Pin 12, 0 = BFO on lower freq.
#define BFO_Hi PORTB,0x07 ; Pin 13, 0 = BFO on higher freq.
#define Prg_FLG FLAGS,0x05
#define AMflag FLAGS,0x03 ; 0 = Don't print USB/LSB suffix
#define beq bz ; Motorola syntax branches
#define BEQ bz
#define BNE bnz
#define bne bnz
#define BCC bnc
#define bcc bnc
#define BCS bc
#define bcs bc
#define BRA goto
#define bra goto
;*******************************************************************
;
; file register declarations: uses only registers in bank0
; bank 0 file registers begin at 0x20 in the 16F628
;
;*******************************************************************
cblock RAMStart
dbg0:4 ; Debugging stuff
dbg1:4
dbg2:4
dbg3:4
dbg4:4
dbg5:4
bcd:5 ; BCD, MSD first
SBflag ; 0 = Lower BFO frequency
; 1 = Higher
COUNT ; Bin to BCD convert (bit count)
cnt ; (BCD BYTES)
CHR
TEMP ; DATS/Putchr temporary
pmsg_t ; Used by PMSG
FLAGS
S_Wtemp ; "debug" Variables
S_count
D_Wtemp
D_Stemp
D_FSR
D_hex
endc
#ifdef F84
Part2 equ D_hex+1 ; Just tack on end
#endif
#ifdef F628
Part2 equ 0x70 ; $70-7F Visible from all banks
#endif
cblock Part2
COUNT1 ; Used by delay routines
COUNT2 ; Timing (100ms)
COUNT3 ; Timing (100ms)
COUNT4 ; Timing (400ms)
AccA:4 ; Binary, MSByte first
AccB:4 ; Intermediate frequency
Hold:4 ; Used in "cal" mode
endc
;**********************************************************
;
; Begin Executable Stuff(tm)
;
org 0
GO clrwdt ; 0 << Reset
clrf INTCON ; 1 No interrupts
#ifdef F628
movlw 0x07 ; 2 Comparator off
movwf CMCON ; 3
#endif
goto START ; 4 << Interrupt.
;**********************************************************
;
; Part of string printer
;
pmsub movwf PCL ; Goto W
nop ; Just in case
pm_end return
;**********************************************************
;
; Text Strings (stored in RETLWs)
;
mhz dt " MHz",0
Spaces dt " ",0
USB dt "U",0
LSB dt "L",0
Prog dt "P",0
Cal dt "C",0
#ifdef Two_Line
adv3 dt "1234567890ABCDEF",0
endif
;**********************************************************
;
; Main Program
;
START call InitIO ; INITIALISE PORTS
CLRF PORTA
CLRF PORTB
bsf S_out ; Serial output to idle
CALL LCDINIT ; INITIALIZE LCD MODULE
; MOVLW adv1 ; Sign on
; call pmsg
; btfss FIXIT ; Test input 1 = just return
; CALL LINE2 ; 0 = fix bad display
; movlw adv2
; call pmsg
; CALL MS512 ; Delay for about 1 sec.
; CALL MS512 ; 0.512 sec x 2
CALL CLEAR
;**********************************************************
;
; Check if in "Calibrate" mode
;
btfsc Store ; If grounded initially
goto newbit ; then were in "cal"
MOVLW 0xfa ; Set initial counter
MOVWF Hold+0 ; value
MOVLW 0xff ;
MOVWF Hold+1 ; for a 4 MHZ XTAL
MOVLW 0x5f
MOVWF Hold+2
MOVLW 0x00 ; Unused
MOVWF Hold+3
GetCal call Measure
call Display
movlw Cal ; Say "we're calibrating"
call pmsg
CALL HOME
;
; Adjust Cal value
;
cal_dn btfsc BFO_Lo
goto cal_up
incf Hold+2,f ; Add 1
bne inc_xit
incf Hold+1,f
bne inc_xit
incf Hold+0,f
inc_xit goto StorCal
cal_up btfsc BFO_Hi
goto StorCal
;
; Hold := Hold + (1-) ; Subtract 1
;
Hadd_2 movlw 0xff ; Process LS byte
addwf Hold+2,F
bcc Hadd_1 ; If no carry,do next
incf Hold+1,f ; Else roll over higher
bne Hadd_1 ; bytes as appropriate
incf Hold+0,f ; may roll over MSByte
Hadd_1 movlw 0xff ; Process next byte
addwf Hold+1,F
bcc Hadd_0 ; If no carry,do next
incf Hold+0,f ; may roll over MSByte
Hadd_0 movlw 0xff ; Process next byte
addwf Hold+0,F
;
; Time to save "Cal" value?
;
StorCal btfss Store ; Ready to store it?
goto GetCal
call MS512 ; Delay 0.5 sec
btfss Store ; De-bounce
goto GetCal
copy Hold,AccB ; Write EEPROM from AccB
movlw 0x10 ; EEADR of Cal value
call EE_WR
;**********************************************************
;
; Begin a new measurement cycle
;
newbit movlw 0x10 ; EEADR of Cal value
call EE_RD ; in AccB
copy AccB,Hold ; Get timing "constant"
call HOME ; Display ready
clrf SBflag ; 0 = Lower BFO frequency
; 1 = Higher
bcf AMflag ; 0 = No USB/LSB suffix
bcf Prg_FLG
btfsc Store ; Doing "BFO STORE"?
goto GetOffs
call MS512 ; Delay 0.5 sec
btfsc Store ; De-bounce
goto GetOffs
GetIf call Measure ; Get freq in AccA:4
copy AccA,AccB ; For EEPROM Writing
call Display ; Display freq in AccA
movlw Prog ; Say "we're programming"
call pmsg
CALL HOME
btfss Store ; Ready to store it?
goto GetIf
call MS512 ; Delay 0.5 sec
btfss Store ; De-bounce
goto GetIf
bsf Prg_FLG ; Flag "to be stored"
GetOffs btfss BFO_Hi ; Which Offset??
goto Get2 ; Point @ EEPROM
btfss BFO_Lo ; 4 bytes each
goto Ch2 ; BFO low link only
goto Ch3 ; No links
Get2 btfss BFO_Lo
goto Ch0 ; Both links
goto Ch1 ; BFO high link only
Ch0 movlw 0x00 ; Offset channel 0 (both links fitted)
goto EndOff
Ch1 bsf AMflag ; We're gunna print
comf SBflag,f ; that BFO is on higher frequency
movlw 0x04 ; Offset channel 1 (BFO_Hi link fitted)
goto EndOff
Ch2 bsf AMflag ; We're gunna print
; that BFO is on lower frequency
movlw 0x08 ; Offset channel 2 (BFO_Lo link fitted)
goto EndOff
Ch3 movlw 0x0C ; Offset channel 3 (no links fitted)
; goto EndOff
EndOff btfsc Prg_FLG ; Storing Offset?
goto Do_St ; If not, then
call EE_RD ; must be reading.
goto Do_Meas
Do_St call EE_WR
;
; Now have IF in AccB
;
Do_Meas call Measure ; Measure Local Osc Freq.
;
; Now have LO in "AccA"
; and IF in "AccB"
;
Add_Sub btfss Add_LO ; Add or Sub LO freq?
goto AddLSB ; Clear = just add
call MinusA ; RF := |IF - LO|
; SBflag is OK
AddLSB call AplusB
;
; Fix overflow. If negative then make positive
;
btfss AccA+0,7 ; Set? (=Overflow)
goto OK2go ; Clear = OK 2 print
call MinusA ; Make positive and
comf SBflag,f ; Swap USB/LSB
;
; Display resulting number in AccA
;
OK2go call Display ; display result at last
;
; Print suffix - USB, LSB or nuffin
; Now disabled
btfsc AMflag ; Do we print at all?
goto trySBf
movlw Spaces ; nuffin = spaces
goto EndMsg
trySBf btfsc SBflag,0 ; Which sideband?
goto pLSB
movlw USB ; USB obviously
goto EndMsg
pLSB movlw LSB ; LSB
; goto EndMsg
EndMsg call pmsg ; Print selected trailer
#ifdef Two_Line
CALL LINE2 ; WRITE second LINE
movlw adv3
call pmsg
endif
goto newbit ; Start next measurement
;**********************************************************
;
; AccA := AccA + AccB
;
AplusB movf AccB+3,W ; Process LSB
addwf AccA+3,F
bcc Add_2 ; If no carry,do next
incf AccA+2,f ; Else roll over higher
bne Add_2 ; bytes as appropriate
incf AccA+1,f
bne Add_2
incf AccA+0,f ; may roll over MSByte
Add_2 movf AccB+2,W ; Process next byte
addwf AccA+2,F
bcc Add_1 ; If no carry,do next
incf AccA+1,f ; Else roll over higher
bne Add_1 ; bytes as appropriate
incf AccA+0,f ; may roll over MSByte
Add_1 movf AccB+1,W ; Process next byte
addwf AccA+1,F
bcc Add_0 ; If no carry,do next
incf AccA+0,f ; may roll over MSByte
Add_0 movf AccB+0,W ; Process next byte
addwf AccA+0,F
return
;**********************************************************
;
; Negate number in AccA (2's complement form)
;
MinusA comf AccA+0,f ; Complement all bits
comf AccA+1,f ; of number
comf AccA+2,f
comf AccA+3,f
incf AccA+3,f ; Add 1
bne N_xit
incf AccA+2,f
bne N_xit
incf AccA+1,f
bne N_xit
incf AccA+0,f
N_xit return
;**********************************************************
;
; Divide AccA:4 by 4
;
;**********************************************************
Div4 call Div2 ; Divide AccA:4 by 4
;**********************************************************
;
; Divide AccA:4 by 2
;
;**********************************************************
Div2 rrf AccA+0,f
rrf AccA+1,f
rrf AccA+2,f
rrf AccA+3,f
bcf AccA+0,7 ; Possible bad carry in.
return
;**********************************************************
;
; Multiply AccA:4 by 64
;
;**********************************************************
Mul64 call Mul2
call Mul2
call Mul2
call Mul2
call Mul2 ; then fall through
;**********************************************************
;
; Multiply AccA:4 by 2
;
;**********************************************************
Mul2 rlf AccA+3,f
rlf AccA+2,f
rlf AccA+1,f
rlf AccA+0,f
bcf AccA+3,0 ; Possible bad carry in.
return
;**********************************************************
;
; Print String addressed by W
; Note: Strings are in program space
;
pmsg movwf pmsg_t ; Temp for pointer
pm1 movf pmsg_t,W ; Get current pointer
call pmsub
andlw 0xff ; Test returned value
beq pm_end ; NULL = All done
call DATS
incf pmsg_t,F
goto pm1
;**********************************************************
;
; Delay for 1000ms (trimmed for actual clock freq)
; Check for Timer register roll over and count 'em
;
; Uses: W, COUUNT1, COUNT2, COUNT3 & others
;
;**********************************************************
MS1000 MOVF Hold+0,w ; 100 MS DELAY LOOP
MOVWF COUNT1 ; 4 MHZ XTAL
MOVF Hold+1,w ; Count up
MOVWF COUNT2 ; to 24 bit overflow
MOVF Hold+2,w
MOVWF COUNT3
L3 INCFSZ COUNT3,F
GOTO L3
call RollOver ; Check for Timer0 RollOver
INCFSZ COUNT2,F
GOTO L3
INCFSZ COUNT1,F
GOTO L3
RETLW 0
;**********************************************************
;
; SEND A COMMAND BYTE TO LCD DISPLAY MODULE
;
STROBE BCF RS ; SELECT COMMAND REGISTER
GOTO CM
;**********************************************************
;
; Put a BCD nybble to display
;
PutNyb ANDLW 0x0F ; MASK OFF OTHER PACKED BCD DIGIT
ADDLW 0x30 ; Convert BIN to ASCII
;**********************************************************
;
; Put a data byte to display
;
DATS movwf TEMP ; Save character for LCD
call putchr
movf TEMP,w
BSF RS ; SELECT DATA REGISTER
CM MOVWF CHR ; STORE CHAR TO DISPLAY
SWAPF CHR,W ; SWAP UPPER AND LOWER NIBBLES (4 BIT MODE)
call PB_dly
MOVF CHR,W ; GET CHAR AGAIN
;**********************************************************
;
; Put 4 bits to LCD & wait (untrimmed)
;
PB_dly ANDLW 0x0F ; MASK OFF UPPER 4 BITS
MOVWF PORTB ; SEND DATA TO DISPLAY
BSF ENA ; ENA HIGH
NOP
BCF ENA ; ENA LOW
; Fall into 200us DELAY subroutine
;**********************************************************
;
; Delay for 200us (untrimmed)
;
; Uses: W, COUNT1
;
;**********************************************************
D200us
DELAY MOVLW 0x42 ; DELAY 200us
MOVWF COUNT1
NXT5 DECFSZ COUNT1,F
GOTO NXT5
RETLW 0
;**********************************************************
;
; Delay for 2ms (untrimmed)
;
; Uses: W, COUNT2, COUNT1
;
;**********************************************************
MS2 MOVLW 0x0A ; DELAY 2ms
MOVWF COUNT2
LP15 call D200us
DECFSZ COUNT2,F
GOTO LP15
RETLW 0
;**********************************************************
;
; Delay for 512ms (untrimmed)
;
; Uses: W, COUNT3, COUNT2, COUNT1
;
;**********************************************************
MS512 clrw ; 0 -> 256 loops
;**********************************************************
;
; Delay for multiples of 2ms (untrimmed)
;
; Uses: W, COUNT3, COUNT2, COUNT1
;
;**********************************************************
MS2xW MOVWF COUNT3
LPx15 call MS2
DECFSZ COUNT3,F
GOTO LPx15
RETLW 0
;******************************************************************
;
; Convert 32-bit binary number at <AccA:4> into a bcd number
; at <bcd:5>. Uses Mike Keitz's procedure for handling bcd
; adjust. Microchip AN526
;
B2_BCD
b2bcd movlw .32 ; 32-bits
movwf COUNT ; make cycle counter
clrf bcd+0 ; clear result area
clrf bcd+1
clrf bcd+2
clrf bcd+3
clrf bcd+4
b2bcd2 movlw bcd ; make pointer
movwf FSR
movlw .5 ; Number of BCD bytes?
movwf cnt ; 2 BCD digits per byte
; Mike's routine:
b2bcd3 movlw 0x33
addwf INDF,f ; add to both nybbles
btfsc INDF,3 ; test if low result > 7
andlw 0xf0 ; low result >7 so take the 3 out
btfsc INDF,7 ; test if high result > 7
andlw 0x0f ; high result > 7 so ok
subwf INDF,f ; any results <= 7, subtract back
incf FSR,f ; point to next
decfsz cnt,f
goto b2bcd3
rlf AccA+3,f ; get another bit
rlf AccA+2,f
rlf AccA+1,f
rlf AccA+0,f
rlf bcd+4,f ; put it into bcd
rlf bcd+3,f
rlf bcd+2,f
rlf bcd+1,f
rlf bcd+0,f
decfsz COUNT,f ; all done?
goto b2bcd2 ; no, loop
return ; yes
;*********** INITIALISE LCD MODULE 4 BIT MODE ***********************
LCDINIT CALL MS512 ; Wait 0.512 sec for LCD RESET
BCF RS ; REGISTER SELECT LOW
BCF ENA ; ENABLE LINE LOW
MOVLW 0x03 ; 1
call PB_dly
CALL MS512 ; WAIT FOR DISPLAY TO CATCH UP
MOVLW 0x03 ; 2
call PB_dly
MOVLW 0x03 ; 3
call PB_dly
MOVLW 0x02 ; Fn set 4 bits
call PB_dly
MOVLW 0x28 ; DISPLAY 2 Line , 5x7 Dot's
CALL STROBE ; Suggested by PA0EJH
CALL DELAY
MOVLW 0x0C ; 0x0C DISPLAY ON
CALL STROBE
CALL DELAY
MOVLW 0x06 ; 0x06 ENTRY MODE SET
CALL STROBE
CALL DELAY
MOVLW 0x01 ; 0x01 CLEAR DISPLAY
CALL STROBE
CALL MS2
RETLW 0
;************ MOVE TO START OF LINE 2 *****************
LINE2 MOVLW 0xC0 ; ADDRESS FOR SECOND LINE OF DISPLAY
CALL STROBE
goto DELAY
;************ CLEAR DISPLAY ***************************
CLEAR MOVLW 0x01 ; COMMAND TO CLEAR DISPLAY
CALL STROBE
goto MS2 ; LONGER DELAY NEEDED WHEN CLEARING DISPLAY
;*********** MOVE TO HOME *****************************
HOME call crlf ; Serial
MOVLW 0x02 ; COMMAND TO HOME LCD DISPLAY
CALL STROBE
goto MS2
;********************************************************************
; Initialise Input & Output devices
;********************************************************************
InitIO bank1
movlw 0x37 ; Option register
movwf OPTION_REG ; Port B weak pull-up enabled
; INTDEG Don't care
; Count RA4/T0CKI
; Count on falling edge
; Prescale Timer/counter
; divide Timer/counter by 256
; PORTA:-
movlw 0x02 ; initialise data direction
; 1 = input, 0 = output
;
; PORTA has 5 pins 4 3 2 1 0
; 0x02 = 0 0 0 0 0 0 1 0
;
movwf TRISA ; PORTA<0> = Serial + Debugging Out
; PORTA<1> = FIXIT (input)
; PORTA<2> = LCD "E" Out
; PORTA<3> = LCD "RS" Out
; PORTA<4> = "Input" with pull-down
; Actually an output.
; PORTA<5:7> = not implemented in 16F84
;
; PORTB:-
movlw 0xf0 ; initialise data direction
; PORTB has 8 pins
; port pin 7 6 5 4 3 2 1 0
; 0xf0 = 1 1 1 1 0 0 0 0
;
movwf TRISB ; PORTB<0> = LCD "DB4"
; PORTB<1> = "DB5"
; PORTB<2> = "DB6"
; PORTB<3> = "DB7"
; PORTB<4> = Input
; PORTB<5> = Input
; PORTB<6> = Input
; PORTB<7> = Input
bank0
return
;**********************************************************
;
; Measure Frequency. Stash in "AccA:4"
;
Measure bcf CLAMP ; CLOSE GATE for safety
bsf PORTB,2 ; For compatibility with
bsf PORTB,3 ; Version 1 hardware
bcf INTCON,T0IF ; Clear any previous overflow
CLRF TMR0 ; RESET INTERNAL COUNT (INCLUDING PRESCALER)
; See page 27 Section 6.0
CLRF AccA+0 ; Ready to receive 32 bit number
CLRF AccA+1
CLRF AccA+2
CLRF AccA+3
bsf CLAMP ; OPEN GATE
CALL MS1000 ; 1.0 sec DELAY
bcf CLAMP ; CLOSE GATE (COUNT COMPLETE)
nop ; and allow time for
nop ; the registers to catch up
nop
nop
nop
call RollOver ; Final check, just in case
MOVF TMR0,W
MOVWF AccA+2
; Now empty the prescaler
PSC1 bank1
bcf OPTION_REG,T0SE ; Clock the prescaler
nop
bsf OPTION_REG,T0SE
bank0
DECF AccA+3,F ; Decrement the counter
movf TMR0,W ; Has TMR0 changed?
xorwf AccA+2,W ; if unchanged, XOR -> 0
beq PSC1
; AccA : AccA+1 : AccA+2 : AccA+3 now holds 32 bit result
; Rollover subroutine has set AccA+0 and AccA+1 suitably.
return
;**********************************************************
;
; Account for TMR0 overflows when counting
; Check at regular intervals and handle as
; necessary.
;
; Needs to be done at less than 936us (@ 70MHz in)
; intervals, or else it can lose counts.
;
RollOver
btfss INTCON,T0IF ; Rolled over?
goto RO3 ; No
RO1 bcf INTCON,T0IF ; Yes. ACK!
INCF AccA+1,f ; Count it
bne RO2 ; Overflowed?
incf AccA+0,f ; No need to check
RO2 return
; Balance path lengths
RO3 nop
nop
goto RO2
;**********************************************************
;
; Display frequency
;
; Display contents of AccA+0...AccA+3 on LCD
; First convert to BCD, Then ASCII (nybble at a time)
;
; In this version, multiply ACCA:4 by 64 since gate
; time = 1.0 second and ext prescale=64
;
Display btfsc PSC ; 1 = prescaler active = *64
call Mul64 ; Account for prescaler
CALL B2_BCD ; CONVERT all AccA TO BCD
; Perform Leading Zero Blanking on first 3 digits
swapf bcd+0,W ; 1000's of MHz
andlw 0x0F ; MASK OFF OTHER PACKED BCD DIGIT
bne NoB1K
MOVLW 0x20 ; YES PRINT A BLANK SPACE
CALL DATS
movf bcd+0,W ; 100's of MHz
andlw 0x0F ; MASK OFF OTHER PACKED BCD DIGIT
bne NoB100
MOVLW 0x20 ; YES PRINT A BLANK SPACE
CALL DATS
swapf bcd+1,W ; 10's of MHz
andlw 0x0F ; MASK OFF OTHER PACKED BCD DIGIT
bne NoB10
MOVLW 0x20 ; YES PRINT A BLANK SPACE
CALL DATS
goto NoB1
; Handle rest of number non blanked
NoB1K SWAPF bcd+0,W ; 1000's of MHz
CALL PutNyb
NoB100 MOVF bcd+0,W ; 100's of MHz
CALL PutNyb
NoB10 SWAPF bcd+1,W ; 10's of MHz
CALL PutNyb
NoB1 MOVF bcd+1,W ; 1's of MHz
CALL PutNyb
MOVLW '.' ; Decimal Point
CALL DATS
SWAPF bcd+2,W ; 100's of KHz
CALL PutNyb
MOVF bcd+2,W ; 10's of KHz
CALL PutNyb
SWAPF bcd+3,W ; 1's of KHz
CALL PutNyb
CALL LINE2
MOVF bcd+3,W ; 100's of Hz
CALL PutNyb
SWAPF bcd+4,W ; 10's of Hz
CALL PutNyb
MOVF bcd+4,W ; 1's of Hz
CALL PutNyb
movlw mhz ; WRITE " Mhz" AT end OF LINE
goto pmsg ; includes RETURN
;********************************************************************
; Read EEPROM into "AccB" (AccB must be visible in both
; W -> memory to read memory banks 0 & 1)
;********************************************************************
EE_RD
#ifdef F628
bank1
#endif
MOVWF EEADR ; Address to read
#ifdef F628
bank0
#endif
XORLW 0x0C ; Special case (no links)
BEQ AVERAGE
CALL EE_R
MOVWF AccB+0
CALL EE_Rinc
MOVWF AccB+1
CALL EE_Rinc
MOVWF AccB+2
CALL EE_Rinc
MOVWF AccB+3
RETURN
;--------------------------------------------------------------------
#ifdef F84
EE_Rinc INCF EEADR,F ; bump address
EE_R bank1
BSF EECON1,RD ; EE Read
bank0
MOVF EEDATA,W ; W = EEDATA
RETURN
#endif
;--------------------------------------------------------------------
#ifdef F628
EE_Rinc bank1
INCF EEADR,F ; bump address
EE_R bank1
BSF EECON1,RD ; EE Read
MOVF EEDATA,W ; W = EEDATA
bank0
RETURN
#endif
;--------------------------------------------------------------------
AVERAGE movlw 0x04 ; AM - use avg BFO freq.
call EE_RD ; Read in one BFO freq
copy AccB,AccA ; Into AccA
movlw 0x08 ; Then second
call EE_RD ; into AccB
call AplusB ; Add 'em
call Div2 ; get average in AccA
copy AccA,AccB ; and in AccB
return
;********************************************************************
; Write EEPROM from "AccB" (AccB must be visible in both
; W -> memory to write memory banks 0 & 1)
;********************************************************************
#ifdef F84
EE_WR MOVWF EEADR ; Address to write
MOVF AccB+0,W ; Data byte #0
CALL EE_W
MOVF AccB+1,W ; Data byte #1
CALL EE_Winc
MOVF AccB+2,W ; Data byte #2
CALL EE_Winc
MOVF AccB+3,W ; Data byte #3
CALL EE_Winc
RETURN
EE_Winc INCF EEADR,F ; bump address
EE_W MOVWF EEDATA
bank1
BSF EECON1,WREN ; Enable Write
MOVLW 0x55 ;
MOVWF EECON2 ; Write 0x55
MOVLW 0xAA ;
MOVWF EECON2 ; Write 0xAA
BSF EECON1,WR ; Set WR bit (begin write)
EE_W2 BTFSC EECON1,WR ; Wait for write to finish
GOTO EE_W2
BCF EECON1,EEIF ; clear interrupts
bank0
RETURN
#endif
;--------------------------------------------------------------------
#ifdef F628
EE_WR bank1
MOVWF EEADR ; Address to write
MOVF AccB+0,W ; Data byte #0
CALL EE_W
MOVF AccB+1,W ; Data byte #1
CALL EE_Winc
MOVF AccB+2,W ; Data byte #2
CALL EE_Winc
MOVF AccB+3,W ; Data byte #3
CALL EE_Winc
bank0
RETURN
errorlevel -302 ; In Bank 2
EE_Winc INCF EEADR,F ; bump address
EE_W MOVWF EEDATA
BSF EECON1,WREN ; Enable Write
MOVLW 0x55 ;
MOVWF EECON2 ; Write 0x55
MOVLW 0xAA ;
MOVWF EECON2 ; Write 0xAA
BSF EECON1,WR ; Set WR bit (begin write)
EE_W2 BTFSC EECON1,WR ; Wait for write to finish
GOTO EE_W2
bank0
BCF PIR1,EEIF ; clear interrupts
bank1
RETURN
errorlevel +302
#endif
;********************************************************************
; Testing counter
;********************************************************************
ctest movlw 0xfe ; MS byte of loop count
movwf COUNT3 ; Counted upward till it overflows
movlw 0x1d
movwf COUNT2
movlw 0xc0
movwf COUNT1
cloop bcf PUFF ; Toggle counter input once
bsf PUFF
incfsz COUNT1,f
goto cloop
incfsz COUNT2,f
goto cloop
incfsz COUNT3,f
goto cloop
return
;***********************************************************************
;
; Debugging Memory & Register dump
;
debug
MOVWF D_Wtemp ; Copy W to temp register,
SWAPF STATUS,W ; Swap status to be saved into W
MOVWF D_Stemp ; Save status to D_Stemp register
movf FSR,W ; Save FSR
movwf D_FSR
movlw 0x57 ; W=
call putchr
movlw 0x3d
call putchr
movf D_Wtemp,w
call hex_2
movlw 0x20 ; 2 spaces, just to be neat
call putchr
movlw 0x20
call putchr
movlw 0x53 ; SR=
call putchr
movlw 0x52
call putchr
movlw 0x3d
call putchr
movf D_Stemp,w
call hex_2
call crlf ; Serial
clrf FSR ; Ready for memory dump
D_loop movf 0,W ; Read indirect
call hex_2
movlw 0x20
call putchr
incf FSR,f ; to next byte
movf FSR,w ; end of line?
andlw 0x0F
bne next_ln
call crlf
bra chk4end
next_ln andlw 0x03 ; Groups of 4
bne chk4end
movlw 0x20
call putchr
chk4end movf FSR,w ; All done?
xorlw 0x80
bne D_loop
call crlf
call crlf
movf D_FSR,W ; Restore FSR
movwf FSR
SWAPF D_Stemp,W ; Swap nibbles in D_Stemp register
; and place result into W
MOVWF STATUS ; Move W into STATUS register
; (sets bank to original state)
SWAPF D_Wtemp,F ; Swap nibbles in D_Wtemp and place result in D_Wtemp
SWAPF D_Wtemp,W ; Swap nibbles in D_Wtemp and place result into W
return
;***********************************************************************
;
; Print CRLF to serial
;
crlf movlw 0x0d ; CRLF
call putchr
movlw 0x0a
goto putchr
;***********************************************************************
;
; Print W as 2 Hex digits
;
hex_2 movwf D_hex
swapf D_hex,w ; Get big bit
call hex_3
movf D_hex,w ; Get little bit
hex_3 andlw 0x0f ; keep bottom 4 bits
addlw 0xF6
bcc hex_4
addlw 0x07 ; binary A -> ASCII A
hex_4 addlw 0x3A ; binary 0 -> ASCII 0
; goto putchr
;********************************************************
;
; Output Routines for PIC16F84
;
; Clock is 4.0 MHz.
; ie. 1.0 us per cycle = 4/Fosc.
;
; 9600 Baud = 104.17 us
; = 104.17 CPU cycles
;
;********************************************************
;
; Output the character in W. Assumes Mac is ready.
;
; Uses W
;
putchr movwf S_Wtemp ; Character being output
movlw 0x08 ; Bit count
movwf S_count
bcf S_out ; Send a 0 - Start bit
put_clp movlw 0xE7 ; Delay "104" cycles
txd_0 addlw 0x01
bne txd_0
rrf S_Wtemp,f ; Transmit a bit
bcs t_0
bcf S_out ; Send a 0
bra tx_1
t_0 bsf S_out ; Send a 1
tx_1 decfsz S_count,f ; Done all bits?
goto put_clp
movlw 0xE7 ; Delay for last data
txd_1 addlw 0x01
bne txd_1
bsf S_out ; Transmit two stop bit
movlw 0xCD
txd_9 addlw 0x01
bne txd_9
return
;********************************************************************
; Tail End Charlie
;********************************************************************
; initialize eeprom locations
ORG 0x2100
DE 0x00, 0x00, 0x00, 0x00 ; Unused (reserved for later)
DE 0x00, 0x00, 0x00, 0x00 ; IF Offset 1 Low BFO ????
DE 0x00, 0x00, 0x00, 0x00 ; IF Offset 2 High BFO ????
DE 0x00, 0x00, 0x00, 0x00 ; IF Offset 3 No BFO -AM-
DE 0xfa, 0xff, 0x5f, 0x00 ; 4.000 MHz initial calibration
END