;******************************************************************* ; ; Morse Frequency Meter; ; Crystal freq. 4.000MHz +/- a bit ; ;******************************************************************* ; ; 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. ; ;******************************************************************* ; ; FM2M.001 Morse output, No LCD, power control ; MFM.001 Renamed to "Morse Frequency Meter" ; MFM.003 Then renumbered yet again ; ;******************************************************************* ; ; MFM.004 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. ; ;******************************************************************* ; ; MFM.005 Moved "Divide by 4", so offsets are stored at 4x ; precision ; ;******************************************************************* ; ; mfm.006 Introduced macros ; Renumbered ; Cleaned up AM IF Offset calculation ; Converted some inline code to subroutines ; Created new 32 bit "copy" macro ; ;******************************************************************* ;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 ; It's a 16F84, HS oscillator, ; watchdog timer off, power-up timer on ; processor 16f84 include __config _HS_OSC & _PWRTE_ON & _WDT_OFF #define S_out PORTA,0x00 ; pin 17 9600 baud serial out #define SOUND PORTA,0x01 ; pin 18 Morse output #define POWER PORTA,0x02 ; pin 1 Power Control #define N_DIGIT PORTA,0x03 ; pin 2 IN. 0 = 3, 1 = 5 digit after DP #define CLAMP PORTA,0x04 ; pin 3 Pull-down the timer input #define WPM0 PORTB,0x00 ; pin 6 WPM LSB #define WPM1 PORTB,0x01 ; pin 7 #define WPM2 PORTB,0x02 ; pin 8 WPM MSB #define NOISY PORTB,0x03 ; pin 9 0 = Morse off. #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: use only registers in bank0 ; bank 0 file registers begin at 0x0c in the 16F84 ; ;******************************************************************* cblock 0x0c 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 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 FLAGS S_Wtemp ; "debug" Variables S_count D_Wtemp D_Stemp D_FSR D_hex speed ; morse speed sp_temp m_spaces ; Number of dot spaces after chr m_temp ; Morse temporary dnddata ; dots'n dashes info dndcount ; count of dots'n dashes endc ;********************************************************** ; ; Begin Executable Stuff(tm) ; org 0 GO clrwdt ; 0 << Reset bcf INTCON,GIE ; No interrupts bcf INTCON,T0IE ; includes timer bcf INTCON,T0IF ; Clear timer interrupt goto START ;********************************************************** ; ; Part of string printer & also ; Look up Morse data from Letter & Number Tables ; m_look pmsub movwf PCL ; Goto W nop ; Just in case nop ; Second may not be needed pm_end return ;**************************************************** ; ; Letter & number table ; First 5 bits: 0=dot, 1=dash ; Last 3 bits: count of morse dots + dashes ; Letter retlw B'01000010' ;A retlw B'10000100' ;B retlw B'10100100' ;C retlw B'10000011' ;D retlw B'00000001' ;E retlw B'00100100' ;F retlw B'11000011' ;G retlw B'00000100' ;H retlw B'00000010' ;I retlw B'01110100' ;J retlw B'10100011' ;K retlw B'01000100' ;L retlw B'11000010' ;M retlw B'10000010' ;N retlw B'11100011' ;O retlw B'01100100' ;P retlw B'11010100' ;Q retlw B'01000011' ;R retlw B'00000011' ;S retlw B'10000001' ;T retlw B'00100011' ;U retlw B'00010100' ;V retlw B'01100011' ;W retlw B'10010100' ;X retlw B'10110100' ;Y retlw B'11000100' ;Z Number retlw B'11111101' ;0 retlw B'01111101' ;1 retlw B'00111101' ;2 retlw B'00011101' ;3 retlw B'00001101' ;4 retlw B'00000101' ;5 retlw B'10000101' ;6 retlw B'11000101' ;7 retlw B'11100101' ;8 retlw B'11110101' ;9 S_Table retlw .123 ; Slow morse retlw .24 ; Wide Spacing retlw .123 retlw .12 retlw .123 retlw .6 retlw .123 retlw .3 ; Normal Spacing retlw .96 retlw .3 retlw .76 retlw .3 retlw .60 retlw .3 retlw .40 ; Fast morse retlw .3 ;********************************************************** ; ; Text Strings (stored in RETLWs) ; mhz dt " MHz ",0 ; Spaces dt " ",0 USB dt "USB",0 LSB dt "LSB",0 Prog dt "PRG",0 Cal dt "CAL",0 ;********************************************************** ; ; Main Program ; START call InitIO ; INITIALISE PORTS movlw 0x01 ; Set RS232, clear morse bsf S_out ; 9600 baud serial out bcf SOUND ; Morse output bsf POWER ; Power Control bcf CLAMP ; Pull-down the timer input ; call setsp ;********************************************************** ; ; Check if in "Calibrate" mode ; btfsc Store ; If grounded initially goto newbit ; then were in "cal" MOVLW 0xfd ; Set initial counter MOVWF Hold+0 ; value MOVLW 0xff ; MOVWF Hold+1 ; for a 4 MHZ XTAL MOVLW 0xbf MOVWF Hold+2 MOVLW 0x00 ; Unused MOVWF Hold+3 GetCal call Measure call Display movlw Cal ; Say "we're calibrating" call pmorse movlw 0x0d ; CR call Morse movlw 0x0a ; LF call Morse ; ; 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.512 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 bsf POWER ; Turn Vcc on movlw 0x10 ; EEADR of Cal value call EE_RD copy AccB,Hold ; Get timing "constant" call setsp 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 pmorse movlw 0x0d ; CR call Morse movlw 0x0a ; LF call Morse btfss Store ; Ready to store it? goto GetIf call MS512 ; Delay 0.512 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 ; ; btfsc AMflag ; Do we print at all? ; goto trySBf ; movlw Spaces ; nuffin = spaces btfss AMflag ; Do we print at all? goto EndM2 trySBf btfsc SBflag,0 ; Which sideband? goto pLSB movlw USB ; USB obviously goto EndMsg pLSB movlw LSB ; LSB ; goto EndMsg EndMsg call pmorse ; Print selected trailer EndM2 movlw 0x0d ; CR call Morse movlw 0x0a ; LF call Morse bcf POWER ; Power Control OFF call MS2 ; for 20ms call MS2 call MS2 call MS2 call MS2 call MS2 call MS2 call MS2 call MS2 call MS2 goto newbit ; Start next measurement ;********************************************************** ; ; Set WPM rate of morse ; setsp rlf PORTB,w ; Set Morse Speed andlw .14 ; Extract speed bits addlw S_Table ; Add to base address call pmsub ; lookup movwf speed ; & save 4 later rlf PORTB,w ; Set Morse Spacing andlw .14 ; Extract spacing bits addlw S_Table ; Add to base address addlw .1 ; Plus 1 call pmsub ; lookup movwf m_spaces ; & save 4 later return ;********************************************************** ; ; 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 ; cos gate = 400ms rrf AccA+1,f rrf AccA+2,f rrf AccA+3,f bcf AccA+0,7 ; Possible bad carry in. return ;********************************************************** ; ; Delay for 400ms (trimmed for actual clock freq) ; Check for Timer register roll over and count 'em ; ; Uses: W, COUUNT1, COUNT2, COUNT3 & others ; ;********************************************************** MS400 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 ;********************************************************** ; ; 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 into a bcd number ; at . 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 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 0x08 ; initialise data direction ; 1 = input, 0 = output ; ; PORTA has 5 pins 4 3 2 1 0 ; 0x08 = 0 0 0 0 1 0 0 0 ; movwf TRISA ; PORTA<0> = Serial out ; PORTA<1> = Morse out ; PORTA<2> = Power control out ; PORTA<3> = N_DIGIT in ; PORTA<4> = "Input" with pull-down ; Actually an output. ; PORTA<5:7> = not implemented in 16F84 ; ; PORTB:- movlw 0xff ; initialise data direction ; PORTB has 8 pins - all are inputs ; port pin 7 6 5 4 3 2 1 0 ; 0xff = 1 1 1 1 1 1 1 1 ; movwf TRISB ; PORTB<0> = Input ; PORTB<1> = Input ; PORTB<2> = Input ; PORTB<3> = Input ; 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 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 MS400 ; 400MS 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 1310 cycle ; 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 present version, ignore 2 most significant BCD digits ; Display call Div4 ; Divide AccA by 4 CALL B2_BCD ; CONVERT all AccA TO BCD MOVF bcd+1,W ; GET FIRST BCD DIGIT. ANDLW 0x0F ; MASK OFF OTHER PACKED BCD DIGIT BTFSS STATUS,Z ; IS IT A '0' ? GOTO NoBlank MOVLW 0x20 ; YES PRINT A BLANK SPACE CALL Morse GOTO NxtDig NoBlank CALL PutNyb NxtDig swapf bcd+2,W ; GET NEXT DIGIT CALL PutNyb ; DISPLAY IT MOVLW '.' ; Obvious! CALL Morse MOVF bcd+2,W ; GET OTHER BCD DIGIT CALL PutNyb SWAPF bcd+3,W ; GET NEXT DIGIT CALL PutNyb ; DISPLAY IT MOVF bcd+3,W ; GET OTHER BCD DIGIT CALL PutNyb btfss N_DIGIT ; if set, do 5 after DP goto do_mhz SWAPF bcd+4,W ; GET NEXT DIGIT CALL PutNyb ; DISPLAY IT MOVF bcd+4,W ; GET OTHER BCD DIGIT CALL PutNyb ; DISPLAY IT do_mhz movlw mhz ; WRITE "Mhz" AT end OF LINE goto pmorse ; includes RETURN PutNyb andlw 0x0F ; MASK OFF OTHER PACKED BCD DIGIT addlw 0x30 ; Convert BIN to ASCII goto Morse ;******************************************************************** ; Read EEPROM into "AccB" ; W -> memory to read ;******************************************************************** EE_RD bank0 MOVWF EEADR ; Address to read 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 EE_Rinc INCF EEADR,F ; bump address EE_R bank1 BSF EECON1,RD ; EE Read bank0 MOVF EEDATA,W ; W = EEDATA RETURN 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" ; W -> memory to write ;******************************************************************** EE_WR bank0 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 ;******************************************************************** ; Morse output routines ; ; Sound String addressed by W ; Note: Strings are in program space ; pmorse movwf EEADR ; Temp for pointer pm1 movf EEADR,W ; Get current pointer call pmsub andlw 0xff ; Test returned value beq pm_end ; NULL = All done call Morse incf EEADR,F goto pm1 ;**************************************************** ; ; Sound character held in W in Morse Code ; Morse movwf m_temp ; Temporary copy of char call putchr btfss NOISY ; R we gunna do morse? return movf m_temp,w ; Recover char addlw .133 bcs other addlw .26 bcs letta addlw .6 bcs other addlw .26 bcs letta addlw .7 bcs other addlw .10 bcs numba other movf m_temp,w ; Recover character xorlw .32 ; Is it a space bne other1 other1 movf m_temp,w ; Recover character xorlw .44 ; Is it a comma bne other2 movlw B'11001100' ; Dots'n dashes in comma movwf dnddata movlw .6 ; Count of dots'n dashes goto sv_cnt other2 movf m_temp,w ; Recover character xorlw .46 ; Is it a full stop bne other3 movlw B'01010100' ; Dots'n dashes in full stop movwf dnddata movlw .6 ; Count of dots'n dashes goto sv_cnt other3 movf m_temp,w ; Recover character xorlw .4 ; Is it a AR (EOT) bne other4 movlw B'01010000' ; Dots'n dashes in AR movwf dnddata movlw .5 ; Count of dots'n dashes goto sv_cnt other4 movf m_temp,w ; Recover character xorlw .32 ; Is it a space bne other5 movf m_spaces,w ; Inter letter gap. movwf COUNT4 s_splp call nodot ; Count off trailing call nodot ; "dot gaps" decfsz COUNT4,f ; Timing is not quite goto s_splp ; right at slow speeds call nodot other5 return ; None of 'em. Ignore char. ;********************************************************** ; ; Look-up entry in table. W holds offset ; letta addlw Letter goto numba1 numba addlw Number numba1 call m_look ; Look-up in table movwf dnddata ; Save dots'n dashes info andlw .7 ; Extract count sv_cnt movwf dndcount ; Save count of dots'n dashes goto soundnd ;**************************************************** ; ; Sound Dots'n dashes ; s_space call nodot ; Inter element gap soundnd rlf dnddata,f ; push element into carry bcc do_dot do_dash call sendot call sendot do_dot call sendot do_cnt decf dndcount,f ; All done? bne s_space movf m_spaces,w ; Inter letter gap. movwf COUNT4 s_s_lp call nodot ; Count off trailing decfsz COUNT4,f ; "dot gaps" goto s_s_lp return ;********************************************************** sendot movf speed,w ; Copy morse speed movwf sp_temp ; into temp counter sd_loop bsf SOUND call D625us bcf SOUND call D625us decfsz sp_temp,f goto sd_loop return ;********************************************************** nodot movf speed,w ; Copy morse speed movwf sp_temp ; into temp counter nd_loop nop call D625us nop call D625us decfsz sp_temp,f goto nd_loop return ;********************************************************** ; ; Delay for 625us ; D625us MOVLW 0xCE ; DELAY 625us MOVWF COUNT1 D625 DECFSZ COUNT1,F GOTO D625 RETLW 0 ;*********************************************************************** ; ; 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? addlw 0xB0 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 0xfd, 0xff, 0xbf, 0x00 ; 4.000 MHz initial calibration END