;***************************************************************************************** ; PSK31 Audio Beacon ; Version 2.0, August 8, 2001 ; George Heron, N2APB ; ; This program generates audio carrier (500 Hz, 1 kHz, or 2 kHz) through R-2R DAC on port B. ; PSK31-modulation occurs at 31.25 baud, reversing the carrier phase whenever a zero is encountered ; in the Varicode bitstream. Carrier power is brought to zero during phase reversals in order to ; provide cleaner spectrum during phase reversals. ; ; The PSK31-modulated baseband audio carrier may be used, with suitable attenuation, to drive the mic ; input of an SSB transmitter, thus generating an RF PSK31 Beacon. Alternatively, the modulated ; audio carrier may be amplified and applied to a speaker to serve as an "audio PSK31 generator" ; for test purposes or fun group activities. (Audio beacon signal may be decoded and displayed by ; DigiPan software running on a Windows-based computer.) ; ; The pre-programmed text string in the SX chip is Varicode-encoded and the SX microcontroller modulates ; a configurable audio carrier frequency at 31.25 baud using BPSK techniques such that the resultant ; audio signal may be decoded by PSK31 demodulation and display software. ; ; For background material, schematic and software theory of operation, reference an article published ; by this author in August 2001 issue of QST. ; ; Test Point TP on pin ra.3 for indication of proper timing: 31ms high, 31ms low ; Use TP to sync oscilloscope while also monitoring the DAC output to view classic PSK31 waveforms ; ; Uses SXKey.exe assembler v1.30 and SX-Key rev E with Ubicom SX28AC/DP device using Murata 50MHz ceramic resonator. ; ; Version History ; v1.3 released 3/10/2001 ... This was the Atlanticon Kit. ; v2.0 released 8/08/2001 ... This version was released with the v2 pc board, after the QST article appeared in Aug 2001. ; (Note: The software for the serial interface option referenced in the QST article is not yet ; operating satisfactorily and is not being released. When available, the RS-232C serial interface ; option provides an ability to deliver a character stream to the Beacon pcb for custom text string ; entry and individual character-by-character encoding/transmission. This software will soon be ; released and all PSK31 Beacon kit owners will be notified with a chip upgrade offer. Check often ; the website of the New Jersey QRP Club for important availability updates, and for helpful ; construction and usage information. The Beacon webpage is at http://www.njqrp.org/psk31beacon.html ; ;***************************************************************************************** ; ; COPYRIGHT 2001 by George L. Heron, N2APB. All rights reserved. ; ; This software may be freely copied and distributed for personal and non-commercial use, ; so long as this author is credited within. ; ;***************************************************************************************** device SX28,oschs3,turbo,stackx_optionx freq 50_000_000 id 'v2.0' reset reset_entry ;***************************************************************************************** ; Global Register definitions org $08 ;start of program registers sync7us ds 1 ;sync flag denoting 7.85 us timing window tabpos ds 1 ;step through table position count ds 1 ;multiplication counter startflag ds 1 ;memory for /START pushbutton iskipcntr ds 1 ;interrupt skip counter (for 7.5 us window creation) cycle_cntr ds 1 ;counts the number of 1 KHz cycles done (0-31) upper_prdt ds 1 ;upper product store for mult8x8 in scale routine sample ds 1 ;sample store in cosine scale routine shftcount ds 1 ;shift counter used in scale routine temp ds 1 ;used in cosine scale routine phase ds 1 ;flag for 1KHz phase (0=POS starting, 1=NEG starting tone) achar ds 1 ;ascii character varicodeLSByte ds 1 ;least significant varicode byte varicodeMSByte ds 1 ;most significant varicode byte scaleflag ds 1 ;scaleflag controls whether we do cosine scaling in SCALE routine currentbit ds 1 ;current bit being output nextbit ds 1 ;next bit to be output buffptr ds 1 ;pointer storage for beaconbuffer string idlecntr ds 1 ;counter for number of idles sent at start of beaconbuffer carrier ds 1 ;3=2KHz, 2=1KHz, 1=500Hz cntr7us ds 1 my_cycle_cntr ds 1 cosine_ptr ds 1 ;pointer for traveling through cosine table RTCCvar ds 1 ;holds the RTCC reload number for interrupt timing ;****************************************************************************************** ; Debugger variable WATCH statements WATCH cycle_cntr,8,uhex WATCH tabpos,8,uhex WATCH iskipcntr,8,uhex WATCH upper_prdt,8,uhex WATCH sample,8,uhex WATCH temp,8,uhex WATCH phase,8,uhex WATCH achar,8,uhex WATCH scaleflag,8,uhex WATCH varicodeMSByte,8,ubin WATCH varicodeLSByte,8,ubin WATCH currentbit,1,ubin WATCH nextbit,1,ubin WATCH idlecntr,8,uhex WATCH RTCCvar,8,uhex ;***************************************************************************************** ; Port Assignment ra_init equ %00000000 ra_io equ %00000000 RB_init equ %00000000 RB_io equ %00000000 rc_init equ %11111111 rc_io equ %11111111 int_period equ 197 ; RTCC interrupt rate: 192 (min) - 197 (nom) - 214 (max) maxidle equ 255 TwoKHz equ 3 ;base carrier frequency = 2 KHz OneKHz equ 2 ;base carrier frequency = 1 KHz FiveHundredHz equ 1 ;base carrier frequency = 500 Hz PTT equ ra.2 ;/PTT line indicates tx in progress sync31ms equ ra.3 ;hardware sync bit for 31ms scope trace START equ rc.7 ;/START pushbutton input bit CONTINUOUS equ rc.6 ;/Continuous looping bit org $0 ;***************************************************************************************** ; Interrupt Service Routine ; ; Interrupt Frequency = (Cycle Frequency / -(retiw value)) ; With a retiw value of -197 and an oscillator frequency of 50MHz, the ; interrupt routine runs every 3.94us. interrupt mov w,m ;Save the m register. mov temp,w clr sync7us ; decsz iskipcntr ;every 2 interrupts, break out to (2 x 3.94us)=7.88us jmp isr_end ;not 7.85 us yet mov sync7us,#$FF ;set flag to indicate start of a 7.88 us timing window mov iskipcntr,#2 ;reset the interrupt-skip counter isr_end mov w,temp ;Restore the m register. mov m,w ; mov w,RTCCvar not w ; mov w,#-int_period ;refresh RTCC on return retiw ;return from the interrupt ; = 1/(int_period*RTCC prescaler*1/50MHz) ; = 1/(197*1*20ns) = 3.94us ;***************************************************************************************** ; INITIALIZATION -- Program execution begins here on power-up or after a reset reset_entry ;mode port config mov w,#$0f mov m,w ;configure port B as output (R-2R DAC) mov w,#RB_init ; Initialize data latches for port B mov rb,w mov w,#RB_io ; Initialize DDIR for port B mov !rb,w ;configure port A as output (sync pulses for scope) mov w,#ra_init ; Initialize data latches for port A mov ra,w mov w,#ra_io ; Initialize DDIR for port A mov !ra,w ;configure port C as input mov w,#$0E ;point to PLP register mov m,w mov w,#$00 ;enable weak pullups mov !rc,w mov w,#$0F ;point to TRIS register mov m,w mov w,#rc_io ; Initialize DDIR for port C mov !rc,w clrb PTT ;put /PTT high at start mov iskipcntr,#2 ;init the interrupt-skip counter call @resetpointers ;sets carrier and my_cycle_cntr based on config switches call @setRTCCvar ;sets the RTCC constant used for interupt timing, based on config switches mov cycle_cntr,my_cycle_cntr mov cosine_ptr,#63 clr phase ;init phase to POS starting 1 KHz waveform clr nextbit clr currentbit clr scaleflag mov idlecntr,#maxidle ;init number of zeros to send at start of beaconbuffer mov buffptr,#beaconbuffer ;init the buffer pointer mov startflag,#$FF ;raise (deactivate) Start flag mov w,#128 ;mid scale for the DAC (an "AC" zero) mov rb,w mov tabpos,#64 ;init the table position ; Setup and enable RTCC interrupt, WREG register mov !option,#%00011111 ;enable rtcc interrupt and wreg jmp @main ;goto mainline on page 1 ;***************************************************************************************** ; MAKE SINE -- output a sample of the sine table. ; Input: pointer TABPOS ; reverse phase when: scaling AND cosine ptr = 31 AND sine ptr = 63 makesine test scaleflag ;are we currently scaling? jz ms2 ;no, continue clr temp ;yes ... clear Z cse cosine_ptr,#31 ;cosine pointer at zero-crossing? (i.e., pntr at 31?) jmp ms2 ;no, continue clr temp ;yes, clear Z cse tabpos,#63 ;sine pointer at start? not phase ;yes, reverse phase one time for following bit cycle ms2 mov w,tabpos ;get pointer for the table lookup test phase ;phase flag indicates a phase reversal needed snz jmp ms3 ;phase = 0, use POS starting table call sinetbN ;phase = 1, use NEG starting table retp ms3 call sinetbP ;get waveform sample from POS starting table retp ;***************************************************************************************** ; sinetbN - a table of sine values - 8 bit entries, centered at 128, table 64 bytes in length ; pointer (W) starts from bottom and works upward ; waveform starts NEGATIVE swing first sinetbN jmp pc+w ;compute the jump value retw 128 ; 0 0 retw 140 ; 1 9.801706E-02 retw 152 ; 2 .1950902 retw 165 ; 3 .2902845 retw 176 ; 4 .3826831 retw 188 ; 5 .4713964 retw 198 ; 6 .5555698 retw 208 ; 7 .6343929 retw 218 ; 8 .7071064 retw 226 ; 9 .77301 retw 234 ; 10 .8314692 retw 240 ; 11 .8819209 retw 245 ; 12 .9238791 retw 250 ; 13 .9569401 retw 253 ; 14 .9807851 retw 254 ; 15 .9951846 retw 255 ; 16 1 retw 254 ; 17 .9951848 retw 253 ; 18 .9807855 retw 250 ; 19 .9569408 retw 245 ; 20 .9238802 retw 240 ; 21 .8819221 retw 234 ; 22 .8314706 retw 226 ; 23 .7730116 retw 218 ; 24 .7071081 retw 208 ; 25 .6343948 retw 198 ; 26 .555572 retw 188 ; 27 .4713986 retw 176 ; 28 .3826855 retw 165 ; 29 .2902869 retw 152 ; 30 .1950926 retw 140 ; 31 9.801959E-02 retw 128 ; 32 2.535182E-06 retw 115 ; 33 -9.801454E-02 retw 103 ; 34 -.1950877 retw 90 ; 35 -.290282 retw 79 ; 36 -.3826808 retw 67 ; 37 -.4713942 retw 57 ; 38 -.5555677 retw 47 ; 39 -.6343909 retw 37 ; 40 -.7071046 retw 29 ; 41 -.7730084 retw 21 ; 42 -.8314677 retw 15 ; 43 -.8819197 retw 10 ; 44 -.9238782 retw 5 ; 45 -.9569393 retw 2 ; 46 -.9807846 retw 1 ; 47 -.9951844 retw 0 ; 48 -1 retw 1 ; 49 -.9951851 retw 2 ; 50 -.980786 retw 5 ; 51 -.9569415 retw 10 ; 52 -.9238811 retw 15 ; 53 -.8819233 retw 21 ; 54 -.831472 retw 29 ; 55 -.7730132 retw 37 ; 56 -.7071099 retw 47 ; 57 -.6343968 retw 57 ; 58 -.5555741 retw 67 ; 59 -.4714009 retw 79 ; 60 -.3826878 retw 90 ; 61 -.2902893 retw 103 ; 62 -.1950951 retw 115 ; 63 -9.802211E-02 ;***************************************************************************************** ; sinetbP - a table of sine values - 8 bit entries, centered at 128, table 64 bytes in length ; pointer (W) starts from bottom and works upward ; waveform starts POSITIVE swing first sinetbP jmp pc+w ;compute the jump value retw 128 ; 0 0 retw 115 ; 63 -9.802211E-02 retw 103 ; 62 -.1950951 retw 90 ; 61 -.2902893 retw 79 ; 60 -.3826878 retw 67 ; 59 -.4714009 retw 57 ; 58 -.5555741 retw 47 ; 57 -.6343968 retw 37 ; 56 -.7071099 retw 29 ; 55 -.7730132 retw 21 ; 54 -.831472 retw 15 ; 53 -.8819233 retw 10 ; 52 -.9238811 retw 5 ; 51 -.9569415 retw 2 ; 50 -.980786 retw 1 ; 49 -.9951851 retw 0 ; 48 -1 retw 1 ; 47 -.9951844 retw 2 ; 46 -.9807846 retw 5 ; 45 -.9569393 retw 10 ; 44 -.9238782 retw 15 ; 43 -.8819197 retw 21 ; 42 -.8314677 retw 29 ; 41 -.7730084 retw 37 ; 40 -.7071046 retw 47 ; 39 -.6343909 retw 57 ; 38 -.5555677 retw 67 ; 37 -.4713942 retw 79 ; 36 -.3826808 retw 90 ; 35 -.290282 retw 103 ; 34 -.1950877 retw 115 ; 33 -9.801454E-02 retw 128 ; 32 2.535182E-06 retw 140 ; 31 9.801959E-02 retw 152 ; 30 .1950926 retw 165 ; 29 .2902869 retw 176 ; 28 .3826855 retw 188 ; 27 .4713986 retw 198 ; 26 .555572 retw 208 ; 25 .6343948 retw 218 ; 24 .7071081 retw 226 ; 23 .7730116 retw 234 ; 22 .8314706 retw 240 ; 21 .8819221 retw 245 ; 20 .9238802 retw 250 ; 19 .9569408 retw 253 ; 18 .9807855 retw 254 ; 17 .9951848 retw 255 ; 16 1 retw 254 ; 15 .9951846 retw 253 ; 14 .9807851 retw 250 ; 13 .9569401 retw 245 ; 12 .9238791 retw 240 ; 11 .8819209 retw 234 ; 10 .8314692 retw 226 ; 9 .77301 retw 218 ; 8 .7071064 retw 208 ; 7 .6343929 retw 198 ; 6 .5555698 retw 188 ; 5 .4713964 retw 176 ; 4 .3826831 retw 165 ; 3 .2902845 retw 152 ; 2 .1950902 retw 140 ; 1 9.801706E-02 ;************************************************************************* ;************************************************************************* ; PAGE 1 ;************************************************************************* ;************************************************************************* org $200 ;page 1 memory ;***************************************************************************************** ; MAINLINE ; ; (1) The programs waits here for the interrupt routine to set SYNC7US flag to indicate the start ; of a 7.85 us processing window. ; ; (2) If CARRIER is set to TwoKHz, ; then another sample of the 64 sample sinewave values is output at 7.88us rate ; (64 x 7.88us = 500us = 2 KHz carrier); or ; If CARRIER is set to OneKHz, ; then every 2nd 7.88us window is skipped and then another sample of the ; 64 sample sinewave values is output at 15.75us rate (64 x 15.75us = 1ms = 1 KHz carrier); or ; If CARRIER is set to FiveHundredHz, ; then every 4th 7.88us window is skipped and then another sample of the ; 64 sample sinewave values is output at 31.25us rate (64 x 31.25us = 2ms = 500 Hz carrier). ; ; (3) When a 31ms window is reached (63, 31 or 15 cycles of the carrier, corresponding ; to 2kHz, 1 KHz, or 500 Hz, respectively), the PSK bit is processed by shifting out the Varicode character bits. ; When a zero bit is encountered phase reversal is performed on the carrier by dropping the power envelope down to ; zero and changing carrier sinewave lookup tables. main test sync7us ;is the ISR is at a 7.85us boundary? jz main ;no, just wait here until it is clr sync7us ;yes, clear the 7us sync flag sb CONTINUOUS ;/CONTINUOUS looping jumper in place? jmp main2 ;yes, bypass the START pushbutton check test startflag ;have we already hit /START pushbutton? snz jmp main2 ;yes, Tx already in progress snb START ;is /START pushbutton actuated (=0) ? jmp main ;no, don't initiate the string transmit clr startflag ;yes, set start flag for memory and start the Tx ;yes, proceed with building the carrier sine wave main2 setb PTT ;activate PTT inc cntr7us ;bump the 7us counter cje cntr7us,#1,loop7us ;7.88us processing for 2 KHz carrier cje cntr7us,#2,loop15us ;15.75us processing for 1 KHz carrier cje cntr7us,#3,main ;there's no processing for 750 Hz carrier jmp loop31us ;31.25us processing for 500 Hz carrier ;get here every 7.88 us ;construct the 2 KHz carrier here if CARRIER = TwoKHz loop7us cjne carrier,#TwoKHz,main ;if carrier not set to TwoKHz, then do nothing jmp outputsample ;else output the sample ;get here every 15.75 us ;construct the 1 KHz carrier here if CARRIER = OneKHz loop15us cjne carrier,#OneKHz,main ;if carrier not set to OneKHz, then do nothing jmp outputsample ;else output the sample ;get here every 31.15us us ;construct the 500 Hz carrier here if CARRIER = FiveHundredHz loop31us cjne carrier,#FiveHundredHz,main ;if carrier not set to FiveHundredHz, then do nothing ;else continue onward to output the sample ;get the sinewave sample and write to port RB outputsample dec tabpos ;"advance" the table pointer up the list call @makesine ;get sample of sine wave call scale ;scale it, if necessary mov rb,w ;send it to the DAC clr cntr7us test tabpos ;done with carrier sinewave? jnz main ;not yet mov tabpos,#64 ;yes, reset table pointer cje carrier,#OneKHz,os2 cje carrier,#FiveHundredHz,os3 os1 dec cosine_ptr ;if doing 2 KHz, advance cosine pointer by 1 jmp os_cont os2 sub cosine_ptr,#2 ;if doing 1 KHz, advance cosine pointer by 2 jmp os_cont os3 sub cosine_ptr,#4 ;if doing 500 Hz, advance cosine pointer by 4 os_cont decsz cycle_cntr ;done with enough carrier cycles for 31ms period? jmp main ;not yet ;yes, we're at mid-bit window, process psk bit ;-------------------------- ;31.25 ms processing window ... Deal with PSK bit processing here at mid-31ms bit position processbit call toggle ;toggles ra.3 for 31.25 ms sync signal for scope call @resetpointers ;update the counters used for determining base carrier freq call @setRTCCvar ;update the RTCC refresh constant (affects interrupt timing) mov cycle_cntr,my_cycle_cntr ;reset the cycle counter mov cosine_ptr,#63 ;done with character? (currentbit = 0 AND nextbit = 0) test currentbit ;currentbit = 0? jnz loop5 ;no, continue clocking out character test nextbit ;yes ... nextbit also zero? jnz loop5 ;no, continue processing character bit sequence ;yes, 2 zero's seen - done with current char ... get another call @getnextchar ;return char in W test w ;idle character? jz loop4 ;yes, make idle codes mov achar,w ;no, turn the ascii char into varicode char call getvaricode ;get varicode bytes into varicodeMSByte, varicodeLSByte jmp loop5 ;and process the data ;make idle codes loop4 clr nextbit ;for idle, clear nextbit clr currentbit ; and current bit jmp loop7 ;and go set scaleflag to force phase reversal ; Process the varicode bit loop5 mov currentbit,nextbit ;"advance" nextbit => current bit, and get new nextbit from character mov nextbit,#$01 rl varicodeLSByte rl varicodeMSByte ;get msb into CY jc loop6 ;CY=1, so continue with nextbit already =1 clr nextbit ;CY=0, so set nextbit = 0 ;check nextbit loop6 test nextbit ;nextbit = 0 or 1? jz loop7 clr scaleflag ;nextbit=1, so keep amplitude at 100%, no phase reversal at next bit time jmp main ;and continue loop7 mov scaleflag,#$01 ;nextbit=0, so do cosine scaling heading toward phase reversal at next bit time jmp main ;***************************************************************************************** ; GET VARICODE -- get the two-byte varicode equivalent of ASCII in reg "achar" ; into registers varicodeUpper and varicodeLower getvaricode clc csb achar,#'@' ;achar in upper half of characterset? jmp getvari2 ;yes, use upper lookup call @vlookupL ;no, use lower lookup ret getvari2 call @vlookupU ;use upper lookup ret ;***************************************************************************************** ; TOGGLE -- toggles the sync bit for 31ms scope signal (ra.3) ; toggle snb sync31ms jmp tog2 setb sync31ms ret tog2 clrb sync31ms ret ;***************************************************************************************** ; Scale -- entry with sample in W. Exit with scaled value in W. scale test scaleflag snz retp ;just return if no scaling desired mov sample,w ;save input ;upper (>128) or lower (<128) half of carrier tone? clc csa sample,#128 ;skip if sample > 128 jmp lower ;sample > 128 clc sub sample,#128 ;get distance above bias (sample - 128) call scaleit ;scale it add sample,#128 ;add back into bias mov w,sample jmp exit ;sample < 128 lower mov temp,#128 clc sub temp,sample ;get distance below bias (128 - sample) mov sample,temp call scaleit ;scale it mov temp,#128 clc sub temp,sample ;put scaled distance below bias again mov w,temp exit retp ;----------------------------------------------------- ; scaleit -- entry in sample, exit in sample ; performs sample x costbl(cosine_ptr) shr<6> scaleit clc ;ensures proper pc+w jump mov w,cosine_ptr call costbl ;get cosine value in W call mult8x8 ;sample x W mov shftcount,#6 ;start shift right by 6 position (/64) s3 rr upper_prdt rr sample decsz shftcount jmp s3 ret ;***************************************************************************************** ; mult8x8 ; 8 bit x 8 bit multiplication ; entry: W x sample ; exit : 2-byte product in upper_prdt, sample mult8x8 mov upper_prdt,w ;store W mov count,#9 ;set number of times to shift mov w,upper_prdt ;restore W (multiplicand) clr upper_prdt ;clear upper product ; the following are executed [count] times m88loop clc ;clear carry rr upper_prdt ;rotate right the whole product rr sample ;check lsb snc ;skip addition if no carry add upper_prdt,w ;add multiplicand to upper product no_add decsz count ;loop 9 times to get proper product jmp m88loop ;jmp to rotate the next half of product ret ;done ;********************************************************************* ; Cosine modulation table ; numbers represent corresponding percentages of 64 (40H) ; "cosine" range goes 1-0-1 (end-middle-start) costbl jmp pc+w ;compute the jump value retw 64 ; 33 .9987956 retw 64 ; 34 .9951849 retw 63 ; 35 .9891767 retw 63 ; 36 .9807856 retw 62 ; 37 .9700316 retw 61 ; 38 .9569408 retw 60 ; 39 .9415446 retw 59 ; 40 .9238802 retw 58 ; 41 .90399 retw 56 ; 42 .8819221 retw 55 ; 43 .8577295 retw 53 ; 44 .8314707 retw 51 ; 45 .8032087 retw 49 ; 46 .7730116 retw 47 ; 47 .7409523 retw 45 ; 48 .7071081 retw 43 ; 49 .6715605 retw 41 ; 50 .6343949 retw 38 ; 51 .5957009 retw 36 ; 52 .555572 retw 33 ; 53 .5141046 retw 30 ; 54 .4713986 retw 27 ; 55 .427557 retw 24 ; 56 .3826855 retw 22 ; 57 .3368921 retw 19 ; 58 .290287 retw 16 ; 59 .2429824 retw 12 ; 60 .1950927 retw 9 ; 61 .1467329 retw 6 ; 62 9.801948E-02 retw 3 ; 63 4.907011E-02 retw 0 ; 64 2.535182E-06 retw 3 ; 1 4.906764E-02 retw 6 ; 2 9.801706E-02 retw 9 ; 3 .1467304 retw 12 ; 4 .1950902 retw 16 ; 5 .24298 retw 19 ; 6 .2902845 retw 22 ; 7 .3368896 retw 24 ; 8 .3826831 retw 27 ; 9 .4275548 retw 30 ; 10 .4713964 retw 33 ; 11 .5141024 retw 36 ; 12 .5555698 retw 38 ; 13 .5956989 retw 41 ; 14 .6343929 retw 43 ; 15 .6715585 retw 45 ; 16 .7071064 retw 47 ; 17 .7409507 retw 49 ; 18 .77301 retw 51 ; 19 .8032071 retw 53 ; 20 .8314693 retw 55 ; 21 .8577282 retw 56 ; 22 .8819208 retw 58 ; 23 .903989 retw 59 ; 24 .9238792 retw 60 ; 25 .9415438 retw 61 ; 26 .9569401 retw 62 ; 27 .970031 retw 63 ; 28 .9807851 retw 63 ; 29 .9891763 retw 64 ; 30 .9951847 retw 64 ; 31 .9987954 retw 64 ; 32 1 ;************************************************************************* ;************************************************************************* ; PAGE 2 ;************************************************************************* ;************************************************************************* org $400 ;page 2 memory ;************************************************************************* ; vlookupLower Varicode Lookup Subroutine. ; Enter with ASCII character (offset) in reg "achar" ; Get two Varicode bytes corresponding to this character ; and place into register "varicodeLower" ; First byte in table is the Upper, second byte is Lower vlookupL clc rl achar ;multiply achar x 2 to form offset mov w,achar call vtableL ;get the MSByte mov varicodeMSByte,w ;store MSByte inc achar ;point to LSByte now mov w,achar call vtableL ;get the LSByte code mov varicodeLSByte,w ;store the LSByte retp ;************************************************************************** ; resetpointers - sets carrier and my_cycle_cntr based on config switches resetpointers mov carrier,rc and carrier,#$30 ;mask all but b5b4 cje carrier,#$30,init2 ;b5b4=11 cje carrier,#$20,init3 ;b5b4=10 cje carrier,#$10,init4 ;b5b4=01 ;b5b4 = 00 = 1 KHz mov carrier,#OneKHz ;init carrier generation to 1 KHz mov my_cycle_cntr,#31 ;init tone cycle counter (0-63, 0-31, or 0-15) jmp init5 ;b5b4 = 01 = 2 KHz init4 mov carrier,#TwoKHz ;init carrier generation to 2 KHz mov my_cycle_cntr,#63 ;init tone cycle counter (0-63, 0-31, or 0-15) jmp init5 ;b5b4 = 10 = 500 Hz init3 mov carrier,#FiveHundredHz ;init carrier generation to 500 Hz mov my_cycle_cntr,#16 ;init tone cycle counter (0-63, 0-31, or 0-15) jmp init5 ;b4b5 = 11 = 1 KHz init2 mov carrier,#OneKHz ;init carrier generation to 1 KHz mov my_cycle_cntr,#31 ;init tone cycle counter (0-63, 0-31, or 0-15) init5 retp ;**************************************************************************** ; setintvar -- get RTCC number (194-209) based on port C b0-3 settings to provide variable interrupt timing setRTCCvar mov w,rc and w,#$0F call RTCCvariable mov RTCCvar,w retp RTCCvariable jmp PC+W retw 194 retw 195 retw 196 retw 197 retw 198 retw 199 retw 200 retw 201 retw 202 retw 203 retw 204 retw 205 retw 206 retw 207 retw 208 retw 209 ;************************************************************************* ; VARICODE LOOKUP TABLE ; ;This table defines the PKS31 varicode. There are 128 entries, ;corresponding to ASCII characters 0-127 with two bytes for each entry. The bits ;for the varicode are to be shifted out MSB-first for both bytes, with the first byte ;in the table for each character being the first one to be sent. ; ;More than one zero in sequence signifies the end of the character (i.e. ;two zeroes are the letter gap. ; ;For modulation, a 0 represents a phase reversal while a 1 represents a steady-state ;carrier. vtableL jmp PC+W retw %10101010 retw %11000000 ; 0 NUL retw %10110110 retw %11000000 ; 1 SOH retw %10111011 retw %01000000 ; 2 STX retw %11011101 retw %11000000 ; 3 ETX retw %10111010 retw %11000000 ; 4 EOT retw %11010111 retw %11000000 ; 5 ENQ retw %10111011 retw %11000000 ; 6 ACK retw %10111111 retw %01000000 ; 7 BEL retw %10111111 retw %11000000 ; 8 BS retw %11101111 retw %00000000 ; 9 HT retw %11101000 retw %00000000 ; 10 LF retw %11011011 retw %11000000 ; 11 VT retw %10110111 retw %01000000 ; 12 FF retw %11111000 retw %00000000 ; 13 CR retw %11011101 retw %01000000 ; 14 SO retw %11101010 retw %11000000 ; 15 SI retw %10111101 retw %11000000 ; 16 DLE retw %10111101 retw %01000000 ; 17 DC1 retw %11101011 retw %01000000 ; 18 DC2 retw %11101011 retw %11000000 ; 19 DC3 retw %11010110 retw %11000000 ; 20 DC4 retw %11011010 retw %11000000 ; 21 NAK retw %11011011 retw %01000000 ; 22 SYN retw %11010101 retw %11000000 ; 23 ETB retw %11011110 retw %11000000 ; 24 CAN retw %11011111 retw %01000000 ; 25 EM retw %11101101 retw %11000000 ; 26 SUB retw %11010101 retw %01000000 ; 27 ESC retw %11010111 retw %01000000 ; 28 FS retw %11101110 retw %11000000 ; 29 GS retw %10111110 retw %11000000 ; 30 RS retw %11011111 retw %11000000 ; 31 US retw %10000000 retw %00000000 ; 32 SP retw %11111111 retw %10000000 ; 33 ! retw %10101111 retw %10000000 ; 34 " retw %11111010 retw %10000000 ; 35 # retw %11101101 retw %10000000 ; 36 $ retw %10110101 retw %01000000 ; 37 % retw %10101110 retw %11000000 ; 38 & retw %10111111 retw %10000000 ; 39 ' retw %11111011 retw %00000000 ; 40 ( retw %11110111 retw %00000000 ; 41 ) retw %10110111 retw %10000000 ; 42 * retw %11101111 retw %10000000 ; 43 + retw %11101010 retw %00000000 ; 44 , retw %11010100 retw %00000000 ; 45 - retw %10101110 retw %00000000 ; 46 . retw %11010111 retw %10000000 ; 47 / retw %10110111 retw %00000000 ; 48 0 retw %10111101 retw %00000000 ; 49 1 retw %11101101 retw %00000000 ; 50 2 retw %11111111 retw %00000000 ; 51 3 retw %10111011 retw %10000000 ; 52 4 retw %10101101 retw %10000000 ; 53 5 retw %10110101 retw %10000000 ; 54 6 retw %11010110 retw %10000000 ; 55 7 retw %11010101 retw %10000000 ; 56 8 retw %11011011 retw %10000000 ; 57 9 retw %11110101 retw %00000000 ; 58 : retw %11011110 retw %10000000 ; 59 ; retw %11110110 retw %10000000 ; 60 < retw %10101010 retw %00000000 ; 61 = retw %11101011 retw %10000000 ; 62 > retw %10101011 retw %11000000 ; 63 ? ;************************************************************************* ;************************************************************************* ; PAGE 3 ;************************************************************************* ;************************************************************************* org $600 ;page 4 memory getnextchar jmp getnextchar_ ;jmp table entry for routine below in this page ;************************************************************************* ; vlookupUpper Varicode Lookup Subroutine. ; Enter with ASCII character (offset) in reg "achar" ; Get two Varicode bytes corresponding to this character ; and place into register "varicodeUpper" ; First byte in table is the Upper, second byte is Lower vlookupU sub achar,#64 ;get actual distance above table start (list midpoint) clc rl achar ;multiply achar x 2 to form offset (2 bytes/varicode) mov w,achar ;now have composite pointer call vtableU ;get the MSByte mov varicodeMSByte,w ;and store it inc achar ;point to next byte in table mov w,achar call vtableU ;get the LSByte mov varicodeLSByte,w ;and store it retp ;************************************************************************* ; VTABLEH -- varicode Table High half ; continuation of the upper half of the varicode table vtableU jmp PC+W retw %10101111 retw %01000000 ; 64 @ retw %11111010 retw %00000000 ; 65 A retw %11101011 retw %00000000 ; 66 B retw %10101101 retw %00000000 ; 67 C retw %10110101 retw %00000000 ; 68 D retw %11101110 retw %00000000 ; 69 E retw %11011011 retw %00000000 ; 70 F retw %11111101 retw %00000000 ; 71 G retw %10101010 retw %10000000 ; 72 H retw %11111110 retw %00000000 ; 73 I retw %11111110 retw %10000000 ; 74 J retw %10111110 retw %10000000 ; 75 K retw %11010111 retw %00000000 ; 76 L retw %10111011 retw %00000000 ; 77 M retw %11011101 retw %00000000 ; 78 N retw %10101011 retw %00000000 ; 79 O retw %11010101 retw %00000000 ; 80 P retw %11101110 retw %10000000 ; 81 Q retw %10101111 retw %00000000 ; 82 R retw %11011110 retw %00000000 ; 83 S retw %11011010 retw %00000000 ; 84 T retw %10101011 retw %10000000 ; 85 U retw %11011010 retw %10000000 ; 86 V retw %10101110 retw %10000000 ; 87 W retw %10111010 retw %10000000 ; 88 X retw %10111101 retw %10000000 ; 89 Y retw %10101011 retw %01000000 ; 90 Z retw %11111011 retw %10000000 ; 91 [ retw %11110111 retw %10000000 ; 92 \ retw %11111101 retw %10000000 ; 93 ] retw %10101111 retw %11000000 ; 94 ^ retw %10110110 retw %10000000 ; 95 _ retw %10110111 retw %11000000 ; 96 ` retw %10110000 retw %00000000 ; 97 a retw %10111110 retw %00000000 ; 98 b retw %10111100 retw %00000000 ; 99 c retw %10110100 retw %00000000 ; 100 d retw %11000000 retw %00000000 ; 101 e retw %11110100 retw %00000000 ; 102 f retw %10110110 retw %00000000 ; 103 g retw %10101100 retw %00000000 ; 104 h retw %11010000 retw %00000000 ; 105 i retw %11110101 retw %10000000 ; 106 j retw %10111111 retw %00000000 ; 107 k retw %11011000 retw %00000000 ; 108 l retw %11101100 retw %00000000 ; 109 m retw %11110000 retw %00000000 ; 110 n retw %11100000 retw %00000000 ; 111 o retw %11111100 retw %00000000 ; 112 p retw %11011111 retw %10000000 ; 113 q retw %10101000 retw %00000000 ; 114 r retw %10111000 retw %00000000 ; 115 s retw %10100000 retw %00000000 ; 116 t retw %11011100 retw %00000000 ; 117 u retw %11110110 retw %00000000 ; 118 v retw %11010110 retw %00000000 ; 119 w retw %11011111 retw %00000000 ; 120 x retw %10111010 retw %00000000 ; 121 y retw %11101010 retw %10000000 ; 122 z retw %10101101 retw %11000000 ; 123 { retw %11011101 retw %10000000 ; 124 | retw %10101101 retw %01000000 ; 125 } retw %10110101 retw %11000000 ; 126 ~ retw %11101101 retw %01000000 ; 127 (del) ;******************************************************************************* ; Get Next Char -- returns next character from beaconbuffer in W getnextchar_ test idlecntr jz gnc2 ;if zero, all done with pre-idle dec idlecntr ;else, decrement and clr w ; return with W=0 retp gnc2 mov w,buffptr ;point lower 8 bits of indirect address to buffer mov m,#6 ;point upper 4 bits of indirect addr to page iread ;read a char from the buffer into M:W mov m,#$0F ;reset the mode register test w ;at end of buffer? jz gnc3 ;yes, need to reset pointer inc buffptr ;else, increment pointer and retp ; return with char in W ;end of buffer -- reset pointers and exit with Z=1 gnc3 mov buffptr,#beaconbuffer ;reset the beaconpuffer pointer mov idlecntr,#maxidle ;reset the idlecounter clrb PTT ;deactivate PTT line mov startflag,#$FF ;deactivate /START pushbutton memory clr w ;w=0 ends text string & starts idle stream retp beaconbuffer DW 'PSK31 Beacon de N3AO/B code 4343',$0A,$0D,0 END