;************************************************************************** ;* OM1AVK - CW MEMORY KEYER * ;************************************************************************** ;* AVKEY : FIX MEMORY KEYER with PIC16F628A * ;************************************************************************** ;* Freeware for radio amateur usage * ;* STATUS : DEVELOPMENT FOR FINAL SOLUTION ON THE BOARD * ;************************************************************************** ;* OM1AVK / avk@kanich.net * * ;* special thanks to : DL4YHF * ;************************************************************************** #include errorlevel -302 __CONFIG _BODEN_ON & _CP_OFF & _DATA_CP_OFF & _PWRTE_ON & _WDT_OFF & _LVP_OFF & _MCLRE_OFF & _XT_OSC ;========================================================================== ; Variable Definition ;========================================================================== ;PORTA bit assignment SW4 EQU H'02' ;SW1 is triggering RA2 SW3 EQU H'03' ;SW2 is triggering RA3 SW2 EQU H'04' ;SW3 is triggering RA4 SW1 EQU H'01' ;SW4 is triggering RA1 ;General registers cblock 0x20 TIMER1 ;Used in delay routine TIMER2 ; " " " PATERN ;Pattern data for effect's TIMER_DOT ;Basic timer for dot length KY_char ;Register for image of CW character KY_count ;Counter for dashes+dots in a character CW_decode ;(ASCII->internal CW code) temp POTI ;poti reading counter POTI2 ;poti data = 3 * POTI TIMER_RX ;Timer for RX wait in repeat loop endc #define IOP_POTI1 PORTA, 0 ; only if poti is POLLED (NO IRQ!!) CWCHR macro char,pause MOVLW char CALL KYT_DEC if pause==0 CALL DASH_SP else CALL WORD_SP endif endm ;========================================================================== ; Program Definition ;========================================================================== ORG 0 ;Reset vector address GOTO RESET ;goto RESET routine when boot. ; Storage format of "spaces", "control characters" and "transmittable CW letters" ; --------------------------------------------------------------------------------- ; The most significant bits define the code type. ; Bit7: 1 = "this is SPACE (=pause) or CONTROL character", in this case: ; Bit6,Bit5 = control character type: ; 0x = SPACE (=pause, bits5..0 contain the length in DOTS (max.63) ; 10 = extra long "dash", bits4..0 contain the length in DOTS (max.31) ; 11 = future reserve, bits4..0 contain 31 possible codes ; Bit7: 0 = "this is a transmittable character (not SPACE or CONTROL)". ; Bits6..0 contain a maximum of 6 dashes or dots, ; with leading 1="Startbit" before the "dash/dot-matrix", ; dash/dot-matrix is in Bit0..max.Bit5: ; 0=dot 1=dash ; Bit0 always contains the LAST TRANSMITTED dash/dot. ; See definitions below for some examples how CW letters are stored in memory. #define CW_0 b'00111111' ; "0" #define CW_1 b'00101111' ; "1" #define CW_2 b'00100111' ; "2" #define CW_3 b'00100011' ; "3" #define CW_4 b'00100001' ; "4" #define CW_5 b'00100000' ; "5" #define CW_6 b'00110000' ; "6" #define CW_7 b'00111000' ; "7" #define CW_8 b'00111100' ; "8" #define CW_9 b'00111110' ; "9" #define CW_A b'00000101' ; 'A' #define CW_B b'00011000' ; 'B' #define CW_C b'00011010' ; 'C' #define CW_D b'00001100' ; 'D' #define CW_E b'00000010' ; 'E' #define CW_F b'00010010' ; 'F' #define CW_G b'00001110' ; 'G' #define CW_H b'00010000' ; 'H' #define CW_I b'00000100' ; 'I' #define CW_J b'00010111' ; 'J' #define CW_K b'00001101' ; 'K' #define CW_L b'00010100' ; 'L' #define CW_M b'00000111' ; 'M' #define CW_N b'00000110' ; 'N' #define CW_O b'00001111' ; 'O' #define CW_P b'00010110' ; 'P' #define CW_Q b'00011101' ; 'Q' #define CW_R b'00001010' ; 'R' #define CW_S b'00001000' ; 'S' #define CW_T b'00000011' ; 'T' #define CW_U b'00001001' ; 'U' #define CW_V b'00010001' ; 'V' #define CW_W b'00001011' ; 'W' #define CW_X b'00011001' ; 'X' #define CW_Y b'00011011' ; 'Y' #define CW_Z b'00011100' ; 'Z' #define CW_SEPAR b'00110001' ; '=' (-...-) this is the "official" separator #define CW_SEPA2 b'01100001' ; '-' (-....-) but this is also frequenty used #define CW_POINT b'01010101' ; '.' (-.-.-.) #define CW_SLASH b'00110010' ; '/' (-..-.) #define CW_? b'01001100' ; '?' (..--..) #define CW_AR b'00101010' ; '+[AR]' (.-.-.) #define CW_SK b'01000101' ; '*[SK]' (...-.-) #define CW_KA b'00110101' ; '$[KA}' (-.-.-) #define CW_KN b'00110110' ; '#[KN]' (-.--.) #define CW_EOM b'01011111' ; 'EOM' (.-----) used for "partitions" of msg #define CW_NNN b'01101010' ; 'NNN' (-.-.-.) replaced by serial number #define CW_ANN b'01011010' ; 'ANN' (.--.-.) advance to next number #define CW_SPACE b'10000000' ; ' ' (pause length in "dots" will be added) ;********************************************* ;* Main delay routine * ;********************************************* DELAY_ROUTINE MOVLW D'3' ;54 Generate approx 10mS delay at 4Mhz CLK MOVWF TIMER2 DEL_LOOP1 MOVLW D'160' ;60 MOVWF TIMER1 DEL_LOOP2 DECFSZ TIMER1,F GOTO DEL_LOOP2 DECFSZ TIMER2,F GOTO DEL_LOOP1 RETLW 0 ; ;********************************************* ;* RX delay routine (repeat function) * ;* with exit to MENU when ESC pressed * ;********************************************* DELAY_RX MOVLW D'3' ;54 Generate approx 10mS delay at 4Mhz CLK MOVWF TIMER2 DEL_RX1 MOVLW D'160' ;60 MOVWF TIMER1 DEL_RX2 BSF PORTB,7 ;Activate (RB7) BCF OPTION_REG, NOT_RBPU BTFSC PORTA,SW2 ;Check ESC GOTO MENU DECFSZ TIMER1,F GOTO DEL_RX2 DECFSZ TIMER2,F GOTO DEL_RX1 RETLW 0 ; ;********************************************* ;* CW character processing * ;********************************************* KYT_DEC BSF PORTB,2 MOVWF KY_char MOVLW 6 ; load number of dots+dashes MOVWF KY_count ; ..into "element counter" BTFSC KY_char,6 ; is it 6-element-char ? GOTO kyt_play6 ; else.. DECF KY_count,F BTFSC KY_char,5 ; is it 5-element-char ? GOTO kyt_play5 ; else.. DECF KY_count,F BTFSC KY_char,4 ; is it 4-element-char ? GOTO kyt_play4 ; else.. DECF KY_count,F BTFSC KY_char,3 ; is it 3-element-char ? GOTO kyt_play3 ; else.. DECF KY_count,F BTFSC KY_char,2 ; is it 2-element-char ? GOTO kyt_play2 ; else must be 1-element-char DECF KY_count,F ; is it 1-element-char RLF KY_char,F kyt_play2 RLF KY_char,F kyt_play3 RLF KY_char,F kyt_play4 RLF KY_char,F kyt_play5 RLF KY_char,F kyt_play6 BTFSC KY_char,5 GOTO KYT_DASH BSF PORTB,1 CALL DOT GOTO KYT_NEXT KYT_DASH BSF PORTB,1 CALL DASH KYT_NEXT BCF PORTB,1 DECFSZ KY_count,F GOTO kyt_playb RETLW 0 kyt_playb CALL DOT_SP RLF KY_char,F GOTO kyt_play6 ; ;********************************** ;** RESET : main boot routine ** ;********************************** RESET MOVLW B'00000111' ;Disable Comparator module's MOVWF CMCON ; BSF STATUS,RP0 ;Switch to register bank 1 ;Disable pull-ups ;INT on rising edge ;TMR0 to CLKOUT ;TMR0 Incr low2high trans. ;Prescaler assign to Timer0 ;Prescaler rate is 1:256 MOVLW B'11010111' ;Set PIC options (See datasheet). MOVWF OPTION_REG ;Write the OPTION register. ; CLRF INTCON ;Disable interrupts MOVLW B'00000000' MOVWF TRISB ;RB7...RB0 are outputs. MOVLW B'11111110' ;RA(1-4) ports are inputs,RA(0) are outputs MOVWF TRISA BCF STATUS,RP0 MOVLW D'30' MOVWF POTI MOVLW D'90' MOVWF POTI2 GOTO MENU ;********************************************* ; 4 x 4 keypad read & switch ;1 CQ CQ TEST DE OM1AVK OM1AVK BK ;2 ?QRZ OM1AVK BK ;3 CFM 73 TU K ;4 DE OM1AVK OM1AVK BK ;5 DE OM1AVK OM1AVK OM1AVK BK ;6 DE OM1AVK OM1AVK OM1AVK OM1AVK BK ;7 ?AGN AGN K ;8 NR? NR? BK ;9 LOC? LOC? BK ;0 OM1AVK ;A WKD B4 TNX ;B 73 TU K ;C ? RPT ALL BK ;D JN88OD ;* ESC (stop) ;# (start) ;********************************************* MENU CLRF PORTB CALL SETPOTI MOVLW B'00010000' ;Activate (RB4) MOVWF PORTB BCF OPTION_REG, NOT_RBPU BTFSC PORTA,SW1 GOTO MA BTFSC PORTA,SW2 GOTO M1 BTFSC PORTA,SW3 GOTO M2 BTFSC PORTA,SW4 GOTO M3 MOVLW B'00100000' ;Activate (RB5) MOVWF PORTB BCF OPTION_REG, NOT_RBPU BTFSC PORTA,SW1 GOTO MB BTFSC PORTA,SW2 GOTO M4 BTFSC PORTA,SW3 GOTO M5 BTFSC PORTA,SW4 GOTO M6 MOVLW B'01000000' ;Activate (RB6) MOVWF PORTB BCF OPTION_REG, NOT_RBPU BTFSC PORTA,SW1 GOTO MC BTFSC PORTA,SW2 GOTO M7 BTFSC PORTA,SW3 GOTO M8 BTFSC PORTA,SW4 GOTO M9 MOVLW B'10000000' ;Activate (RB7) MOVWF PORTB BCF OPTION_REG, NOT_RBPU BTFSC PORTA,SW1 GOTO MD BTFSC PORTA,SW2 GOTO ESC BTFSC PORTA,SW3 GOTO M0 BTFSC PORTA,SW4 GOTO NUM GOTO MENU ; ReadPoti BCF INTCON, GIE ;01 disable IRQs while we are in register bank 1 ; (and to prevent bad poti readings !) CLRF POTI CLRF POTI2 BCF IOP_POTI1 ;02 clear Poti pin output latch to discharge BSF STATUS, RP0 ;! ;03 set RP0 for TRIS access (;!) BCF IOP_POTI1 ;! ;04 define PortB.0 as output -> begin discharge ; (typical discharge of 220nF from 2V to 0V takes about 100usec) NOP ;! ;05 ensure capacitor gets completely discarged ! BSF IOP_POTI1 ;! ;06 define PortB.0(!!) as input -> start e-function BCF STATUS, RP0 ;! ;07 clear RP0 for "normal" access ; after a certain time the state of the poti input ; will toggle from '0' (which it should be now) to '1'. LoopPoti BTFSC IOP_POTI1 ;08 check if already charged RETURN INCF POTI BTFSC STATUS,Z RETURN GOTO LoopPoti ; SETPOTI CALL ReadPoti ; RRF POTI MOVF POTI,W ANDLW H'F0' MOVWF POTI SWAPF POTI MOVLW D'14' ADDWF POTI ; MOVF POTI,W ; CALL KYT_DEC MOVF POTI,W MOVWF POTI2 ADDWF POTI2 ADDWF POTI2 RETURN ;********************************************* ;* Wait routine for memory #1 repeat call * ;********************************************* RX_WAIT BCF PORTB,2 ;Stop PTT -> OFF MOVLW D'200' MOVWF TIMER_RX RX_LOOP CALL DELAY_RX CALL DELAY_RX DECFSZ TIMER_RX,F GOTO RX_LOOP RETURN ;********************************************* ;* Message generation * ;********************************************* M1 CALL CQTEST ;CQ CQ TEST DE OM1AVK OM1AVK BK CALL OM1AVK CALL OM1AVK CALL BK CALL RX_WAIT GOTO M1 ; M2 CALL CQTEST ;CQ CQ TEST DE OM1AVK OM1AVK OM1AVK BK CALL OM1AVK CALL OM1AVK CALL OM1AVK CALL BK GOTO MENU ; M3 CWCHR CW_?,0 ;?QRZ OM1AVK BK CWCHR CW_Q,0 CWCHR CW_R,0 CWCHR CW_Z,1 CALL OM1AVK CALL BK GOTO MENU ; M4 CALL DE1 ;DE OM1AVK OM1AVK BK CALL OM1AVK CALL OM1AVK CALL BK GOTO MENU M5 CALL DE1 ;DE OM1AVK OM1AVK OM1AVK BK CALL OM1AVK CALL OM1AVK CALL OM1AVK CALL BK GOTO MENU M6 CALL DE1 ;DE OM1AVK OM1AVK OM1AVK OM1AVK BK CALL OM1AVK CALL OM1AVK CALL OM1AVK CALL OM1AVK CALL BK GOTO MENU M7 MOVLW CW_? ;?AGN AGN K CALL KYT_DEC CALL DASH_SP CALL AGN CALL AGN MOVLW CW_K CALL KYT_DEC GOTO MENU M8 CALL NR ;NR? NR? BK CALL NR CALL BK GOTO MENU M9 CALL LOC ;LOC? LOC? BK CALL LOC CALL BK GOTO MENU M0 NOP GOTO MENU ESC NOP GOTO MENU ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx NUM BSF PORTB,2 ;Switch PTT ON without CW keying NUM1 BSF PORTB,7 ;Activate (RB7) BCF OPTION_REG, NOT_RBPU BTFSC PORTA,SW4 GOTO MENU GOTO NUM1 ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx MA CALL ReadPoti RLF POTI MOVF POTI,W ANDLW H'F0' MOVWF POTI SWAPF POTI INCF POTI MOVLW D'13' ADDWF POTI MOVF POTI,W CALL KYT_DEC MOVF POTI,W MOVWF POTI2 ADDWF POTI2 ADDWF POTI2 GOTO MENU MB NOP GOTO MENU MC NOP GOTO MENU MD NOP GOTO MENU OM1AVK MOVLW CW_O CALL KYT_DEC CALL DASH_SP MOVLW CW_M CALL KYT_DEC CALL DASH_SP MOVLW CW_1 CALL KYT_DEC CALL DASH_SP MOVLW CW_A CALL KYT_DEC CALL DASH_SP MOVLW CW_V CALL KYT_DEC CALL DASH_SP MOVLW CW_K CALL KYT_DEC CALL WORD_SP RETURN ; CQTEST MOVLW CW_C ;CQ CQ TEST DE CALL KYT_DEC CALL DASH_SP MOVLW CW_Q CALL KYT_DEC CALL WORD_SP MOVLW CW_C CALL KYT_DEC CALL DASH_SP MOVLW CW_Q CALL KYT_DEC CALL WORD_SP ; MOVLW CW_T CALL KYT_DEC CALL DASH_SP MOVLW CW_E CALL KYT_DEC CALL DASH_SP MOVLW CW_S CALL KYT_DEC CALL DASH_SP MOVLW CW_T CALL KYT_DEC CALL WORD_SP ; CALL DE1 RETURN ; DE1 MOVLW CW_D CALL KYT_DEC CALL DASH_SP MOVLW CW_E CALL KYT_DEC CALL WORD_SP RETURN ; BK MOVLW CW_B CALL KYT_DEC CALL DOT_SP MOVLW CW_K CALL KYT_DEC RETURN ; AGN MOVLW CW_A CALL KYT_DEC CALL DASH_SP MOVLW CW_G CALL KYT_DEC CALL DASH_SP MOVLW CW_N CALL KYT_DEC CALL WORD_SP RETURN ; NR MOVLW CW_N CALL KYT_DEC CALL DASH_SP MOVLW CW_R CALL KYT_DEC CALL DASH_SP MOVLW CW_? CALL KYT_DEC CALL WORD_SP RETURN ; LOC MOVLW CW_L CALL KYT_DEC CALL DASH_SP MOVLW CW_O CALL KYT_DEC CALL DASH_SP MOVLW CW_C CALL KYT_DEC CALL DASH_SP MOVLW CW_? CALL KYT_DEC CALL WORD_SP RETURN ; DOT MOVF POTI,W ;D'30' ;MOVLW D'30' MOVWF TIMER_DOT D_LOOP BSF PORTB,0 ;Activate LD1 (RB0) CALL DELAY_ROUTINE BCF PORTB,0 ;DeActivate LD1 (RB0) CALL DELAY_ROUTINE DECFSZ TIMER_DOT,F GOTO D_LOOP RETLW 0 ; DOT_SP MOVF POTI,W ;D'30' ;MOVLW D'30' MOVWF TIMER_DOT S_LOOP NOP CALL DELAY_ROUTINE NOP CALL DELAY_ROUTINE DECFSZ TIMER_DOT,F GOTO S_LOOP RETLW 0 ; DASH MOVF POTI2,W ;D'90' ;MOVLW D'90' MOVWF TIMER_DOT D_LOOP2 BSF PORTB,0 ;Activate LD1 (RB0) CALL DELAY_ROUTINE BCF PORTB,0 ;DeActivate LD1 (RB0) CALL DELAY_ROUTINE DECFSZ TIMER_DOT,F GOTO D_LOOP2 RETLW 0 ; DASH_SP MOVF POTI2,W ;D'90' ;MOVLW D'90' MOVWF TIMER_DOT S_LOOP2 ;NOPxxxxxxxxxxxxxxxxxxxxxxxxxx ESC Trap BSF PORTB,7 ;Activate (RB7) BCF OPTION_REG, NOT_RBPU BTFSC PORTA,SW2 GOTO MENU ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx CALL DELAY_ROUTINE CALL DELAY_ROUTINE DECFSZ TIMER_DOT,F GOTO S_LOOP2 RETLW 0 ; WORD_SP MOVF POTI2,W ;D'90' ;MOVLW D'90' MOVWF TIMER_DOT S_LOOP3 ;NOPxxxxxxxxxxxxxxxxxxxxxxxxxx ESC Trap BSF PORTB,7 ;Activate (RB7) BCF OPTION_REG, NOT_RBPU BTFSC PORTA,SW2 GOTO MENU ;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx CALL DELAY_ROUTINE NOP CALL DELAY_ROUTINE DECFSZ TIMER_DOT,F GOTO S_LOOP3 RETLW 0 END