;Cross Country Wireless CW Iambic Memory Keyer ver 2.27 ;Chris Moulding, G4HYG 3 December 2009 LIST P=16F88, n=.61, c=.78 errorlevel 0,-302, -305 #INCLUDE "p16F88.inc" __CONFIG _CONFIG1, _CPD_OFF & _CP_ALL & _DEBUG_OFF & _LVP_OFF & _MCLR_OFF & _PWRTE_ON & _WDT_OFF & _WRT_PROTECT_ALL & _INTRC_IO & _BODEN_OFF ; ;Register definitions PCL equ 0x02 ;PCL register STATUS equ 0x03 ;STATUS register RP0 equ 0x5 ;Bank switch bit CARRY equ 0x0 ;C bit EEDATA equ 0x10C ;EEPROM data address EEADR equ 0x10D ;EEPROM register address EECON1 equ 0x18C ;EEPROM data address EECON2 equ 0x18D ;EEPROM register address RD equ 0x0 ;EEPROM read bit WR equ 0x1 ;EEPROM write bit WREN equ 0x2 ;EEPROM write enable bit ;PortB pin mapping #define SPKR_ PORTA,2 #define RX_MUTE PORTA,3 #define PTT PORTB,0 #define SPKR PORTB,1 #define KEYOUT PORTB,2 #define CMDIN PORTB,3 #define DITIN PORTB,4 #define DAHIN PORTB,5 #define MEM1 PORTB,6 #define MEM2 PORTB,7 ; Register Usage CBLOCK 0x20 ; Start Registers at End of the Values CNT1 CNT2 DLYREG DITREG DAHREG PFLAGS0 ENDC ;==================================================================== #define DIT_FLAG PFLAGS0,0 ;dit flag for iambic routine #define MEM_FLAG PFLAGS0,1 ;cancel memory flag #define QUIET PFLAGS0,2 ;flag set when no sitetone required #define SWAP PFLAGS0,3 ;flag set when paddles are swapped #define AWAKE PFLAGS0,4 ;flag set when any key or button is pressed #define DITTER_FLAG PFLAGS0,5 ;flag for dot memory #define DAH_FLAG PFLAGS0,6 ;flag for dash memory ;EEPROM register EEDITLEN equ 0x02 ;Constants ditlen equ 0x30 dlylen equ 0xDF PAGE ;================= Start of Code ================= org 0 goto BEGIN org 4 BEGIN clrf STATUS ; this also sets bank 0 clrf PORTA clrf PORTB movlw b'01111111' banksel INTCON movwf INTCON movlw 0x000 banksel TRISA movwf TRISA banksel TRISB bcf OPTION_REG,7 ;enable pull up on all PortB ports movlw b'11111000' ;define RB0, RB1 and RB2 as output movwf TRISB movwf TRISB banksel ANSEL clrf ANSEL ; ;========================= OSCCON =================================== banksel OSCCON ; --------The Internal RC Frequency can be set at any time after ORG ----------------------- ; Now set 32 kHz clock bcf OSCCON, IRCF2 ; 110 is 4 MHz ; 000 is 32 kHz; 001 is 125 kHz bcf OSCCON, IRCF1 bsf OSCCON, IRCF0 ; ; ============ the 16F88 has a clock fail safe system that's not used here = bcf OSCCON,SCS0 ; 00 is Oscillator mode defined by FOSC <2:0> bcf OSCCON,SCS1 ; nop ; allow some time for oscillator to settle nop banksel OSCTUNE bsf OSCTUNE,TUN5 bcf OSCTUNE,TUN4 bsf OSCTUNE,TUN3 bsf OSCTUNE,TUN2 banksel PORTA bcf QUIET bcf SWAP movlw 0x55 ;4 MHz ;Default speed with 3:1 ratio movwf DITREG movlw 0xFF ;4 MHz movwf DAHREG movlw 0x01 ;Test 32 kHz clock movwf DLYREG RESTART call DITQ ;boot-up A character call DAHQ call SPCQ ;The basic algorithm for the keyer is: ;Check dit paddle - send dit if pressed ;Check dah paddle - send dah if pressed ;Check for command mode ;Cycle START btfss DITIN ;check dit paddle call DIT ;send dit if pressed btfss DAHIN ;check dah paddle call DAH ;send dah if pressed btfss MEM1 call MEMORY_3 btfss MEM2 call MEMORY_4 btfss CMDIN ;check speed adjust goto DO_SPD bcf MEM_FLAG btfss DITIN ;check if switches are still pressed goto START ;avoid sleep if pressed btfss DAHIN goto START btfss MEM1 goto START btfss MEM2 goto START btfss CMDIN goto START banksel INTCON ;select INTCON clrf INTCON ;clear it bcf INTCON,GIE ;read/clear INTCON bsf INTCON,RBIE movlw 0xFF ;Make TRISIO all input to save power. banksel TRISA ;select TRISIO movwf TRISA ;create all inputs sleep ;Sleep nop movlw 0x000 ;configure 0,1,2 as output banksel TRISA movwf TRISA banksel INTCON bcf INTCON,GIE ;read/clear INTCON goto START ;Enter command mode DO_SPD btfsc CMDIN goto END_SPD btfsc MEM_FLAG ;+++++++++++++++++++++++++++++++++++++++++++++++++++++ goto START ;speed adjustment call DITQ call DAHQ btfsc DITIN ;check dit paddle goto ADJ_SLO ; movlw 4 ;go faster subwf DITREG, F ;decrease the dit length bcf DITREG, 7 bcf DITREG, 6 movf DITREG, W movwf DAHREG addwf DAHREG, F addwf DAHREG, F goto DO_SPD ADJ_SLO btfsc DAHIN ;check dah paddle goto DO_SPD movlw 4 ;go slower addwf DITREG, F ;increase the dit length bcf DITREG, 6 movf DITREG, W movwf DAHREG addwf DAHREG, F addwf DAHREG, F goto DO_SPD END_SPD goto RESTART DIT btfss DAHIN goto IAMBIC DITS movf DITREG, W ;makes a dit and a space with dot/dash memory and keyed output movwf CNT2 bsf RX_MUTE bsf PTT bsf KEYOUT DIT1 decfsz CNT2, F goto DIT2 goto DIT3 DIT2 btfsc QUIET ;check for no sidetone goto DIT2A bsf SPKR bcf SPKR_ call DIT_DELAY bcf SPKR bsf SPKR_ DIT2A call DIT_DELAY btfsc QUIET ;check for no sidetone goto DIT2B bsf SPKR bcf SPKR_ call DIT_DELAY bcf SPKR bsf SPKR_ DIT2B call DIT_DELAY goto DIT1 DIT3 movf DITREG, W movwf CNT2 DIT4 decfsz CNT2, F goto DIT5 bcf PTT bcf RX_MUTE bsf DIT_FLAG bcf DITTER_FLAG btfsc DAH_FLAG goto DAHS return DIT5 bcf KEYOUT bcf SPKR bcf SPKR_ call DIT_DELAY call DIT_DELAY bcf SPKR bcf SPKR_ call DIT_DELAY call DIT_DELAY goto DIT4 DAH btfss DITIN goto IAMBIC DAHS movf DAHREG, W ;makes a dah and a space movwf CNT2 bsf RX_MUTE bsf PTT bsf KEYOUT DAH1 decfsz CNT2, F goto DAH2 goto DAH3 DAH2 btfsc QUIET goto DAH2A bsf SPKR bcf SPKR_ call DAH_DELAY bcf SPKR bsf SPKR_ DAH2A call DAH_DELAY btfsc QUIET goto DAH2B bsf SPKR bcf SPKR_ call DAH_DELAY bcf SPKR bsf SPKR_ DAH2B call DAH_DELAY goto DAH1 DAH3 movf DITREG, W movwf CNT2 DAH4 decfsz CNT2, F goto DAH5 bcf PTT bcf RX_MUTE bcf DIT_FLAG bcf DAH_FLAG btfsc DITTER_FLAG goto DITS return DAH5 bcf KEYOUT bcf SPKR bcf SPKR_ call DAH_DELAY call DAH_DELAY bcf SPKR bcf SPKR_ call DAH_DELAY call DAH_DELAY goto DAH4 SPC movf DAHREG, W ;makes a letter space movwf CNT2 bsf RX_MUTE bsf PTT bcf KEYOUT SPC1 decfsz CNT2, F goto SPC2 goto SPC3 SPC2 bcf SPKR bcf SPKR_ call DELAY call DELAY bcf SPKR bcf SPKR_ call DELAY call DELAY goto SPC1 SPC3 movf DITREG, W movwf CNT2 SPC4 decfsz CNT2, F goto SPC5 bcf PTT bcf RX_MUTE return SPC5 bcf SPKR bcf SPKR_ call DELAY call DELAY bcf SPKR bcf SPKR_ call DELAY call DELAY goto SPC4 DITT movf DITREG, W ;makes a dit and a space (no dot/dash memory or iambic) keyed output for memory output movwf CNT2 bsf RX_MUTE bsf PTT bsf KEYOUT DITT1 decfsz CNT2, F goto DITT2 goto DITT3 DITT2 btfsc QUIET ;check for no sidetone goto DITT2A bsf SPKR bcf SPKR_ call DELAY bcf SPKR bsf SPKR_ DITT2A call DELAY btfsc QUIET ;check for no sidetone goto DITT2B bsf SPKR bcf SPKR_ call DELAY bcf SPKR bsf SPKR_ DITT2B call DELAY goto DIT1 DITT3 movf DITREG, W movwf CNT2 DITT4 decfsz CNT2, F goto DITT5 bcf PTT bcf RX_MUTE bsf DIT_FLAG bcf DITTER_FLAG bcf DAH_FLAG return DITT5 bcf KEYOUT bcf SPKR bcf SPKR_ call DELAY call DELAY bcf SPKR bcf SPKR_ call DELAY call DELAY goto DIT4 DAHH movf DAHREG, W ;makes a dah and a space movwf CNT2 bsf RX_MUTE bsf PTT bsf KEYOUT DAHH1 decfsz CNT2, F goto DAHH2 goto DAHH3 DAHH2 btfsc QUIET goto DAHH2A bsf SPKR bcf SPKR_ call DELAY bcf SPKR bsf SPKR_ DAHH2A call DELAY btfsc QUIET goto DAHH2B bsf SPKR bcf SPKR_ call DELAY bcf SPKR bsf SPKR_ DAHH2B call DELAY goto DAHH1 DAHH3 movf DITREG, W movwf CNT2 DAHH4 decfsz CNT2, F goto DAHH5 bcf PTT bcf RX_MUTE bcf DIT_FLAG bcf DAH_FLAG return DAHH5 bcf KEYOUT bcf SPKR bcf SPKR_ call DELAY call DELAY bcf SPKR bcf SPKR_ call DELAY call DELAY goto DAHH4 DELAY nop ;new 32 kHz (now 125 kHz) routine nop return DIT_DELAY btfss DAHIN bsf DAH_FLAG return DITT_DELAY btfss DAHIN nop return DAH_DELAY btfss DITIN bsf DITTER_FLAG return DAHH_DELAY btfss DITIN nop return IAMBIC btfsc DIT_FLAG goto DAHS goto DITS DITQ movf DITREG, W ;makes a dit and a space movwf CNT2 bcf PTT bcf RX_MUTE bcf KEYOUT DITQ1 decfsz CNT2, F goto DITQ2 goto DITQ3 DITQ2 btfsc QUIET goto DITQ2A bsf SPKR bcf SPKR_ call DELAY bcf SPKR bsf SPKR_ DITQ2A call DELAY btfsc QUIET goto DITQ2B bsf SPKR bcf SPKR_ call DELAY bcf SPKR bsf SPKR_ DITQ2B call DELAY goto DITQ1 DITQ3 movf DITREG, W movwf CNT2 DITQ4 decfsz CNT2, F goto DITQ5 bcf PTT bcf RX_MUTE bcf DIT_FLAG bcf DITTER_FLAG bcf DAH_FLAG return DITQ5 bcf KEYOUT bcf SPKR bcf SPKR_ call DELAY call DELAY bcf SPKR bcf SPKR_ call DELAY call DELAY goto DITQ4 DAHQ movf DAHREG, W ;makes a dah and a space movwf CNT2 bcf PTT bcf RX_MUTE bcf KEYOUT DAHQ1 decfsz CNT2, F goto DAHQ2 goto DAHQ3 DAHQ2 btfsc QUIET goto DAHQ2A bsf SPKR bcf SPKR_ call DELAY bcf SPKR bsf SPKR_ DAHQ2A call DELAY btfsc QUIET goto DAHQ2B bsf SPKR bcf SPKR_ call DELAY bcf SPKR bsf SPKR_ DAHQ2B call DELAY goto DAH1 DAHQ3 movf DITREG, W movwf CNT2 DAHQ4 decfsz CNT2, F goto DAHQ5 bcf PTT bcf RX_MUTE bcf DIT_FLAG bcf DITTER_FLAG bcf DAH_FLAG return DAHQ5 bcf PTT bcf RX_MUTE bcf KEYOUT bcf SPKR bcf SPKR_ call DELAY call DELAY bcf SPKR bcf SPKR_ call DELAY call DELAY goto DAHQ4 SPCQ movf DAHREG, W ;makes a letter space movwf CNT2 bcf KEYOUT SPCQ1 decfsz CNT2, F goto SPCQ2 goto SPCQ3 SPCQ2 bcf SPKR bcf SPKR_ call DELAY call DELAY bcf SPKR bcf SPKR_ call DELAY call DELAY goto SPCQ1 SPCQ3 movf DITREG, W movwf CNT2 SPCQ4 decfsz CNT2, F goto SPCQ5 bcf PTT bcf RX_MUTE return SPCQ5 bcf SPKR bcf SPKR_ bcf PTT bcf RX_MUTE call DELAY call DELAY bcf SPKR bcf SPKR_ call DELAY call DELAY goto SPCQ4 MEMORY_3 btfss DAHIN goto MEMORY_1 btfss DITIN goto MEM_3 btfss MEM2 goto SWAPPER goto MEMORY_3 MEM_3 call SPC call M_C ;CQ CQ CQ DE MYCALL MYCALL call M_Q call SPC call STOP call M_C call M_Q call SPC call STOP call M_C call M_Q call SPC call STOP call M_D call M_E call SPC call STOP call MYCALL call SPC call STOP call MYCALL call SPC MEMORY_1 call SPC call M_C ;CQ CQ CQ DE MYCALL MYCALL MYCALL AR K call M_Q call SPC call STOP call M_C call M_Q call SPC call STOP call M_C call M_Q call SPC call STOP call M_D call M_E call SPC call STOP call MYCALL call SPC call STOP call MYCALL call SPC call STOP call MYCALL call SPC call STOP call M_AR call SPC call M_K goto START MEMORY_2 call SPC call M_C ;CQ TEST CQ TEST DE MYCALL MYCALL K call M_Q call SPC call STOP call M_T call M_E call M_S call M_T call SPC call STOP call M_C call M_Q call SPC call STOP call M_T call M_E call M_S call M_T call SPC call STOP call M_D call M_E call SPC call STOP call MYCALL call SPC call STOP call MYCALL call SPC call M_K goto START MEMORY_4 btfss DAHIN goto MEMORY_2 btfss DITIN goto MEM_4 btfss MEM1 goto SILENCE goto MEMORY_4 MEM_4 call SPC call M_Q ;QRZ QRZ DE MYCALL MYCALL K call M_R call M_Z call M_? call SPC call STOP call M_D call M_E call SPC call STOP call MYCALL call SPC call M_K goto START M_0 call DAHH ;0 call DAHH call DAHH call DAHH call DAHH call SPC return M_1 call DITT ;1 call DAHH call DAHH call DAHH call DAHH call SPC return M_2 call DITT ;2 call DITT call DAHH call DAHH call DAHH call SPC return M_3 call DITT ;3 call DITT call DITT call DAHH call DAHH call SPC return M_4 call DITT ;4 call DITT call DITT call DITT call DAHH call SPC return M_5 call DITT ;5 call DITT call DITT call DITT call DITT call SPC return M_6 call DAHH ;6 call DITT call DITT call DITT call DITT call SPC return M_7 call DAHH ;7 call DAHH call DITT call DITT call DITT call SPC return M_8 call DAHH ;8 call DAHH call DAHH call DITT call DITT call SPC return M_9 call DAHH ;9 call DAHH call DAHH call DAHH call DITT call SPC return M_AR call DITT ;AR call DAHH call DITT call DAHH call DITT call SPC return M_SK call DITT ;SK call DITT call DITT call DAHH call DITT call DAHH call SPC return M_PER call DITT ;PER call DAHH call DITT call DAHH call DITT call DAHH call SPC return M_COM call DAHH ;COM call DAHH call DITT call DITT call DAHH call DAHH call SPC return M_BT call DAHH ;BT call DITT call DITT call DITT call DAHH call SPC return M_? call DITT ;QUESTION Mark call DITT call DAHH call DAHH call DITT call DITT call SPC return M_DN call DAHH ;DN / call DITT call DITT call DAHH call DITT call SPC return M_A call DITT ;A call DAHH call SPC return M_B call DAHH ;B call DITT call DITT call DITT call SPC return M_C call DAHH ;C call DITT call DAHH call DITT call SPC return M_D call DAHH ;B call DITT call DITT call SPC return M_E call DITT ;E call SPC return M_F call DITT ;F call DITT call DAHH call DITT call SPC return M_G call DAHH ;G call DAHH call DITT call SPC return M_H call DITT ;H call DITT call DITT call DITT call SPC return M_I call DITT ;B call DITT call SPC return M_J call DITT ;J call DAHH call DAHH call DAHH call SPC return M_K call DAHH ;K call DITT call DAHH call SPC return M_L call DITT ;L call DAHH call DITT call DITT call SPC return M_M call DAHH ;M call DAHH call SPC return M_N call DAHH ;N call DITT call SPC return M_O call DAHH ;O call DAHH call DAHH call SPC return M_P call DITT ;P call DAHH call DAHH call DITT call SPC return M_Q call DAHH ;Q call DAHH call DITT call DAHH call SPC return M_R call DITT ;R call DAHH call DITT call SPC return M_S call DITT ;S call DITT call DITT call SPC return M_T call DAHH ;T call SPC return M_U call DITT ;U call DITT call DAHH call SPC return M_V call DITT ;V call DITT call DITT call DAHH call SPC return M_W call DITT ;W call DAHH call DAHH call SPC return M_X call DAHH ;X call DITT call DITT call DAHH call SPC return M_Y call DAHH ;Y call DITT call DAHH call DAHH call SPC return M_Z call DAHH ;Z call DAHH call DITT call DITT call SPC return SILENCE btfss QUIET goto SILENCE1 goto SILENCE2 SILENCE1 bsf QUIET return SILENCE2 bcf QUIET return SWAPPER btfss SWAP goto SWAPPER1 goto SWAPPER2 SWAPPER1 bsf SWAP return SWAPPER2 bcf SWAP return STOP bsf MEM_FLAG btfss CMDIN goto START return MYCALL call M_G call M_4 call M_H call M_Y call M_G return end ;History ;12 Oct 2009 v101 Initial test firmware. Input and output doesn't work yet! ;23 Oct 2009 v102 Inputs and outputs working, timing isn't right. ;23 Oct 2009 v103 Fixed timing added for testing, next add iambic memory. ;23 Oct 2009 v104 Tidy up. ;24 Oct 2009 v105 Add PTT output (was LED, add "quiet" dit, dah and space with no ; keyout or ptt for boot-up and future command. ;24 Oct 2009 v106 Iambic dot / dash memory added. ;24 Oct 2009 v107 Speed control added. ;24 Oct 2009 v108 Memories added. ;24 Oct 2009 v109 Alpha-numeric routines added. ;24 Oct 2009 v110 Tidy code up. Sleep added. Needs DC current tests to check. ;27 Oct 2009 v111 Four memories added. Memory switch + dit or dah. ;27 Oct 2009 v112 Now uses internal 4 MHz clock (doesn't need crystal and two caps). ;27 Oct 2009 v113 Test sleep mode. ;29 Oct 2009 v114 Add SPC in front of all messages, add STOP function to cancel ; messages part way through, add code and write protection. ;29 Oct 2009 v115 Add MEM_FLAG to stop Cancel button going into Speed routine after ; cancelling a memory. ;30 Oct 2009 v116 SPKR_ added to increase AC voltage across piezo sounder. Finished ; version so far. ;30 Oct 2009 v117 Proposed production version before public demo at rally ;3 Nov 2009 v118 Add RX_MUTE for receiver muting output (same as PTT)and sidetone ; quiet option (Memory 2 then Memory 1). ;3 Nov 2009 v119 Final version. QRZ now QRZ? de mycall K. ;25 Nov 2009 v121 Sleep routine removed not needed for solar power ;3 Dec 2009 v122 Solar power shelved for now, NOP's added in front of sleep ;3 Dec 2009 v123 Osc set to 31 kHz before sleep, now sleeps but will not restart ;3 Dec 2009 v124 Osc runs at 31 kHz, delay routine replaced by 2 NOP's, sleep ; current now 10 uA, running (dots) 110 uA. ;3 Dec 2009 v125 Code tidied up ;10 Dec 2009 v225 New sleep routine added. Dit, dah and cmd pins changed so that ; dit, dah, mem1 and mem2 are on PortB interrupt pins. Check added ; to see if paddles/buttons still pressed before sleep. Sleep 0.1 uA. ;30 Dec 2009 v226 Dot and dash memories added, additional DITT and DAHH routines added for no dot dash memories during ; memory playback ;30 Dec 2009 v227 Double delays added to double audio tone frequency.Osc now runs at 125 kHz. Sidetone output now OK, ; Sleep current 0.1 uA, running (dots) 395 uA. ;Cross Country Wireless Keyer Firmware v 227 by Chris Moulding G4HYG ;Copyright (c) 2009, Chris Moulding G4HYG ;All rights reserved. ;Redistribution and use in source and binary forms, with or without modification, ;are permitted provided that the following conditions are met: ;Redistributions of source code must retain the above copyright notice, ;this list of conditions and the following disclaimer. ;Redistributions in binary form must reproduce the above copyright notice, ;this list of conditions and the following disclaimer in the documentation ;and/or other materials provided with the distribution. ;Neither the name of the nor the names of its contributors ;may be used to endorse or promote products derived from this software without ;specific prior written permission. ;THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ;AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ;THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ;PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS ;BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ;CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ;SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ;INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ;CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ;ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF ;THE POSSIBILITY OF SUCH DAMAGE. ;------------------------------------------------------------