TITLE "Direct Frequency Entry Keypad - Yaesu CAT" ; Written by Lee de Vries VK3PK April 2001 ; Based on an earlier Keypad for ICOM rigs using 68705K1 written by me. ; The serial routine was borrowed , modified a little & retimed for 4 Mhz. ; Modified to use computed goto's, modification debugged & tested 22/8/2001 ; Bugs found ;1. In digital modes, the keypad will not resend same freq again. ; Output went low on send port on last send. ; Bypassed temporarily by patching out the DIG mode & substituting CW ; Note that Yaesu's instructions for repeater offset is incorrect ; Some of the timing delays between commands could be tidied up a little. ; A jump table has been set up to provide for additional commands ; a=dp/reset, b=send, c=up, d=down, e & f unallocated ; ; I must modify this code someday, to handle both Yaesu CAT & ICOM CIV & add DTMF output ; ; ; ________ ________ ; 1=CAT, 0=CIV >> RA2 |1 U 18| RA1 <> ; 1=735, 0=OTHER >> RA3 |2 17| RA0 >> TXOUT ; DTMF OUT < RB0/INT |6 13| RB7 <> R3 keypad (4) ; columns C2 (3) <> RB1 |7 12| RB6 <> R2 rows (9) ; C2 (5) <> RB2 |8 11| RB5 <> R1 (8) ; C3 <> RB3 |9______________10| RB4 <> R0 (6) ; ; keypad details in brackets refer to the tag numbers on "my" keypad LIST P=PIC16F84 include "P16F84.INC" __CONFIG _HS_OSC & _CP_OFF & _PWRTE_ON & _WDT_OFF radix hex errorlevel -302 ; suppress Message 302 (Register in operand not in bank 0.) #define _txout PORTA,0 #define _rxin PORTA,1 #define _RADIO PORTA,2 #define _735 PORTA,3 #define _AUTOMODE PORTA,4 #define _FREQVALID flags,0 ; Modes #define LSB 0 #define USB 1 #define CW 2 #define CWR 3 #define AM 4 #define FM 8 #define DIG 0A #define PKT 0C ; 0b also seems to work OK ; caution other codes seem to lock up ; dont fiddle with the following bits, they have been carefully allocated ; b0-b3 are yaesu mode bits #define FMS b'10011000' ; b4=1 FM MODE b4=0 non-FM mode #define FMNeg b'00011000' ; b6=0 is -ve shift b6=1 is +ve shift #define FMPos b'01011000' ; b7=1 SIMPLEX b7=0 repeater ; FM mode flags defined #define FMMODE 4 #define SIMPLEX 7 ;following are used for testing ;use the following defines & macros to allow for easy relocation of leds ;don'd forget to set up the tris regs! #define ledport PORTA #define red 4 #define yellow 3 #define green 2 ledon macro color ; expanded with ledon red etc. bcf ledport,color endm ledoff macro color ;expanded with ledoff red etc. bsf ledport,color endm #define _RBPU OPTION_REG,NOT_RBPU ; weak pull up enable #define _RBINT INTCON,RBIE ; RB<4.7> interupt #define _RBINTFL INTCON,RBIF ; RB<4.7> interupt flag #define _GLINTE INTCON,GIE ; Global Interupt enable cblock 0x0c ;The first four ram variables must remain in this order. byte1 ;10 &100 Mhz. byte2 ;100 & 1000 kHz. byte3 ;1 & 10 kHz. byte4 ;10 & 100 Hz. mode ;mode to be sent to yaesu ( no FM bits) newmode ;mode out of mode table ( includes FM flags) khzcnt ;this keeps track of the number of khz digits still required newkey ;new_key detected serbuffer ;serial input/output buffer count ;keep track of no of bits sent temp ;carefull with following three bytes temp1 ;they have multiple uses temp2 ; Num_1 ; Overflow flow carry overwrites Num_1 Num_2 ; Num_2 + Num_1 overwrites Num_2 ptr ;pointer to data tables flags ;use a flag where a flag will do ; 0 freqvalid ; 1 up/down size 0=100 Hz. 1=1Khz state ;key entry state ( this will obviate flags i think) ; state 0 waiting for first key press ; state 1 building Mhz ; state 2 building khz endc result equ Num_1 O_flow equ Num_2 ;***************************************************************************** ; ; HERE ON RESET ; ;***************************************************************************** ORG 0 ; start code goto startup ;***************************************************************************** ; ; HERE TO HANDLE INTERUPT (NOTE THAT THE UNUSUAL EXIT!) ; ;***************************************************************************** ORG 4 ; interupt code bcf _RBINTFL ; reset the RB interupt flag return ; return from interupt WITHOUT restoring GIE bit goto interupt ;***************************************************************************** ; ; HERE TO LOOKUP REPEATER OFFSETS ; ;***************************************************************************** ;Only one set of bytes required if we don't allow shifts of 10 Mhz. or greater. ;Note that the Yaesu documentation is incorrect for the format of the offset byte offset addwf PCL,f retlw 02 ; 10 m. retlw 01 ; 0.1 Mhz retlw 05 ; 6 m retlw 10 ; 1.0 Mhz retlw 14 ; 2 m retlw 06 ; 0.6 Mhz. retlw 43 ; 70 cm. retlw 50 ; 5.0 Mhz. ;***************************************************************************** ; ; HERE TO LOOKUP KEYPAD VALUES (ALLOWS KEYMAPPING); ; ;***************************************************************************** keytbl addwf PCL,f ;jump to table & return with data in W retlw 01 ;key 1 retlw 04 ;key 4 retlw 07 ;key 7 retlw 0a ;key * decimal point retlw 02 ;key 2 retlw 05 ;key 5 retlw 08 ;key 8 retlw 00 ;key 0 retlw 03 ;key 3 retlw 06 ;key 6 retlw 09 ;key 9 retlw 0b ;key # send retlw 0c ;key c freq up retlw 0d ;key d freq down retlw 0e ;key e slow/fast toggle retlw 0f ;key f freq/dtmf toggle ;***************************************************************************** ; ; HERE ON STARTUP ; ;***************************************************************************** startup movlw B'00000001' ; set tx data high movwf PORTA ; bsf STATUS,RP0 ; select Bank 1 movlw b'00011110' ; make txout & rxin movwf trisa bcf _RBPU ; allow weak pull ups on Port B (default) bcf STATUS,RP0 ; de-select Bank 1 bsf _RBINT ; allow RB4-7 to cause interupt call erase ; clear state & valid frequency flag ;***************************************************************************** ; ; HERE TO GET A KEY PRESS & EXECUTE A TASK ; ;***************************************************************************** main call getkey ; enter here for possible re-sending call keytask ; do the required key task goto main ; repeat again keytask addwf PCL,f ;jump to table & return with data in W goto store ;key 0 goto store ;key 1 goto store ;key 2 goto store ;key 3 goto store ;key 4 goto store ;key 5 goto store ;key 6 goto store ;key 7 goto store ;key 8 goto store ;key 9 goto decpoint ;key a (*) pressed, this key and the following are actions goto send ;key b (#) pressed goto up ;key c step up goto down ;key d step down goto slow_fast ;key e change step size 10 Hz. 100 Khz goto unassigned ;key f not implemented ;***************************************************************************** ; ; RECEIVED A DIGIT ; ;***************************************************************************** store movf state,w addwf PCL,f goto sdfmhz ;waiting for first key press thereforw it is first Mhz. digit goto sdmhz ;entering subsequent Mhz. digits goto sdkhz ;entering khz. digits sdfmhz call erase ; clear last frequency out movlw 0x01 movwf state sdmhz bsf _FREQVALID ; indicate something is stored swapf byte1,w ; move lsn of byte1 to andlw 0xf0 ; & clear lsb of byte 1 movwf byte1 ; msn of byte1 swapf byte2,w ; move msn of byte2 iorwf byte1,f ; lsn of byte1 bildmh2 swapf newkey,w ; move latest into msn of byte2 movwf byte2 return sdkhz bsf _FREQVALID ; indicate something is stored movf newkey,w ; restore digit movf khzcnt,f ; test whether we should throw away >5 btfsc STATUS,Z ; return ; no more digits to be stored wait for dp or send decf khzcnt,f ; adjustment khzstored count btfsc khzcnt,0 ; & test least significant bit goto sthinyb ; do next khz byte movf newkey,w ; store low nybble iorwf INDF,f ; combine with what is stored incf FSR,f return ; get next digit sthinyb swapf newkey,w ; get it into the msn movwf INDF ; store in buffer return ; get next digit ;***************************************************************************** ; ; RECEIVED A DECIMAL POINT ; ;***************************************************************************** decpoint movf state,w addwf PCL,f goto dpwaitfkp ; waiting for first key press therfore no leading Mhz goto dpbuildmhz goto dpbuildkhz dpwaitfkp ; this is a no leading Mhz. entry call erase ; erase buffer movlw 0x02 movwf state ; new frequency starting with dp return dpbuildkhz ; this is a reset call erase ; dont allow a resend of anything that may have been entered return dpbuildmhz ;This is a dp after some Mhz. have been entered movlw 0x02 movwf state ; new frequency starting with dp unassigned ;should never get here return ;************************************************* ; ; RECEIVED A SEND ; ;************************************************* send btfss _FREQVALID goto nosend ; dont do or send anything if frequency not valid call getmode call sendmode ; best to send mode before frequency to avoid small frequency shifts call sendfreq btfss newmode,FMMODE ; check the FM mode bit goto nosend ; not FM ; come here only for FM modes call sendshift ; have to set or clear shift if FM btfsc newmode,SIMPLEX ; check the repeater flag goto nosend ; not a repeater, no offset required call sendoffset nosend clrf state ; back to receiving a first keypress on return return sendmode ;send the mode movf mode,w ; call serout ; and send it call txdummy ; neater to send some 0's call txdummy call txdummy movlw 7 ; set mode command call serout call delay ;50ms. return round movlw 0xf0 ;clear 10 Hz. btfsc flags,1 movlw 0x00 ;clear 100 Hz. andwf byte4,f return ; The following two are not implementd up call round; adjust the freq up ; put increment code here goto sendfreq down call round; adjust the freq down ; send frequency ;put decrement code here sendfreq movf byte1,w call serout movf byte2,w call serout movf byte3,w call serout movf byte4,w call serout movlw 1 ;set frequency command call serout call delay ; 50 ms. call delay ; seemed to be unreliable at 50 return ; FMS b'00011000' ; b4=1 FM MODE Yaesu code 89 ; FMNeg b'01111000' ; b5=1 REPEATER Yaesu code 49 ; FMPos b'10111000' ; b7=0 is -ve shift b7=1 is +ve shift Yaesu code 09 sendshift movlw b'11000000' ; converts data to suitable format andwf newmode,w ; strip of the REPEATER & FMMODE bits & mode addlw b'00001001' ; converts lower nibble to 9 call serout call txdummy ; neater to send some 0's call txdummy call txdummy movlw 9 ; set repeater shift command call serout call delay ; 50 ms. noshift return sendoffset ; if it was a repeater, check repeater offset & send it ; to get offset size in here if required ; we need to consider only 10 mx, 6 mx, 2 mx & 70 cm. ; -100khz, +1 Mhz. +/- 600, -5Mhz ; we can discriminate on the first freq byte btfsc newmode,7 ;no need to do this if shift not on goto nooffset movlw 0 nextoffset movwf ptr call offset subwf byte1,w btfsc STATUS,Z goto gotoffset movf ptr,w addlw 2 goto nextoffset gotoffset call txdummy ;dont allow offset >=10 Mhz. incf ptr,w call offset call serout call txdummy call txdummy movlw 0xf9 ;set repeater offset command call serout nooffset return ;Leave buffer intact for re-sending getmode ;determine the mode movlw 0x03 ; set to new page movwf PCLATH movlw -4 ; initialize matching code for whole spectrum movwf ptr movlw (endtable-begtable)/4 ;number of limits to check movwf temp match1 movlw 4 ;initialize matching next four bytes addwf ptr,f movlw byte1-1 ; initialize pointer to Mhz X 100 movwf FSR ; to RAM clrf temp1 match2 incf FSR,f movf ptr,w addwf temp1,w call flimits ;get byte from table movwf temp2 movf INDF,w subwf temp2,w ; f-w > w check to see if it is lower btfss STATUS,C ; can get out as soon as it is goto higher ; new frequency is higher ;here for lower or same btfss STATUS,Z ; goto lower ;here for same incf temp1,f movlw 3 subwf temp1,w ; subtract w from f btfss STATUS,Z goto match2 ;search up to three bytes higher decfsz temp,f ;search whole table goto match1 lower movf ptr,w addlw 3 call flimits ;get mode movwf newmode movlw 0f andwf newmode,w movwf mode ; update mode clrf PCLATH ; reset to default area for lookup tables return slow_fast movlw 0x02 xorwf flags,1 ;toggle fast slow bit return dtmf ;toggle freq/dtmf mode ;************************************************* ; ; HERE TO CLEAR & INITIALIZE VARIABLES ; ;************************************************* erase clrf byte1 clrf byte2 clrf byte3 clrf byte4 clrf state movlw byte2 ; initialize pointer to where khz needs to be stored movwf FSR ; to RAM movlw 5 ; store count maximum hhz. digits movwf khzcnt bcf _FREQVALID ; only send freq if = 1 return ;************************************************* ; This routine scans the 4x4 hex key pad for a key press. ; On entry it checks for a previous key press to be released ; & waits until it is released ; When the key is pressed the hex key value is returned in ; reg new_key & W reg ; If no key is detected, it waits until one occurs. ; This is rough & ready and can no doubt be refined ;************************************************* getkey movlw b'00000000' ;make RB0-4 outputs & make them low movwf portb ;make Rb4-7 inputs movlw b'11110000' ; bsf STATUS,RP0 ; Select Bank 1 movwf trisb ; bcf STATUS,RP0 ; Select Bank 0 gk0 movlw 10 movwf temp gk1 movf PORTB,w ;input port value xorlw b'11110000' ; btfss STATUS,Z ;no key then skip goto gk0 ;wait for a key release & reset debounce decf temp,f btfss STATUS,Z goto gk1 ; decrement debounce backtosleep bsf _GLINTE ; allow global iterupt sleep ; put system to sleep here movf PORTB,w ;input port value xorlw b'11110000' ;this effectivily inverts the data btfsc STATUS,Z ;wake up but still no key goto backtosleep ;do it all over again ; I have a key press now movwf temp ;store the column value swapf temp,f movlw 0 ;make RB4-7 outputs & make them low movwf portb ;make RB0-3 inputs bsf STATUS,RP0 ; Select Bank 1 movlw b'00001111' ; movwf trisb bcf STATUS,RP0 ; Select Bank 0 clrf newkey movlw 1 nextr rrf temp,f btfsc STATUS,C ;the bits in temp are inverted goto foundr ;break out if carry clear, row found addwf newkey,f goto nextr foundr movf PORTB,w ;input port value ;not sure whether it is worth doing following test ; andlw b'00001111' ; btfsc STATUS,Z ;no key then skip ; goto getkey ;do it all over again xorlw b'00001111' ;this effectivily inverts the data movwf temp ;store the row value movlw 4 nextc rrf temp,f btfsc STATUS,C ;the bits in temp are inverted goto foundc ;break out if carry clear, column found addwf newkey,f goto nextc foundc movf newkey,w call keytbl ;convert to a number 0-f movwf newkey return ; approx 50 ms. delay delay movlw 0 ;Minimum delay for CAT to work reliably movwf temp1 delay1 movlw 0 movwf temp2 delay2 decfsz temp2,f goto delay2 decfsz temp1,f goto delay1 return ;**************************************************************************** ; ; serial output routine ; 9600 bps with a 4.0 MHz crystal. ; ;****************************************************************************** txdummy movlw 0 serout movwf serbuffer ; save byte to transmit movlw d'12' ; send three stop bits for YAESU CAT (else 10) movwf count ; start counter w/10 bits start tx_ing w/start bit lo in carry clrc ; start bit = 0 goto serout2 ; skip the rrf txloop rrf serbuffer,f ; 1 ~ bit0 -> carry =1 moved into b7( see ** below) & b0 moved to carry serout2 skpnc ; 1/2 ~ tx bit "0" ? 1 for "0" or 2 for "1" goto txone ; 2~ no, skip ("1") setc ; 1 ~ set carry to make sure stop bits are set ** & waste 1t [93t] bcf _txout ; 1 ~ send 0 nop ; 1 ~ pad out the shorter duration part of the algorithm nop ; 1 ~ serout3 movlw d'31' ; 1 ~ , load for 9600 match at for 4 mhz movwf temp ; 1 ~ used as a scratch counter serout4 decfsz temp,f ; 1/2 ~ goto serout4 ; 2 ~ decfsz count,f ; 1/2 ~ tx all 10 bits ? 11 bits now I hope goto txloop ; 2~ no, back return ; not in loop txone bsf _txout ; 1 ~ send 1 goto serout3 ; 2 ~ back ; ;******************************************************************** ; Test Program ;********************************************************************* ; movlw 99 ; movwf Num_1 ; Set Num_1 = 99 ( max BCD digit ) ; movlw 99 ; movwf Num_2 ; Set Num_2 = 99 ; ; call BCDAdd ; After addition, Num_2 = 98 ; ; and Num_1 = 01 ( 99+99 = 198 -> max number ) BCDAdd movf Num_1,W addwf Num_2, F ; do binary addition clrf Num_1 rlf Num_1, F btfsc STATUS,DC ; Is DC = 0 ? goto adjust ; adjust LSD movlw 6 addwf Num_2, F ; Test for LSD > 9 ( by adding 6 btfsc STATUS,C incf Num_1, F btfss STATUS,DC ; & checking Digit Carry subwf Num_2, F ; LSD < 9 , so get back original value. goto over1 adjust movlw 6 addwf Num_2, F over1 movlw 60 ; add 6 to MSD addwf Num_2, F btfsc STATUS,C goto over3 btfss Num_1,0 subwf Num_2, F RETLW 0 over3 movlw 1 movwf Num_1 RETLW 0 ;******************************************************************** ; Test Program ;********************************************************************* ; movlw 23 ; movwf Num_1 ; Set Num_1 = 23 ; movlw 99 ; movwf Num_2 ; Set Num_2 = 99 ; call BCDSub ; After subtraction, Num_2 = 76 ( 99-23 ) ; ; and Num_1 = 0 ( indicates positive result ) ; ; movlw 99 ; movwf Num_1 ; Set Num_1 = 99 ; movlw 0 ; movwf Num_2 ; Set Num_2 = 0 ; ; call BCDSub ; After subtraction, Num_2 = 1 ; ; and Num_1 = 1 ( indicates negative result ) ; ; -1 <- ( -99 ) BCDSub movf Num_1,W subwf Num_2, F clrf Num_1 rlf Num_1, F btfss STATUS,DC goto adjst1 btfss Num_2,3 ; Adjust LSD of Result goto Over_1 btfsc Num_2,2 goto adjst1 ; Adjust LSD of Result btfss Num_2,1 goto Over_1 ; No : Go for MSD adjst1 movlw 6 subwf Num_2, F Over_1 btfss Num_1,0 ; CY = 0 ? goto adjst2 ; Yes, adjust MSD of result clrf Num_1 btfss Num_2,7 ; No, test for MSD >9 RETLW 0 btfsc Num_2,6 goto adjst2 btfss Num_2,5 RETLW 0 adjst2 movlw 60 ; add 6 to MSD subwf Num_2, F clrf Num_1 btfss STATUS,C ; test if underflow RETLW 0 movlw 1 movwf Num_1 Over RETLW 0 ;***************************************************************************** ; ; HERE TO LOOKUP MODES ACCORDING TO GENERALLY ACCEPTED BAND PLAN ; ;***************************************************************************** ; Band plan - edit to your requirements ; Format bytes 1,2 & 3 specifies a frequency ; byte 3 specifies the mode that should be used BELOW that frequencies ; We store a maximum of 64 band segments org 0x2ff ;placed here to allow largest number of band segments flimits addwf PCL,f begtable retlw 00 ;this table must start in a new page retlw 18 retlw 00 retlw AM ;AM Mode which should be used on frequencies below 1.8 Mhz. etc retlw 00 retlw 18 retlw 25 retlw CW retlw 00 retlw 18 retlw 80 retlw LSB ; LSB or AM retlw 00 retlw 35 retlw 00 retlw AM retlw 00 retlw 35 retlw 40 retlw CW retlw 00 retlw 38 retlw 00 retlw LSB retlw 00 retlw 70 retlw 00 retlw AM retlw 00 retlw 70 retlw 40 retlw CW retlw 00 retlw 73 retlw 00 retlw LSB retlw 01 retlw 01 retlw 00 retlw AM retlw 01 retlw 01 retlw 40 retlw USB retlw 01 retlw 01 retlw 50 retlw DIG retlw 01 retlw 40 retlw 00 retlw AM retlw 01 retlw 40 retlw 70 retlw CW retlw 01 retlw 41 retlw 12 retlw DIG retlw 01 retlw 43 retlw 50 retlw USB retlw 01 retlw 80 retlw 68 retlw AM retlw 01 retlw 81 retlw 00 retlw CW retlw 01 retlw 81 retlw 10 retlw DIG retlw 01 retlw 81 retlw 68 retlw USB retlw 02 retlw 10 retlw 00 retlw AM retlw 02 retlw 10 retlw 70 retlw CW retlw 02 retlw 11 retlw 25 retlw DIG retlw 02 retlw 14 retlw 50 retlw USB retlw 02 retlw 48 retlw 90 retlw AM retlw 02 retlw 49 retlw 20 retlw CW retlw 02 retlw 49 retlw 30 retlw DIG retlw 02 retlw 49 retlw 90 retlw USB retlw 02 retlw 80 retlw 00 retlw AM retlw 02 retlw 80 retlw 00 retlw AM retlw 02 retlw 81 retlw 90 retlw CW retlw 02 retlw 95 retlw 10 retlw USB retlw 02 retlw 96 retlw 20 retlw FMS retlw 02 retlw 96 retlw 80 retlw FMNeg retlw 05 retlw 00 retlw 00 retlw FMS retlw 05 retlw 01 retlw 00 retlw CW retlw 05 retlw 25 retlw 00 retlw USB retlw 05 retlw 25 retlw 50 retlw FMS retlw 05 retlw 30 retlw 00 retlw FMPos retlw 08 retlw 80 retlw 00 retlw FMS ; I dont know what the WFM code is but, the FT817 defaults to WFM ; and cannot be put in modes other then WFM anyway. retlw 10 retlw 80 retlw 00 retlw FMS retlw 13 retlw 60 retlw 00 retlw AM retlw 14 retlw 40 retlw 00 retlw FMS retlw 14 retlw 41 retlw 00 retlw CW retlw 14 retlw 46 retlw 00 retlw USB retlw 14 retlw 66 retlw 25 retlw FMS retlw 14 retlw 70 retlw 25 retlw FMNeg retlw 14 retlw 74 retlw 00 retlw FMPos retlw 14 retlw 76 retlw 00 retlw FMS retlw 43 retlw 20 retlw 00 retlw FMS retlw 43 retlw 21 retlw 00 retlw CW retlw 43 retlw 24 retlw 00 retlw USB retlw 43 retlw 80 retlw 00 retlw FMS retlw 43 retlw 87 retlw 50 retlw FMNeg retlw 43 retlw 92 retlw 75 retlw FMS retlw 44 retlw 00 retlw 00 retlw FMNeg retlw 46 retlw 99 retlw 00 retlw FMS ;undefined & strange modes - may work better now ?? #define X3 3 ; 469.990 CWR #define X5 5 ; 469.991 This locks up the FT817 (disconnect battery to reset) #define X6 6 ; 469.992 as above #define X7 7 ; 469.993 as above #define X9 9 ; 469.994 as above #define XB 0B ; 469.995 PACKET #define XC 0C ; 469.996 PACKET retlw 46 retlw 99 retlw 10 retlw X3 ;cwr retlw 46 retlw 99 retlw 20 retlw X5 ;lockup retlw 46 retlw 99 retlw 30 retlw X6 ;shut down after 10 secs, have to remobe batteries to reset retlw 46 retlw 99 retlw 40 retlw X7 ;shut down after 10 secs, have to remobe batteries to reset retlw 46 retlw 99 retlw 50 retlw X9 ;shut down as above retlw 46 retlw 99 retlw 60 retlw XB ;packet retlw 46 retlw 99 retlw 70 retlw XC ;packet ; retlw 99 ; leave this at the end for mopping up ; retlw 99 ; retlw 99 ; retlw FMS endtable ;leave this label here end