CW keyer for foxes and beacons
Introduction
Beacons and foxes have to identify themselves. Although I could sit along all day with my morse key, transmitting my call, I wanted to have some automatic keyer. Since I recently bought a PIC development kit (Velleman K8048), I thought that it would be a nice idea to create my first PIC application by building a CW keyer.
I never wrote PIC source code yet, but I have done some assembly for 68000 and x86 in the past. So it shouldn’t be to difficult to write a simple program, keying one of the outputs of a PIC. On the CD of my PIC development kit I found some sample programs, including one for a flashing LED (this appears to be the “Hello, World!” application for microcontrollers). I modified the source code and finally build the bunch of code which you can find on the bottom of this page. I’m sure that this code is not the best PIC program of the world, but it works and at least I understand how it actually works. If you have any suggestions, please feel free to send them to me!
The reason that I used a PIC16F627 and not the far more popular 16F84 is that the 627 comes default with the PIC development kit and the “flashing lED” code was written for that PIC too…
Schematic

The schematic is not that difficult. Actually the software keys 2 outputs (RB0 and RB1). You can use one to create a PTT/key output (T1, R2) and one to flash a LED (then you know it’s doing its job). R1 provides a correct initialisation of the PIC processor, and X1, C3 and C4 form a basic clock circuit. Using a crystal with another frequency wil impact the keying speed.
Most beacons and foxes don’t use 5 volts for power but some higher voltage. So you may add U1, C1 and C2 to create 5V (required for the PIC).
Code
;*********************
;* PA3HCM * CW KEYER *
;*********************
W EQU H'0000'
F EQU H'0001'
;----- Register Files------------------------------------------------------
INDF EQU H'0000'
TMR0 EQU H'0001'
PCL EQU H'0002'
STATUS EQU H'0003'
FSR EQU H'0004'
PORTA EQU H'0005'
PORTB EQU H'0006'
INTCON EQU H'000B'
OPTION_REG EQU H'0081'
TRISA EQU H'0085'
TRISB EQU H'0086'
CMCON EQU H'001F'
;----- STATUS Bits --------------------------------------------------------
IRP EQU H'0007'
RP1 EQU H'0006'
RP0 EQU H'0005'
NOT_TO EQU H'0004'
NOT_PD EQU H'0003'
Z EQU H'0002'
DC EQU H'0001'
C EQU H'0000'
;==========================================================================
;
; RAM Definition
;
;==========================================================================
__MAXRAM H'01FF'
__BADRAM H'07'-H'09', H'0D', H'13'-H'14', H'1B'-H'1E'
__BADRAM H'87'-H'89', H'8D', H'8F'-H'91', H'93'-H'97', H'9E'
__BADRAM H'105', H'107'-H'109', H'10C'-H'11F', H'150'-H'16F'
__BADRAM H'185', H'187'-H'189', H'18C'-H'1EF'
;==========================================================================
;
; Configuration Bits
;
;==========================================================================
_BODEN_ON EQU H'3FFF'
_BODEN_OFF EQU H'3FBF'
_CP_ALL EQU H'03FF'
_CP_75 EQU H'17FF'
_CP_50 EQU H'2BFF'
_CP_OFF EQU H'3FFF'
_DATA_CP_ON EQU H'3EFF'
_DATA_CP_OFF EQU H'3FFF'
_PWRTE_OFF EQU H'3FFF'
_PWRTE_ON EQU H'3FF7'
_WDT_ON EQU H'3FFF'
_WDT_OFF EQU H'3FFB'
_LVP_ON EQU H'3FFF'
_LVP_OFF EQU H'3F7F'
_MCLRE_ON EQU H'3FFF'
_MCLRE_OFF EQU H'3FDF'
_ER_OSC_CLKOUT EQU H'3FFF'
_ER_OSC_NOCLKOUT EQU H'3FFE'
_INTRC_OSC_CLKOUT EQU H'3FFD'
_INTRC_OSC_NOCLKOUT EQU H'3FFC'
_EXTCLK_OSC EQU H'3FEF'
_LP_OSC EQU H'3FEC'
_XT_OSC EQU H'3FED'
_HS_OSC EQU H'3FEE'
__CONFIG _BODEN_ON & _CP_OFF & _DATA_CP_OFF & _PWRTE_ON & _WDT_OFF & _LVP_OFF & _MCLRE_ON & _XT_OSC
;==========================================================================
; Variable Definition
;==========================================================================
TIMER1 EQU H'20' ;Used in delay routine
TIMER2 EQU H'21' ; " " "
PATERN EQU H'22' ;Pattern data for effect's
ORG 0 ;Reset vector address
GOTO RESET ;goto RESET routine when boot.
; *********************************************
; * Example of a delay routine *
; *********************************************
DELAY_ROUTINE MOVLW D'127' ;54 Generate approx 10mS delay at 4Mhz CLK
MOVWF TIMER2
DEL_LOOP1 MOVLW D'255' ;60
MOVWF TIMER1
DEL_LOOP2 DECFSZ TIMER1,F
GOTO DEL_LOOP2
DECFSZ TIMER2,F
GOTO DEL_LOOP1
RETLW 0
; **********************************
; ** 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'11000000'
MOVWF TRISB ;RB7 & RB6 are inputs.
;RB5...RB0 are outputs.
MOVLW B'11111111' ;all RA ports are inputs
MOVWF TRISA
BCF STATUS,RP0 ;Switch Back to reg. Bank 0
CLRF PORTB
;
MAIN CALL CW_P
CALL CW_A
CALL CW_3
CALL CW_H
CALL CW_C
CALL CW_M
CALL CW_PAUSE
CALL CW_R
CALL CW_E
CALL CW_C
CALL CW_PAUSE
CALL CW_F
CALL CW_O
CALL CW_X
CALL CW_PAUSE
CALL CW_A
CALL CW_PAUSE
CALL CW_KEYDOWN
CALL CW_KEYUP
CALL CW_PAUSE
GOTO MAIN
DIT MOVLW B'00000011' ;Activate RB0
MOVWF PORTB
CALL DELAY_ROUTINE
MOVLW B'00000000' ;Activate RB0
MOVWF PORTB
CALL DELAY_ROUTINE
RETLW 0
DAH MOVLW B'00000011' ;Activate RB0
MOVWF PORTB
CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
MOVLW B'00000000' ;Activate RB0
MOVWF PORTB
CALL DELAY_ROUTINE
RETLW 0
CW_5 CALL DIT
CW_H CALL DIT
CW_S CALL DIT
CW_I CALL DIT
CW_E CALL DIT
CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
RETLW 0
CW_0 CALL DAH
CALL DAH
CW_O CALL DAH
CW_M CALL DAH
CW_T CALL DAH
CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
RETLW 0
cW_4 CALL DIT
cW_V CALL DIT
cW_U CALL DIT
CW_A CALL DIT
CALL DAH
CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
RETLW 0
CW_8 CALL DAH
CALL DAH
CW_D CALL DAH
CALL DIT
CALL DIT
CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
RETLW 0
CW_7 CALL DAH
CW_B CALL DAH
CALL DIT
CALL DIT
CALL DIT
CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
RETLW 0
CW_SLASH CALL DAH
CW_F CALL DIT
CW_R CALL DIT
CALL DAH
CALL DIT
CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
RETLW 0
CW_C CALL DAH
CALL DIT
CALL DAH
CALL DIT
CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
RETLW 0
CW_9 CALL DAH
CALL DAH
CW_G CALL DAH
CW_N CALL DAH
CALL DIT
CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
RETLW 0
CW_P CALL DIT
CALL DAH
CALL DAH
CALL DIT
CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
RETLW 0
CW_3 CALL DIT
CALL DIT
CALL DIT
CALL DAH
CALL DAH
CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
RETLW 0
CW_2 CALL DIT
CW_J CALL DIT
CALL DAH
CALL DAH
CALL DAH
CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
RETLW 0
CW_Q CALL DAH
CW_K CALL DAH
CALL DIT
CALL DAH
CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
RETLW 0
CW_L CALL DIT
CALL DAH
CALL DIT
CALL DIT
CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
RETLW 0
CW_Y CALL DAH
CW_W CALL DIT
CALL DAH
CALL DAH
CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
RETLW 0
CW_X CALL DAH
CALL DIT
CALL DIT
CALL DAH
CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
RETLW 0
CW_Z CALL DAH
CALL DAH
CALL DIT
CALL DIT
CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
RETLW 0
CW_1 CALL DIT
CALL DAH
CALL DAH
CALL DAH
CALL DAH
CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
RETLW 0
CW_6 CALL DAH
CALL DIT
CALL DIT
CALL DIT
CALL DIT
CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
RETLW 0
CW_PAUSE CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
CALL DELAY_ROUTINE
RETLW 0
CW_KEYDOWN MOVLW B'00000011'
MOVWF PORTB
CALL CW_PAUSE
CALL CW_PAUSE
CALL CW_PAUSE
CALL CW_PAUSE
CALL CW_PAUSE
CALL CW_PAUSE
MOVLW B'000000000'
MOVWF PORTB
RETLW 0
CW_KEYUP MOVLW B'00000000'
MOVWF PORTB
CALL CW_PAUSE
CALL CW_PAUSE
CALL CW_PAUSE
CALL CW_PAUSE
CALL CW_PAUSE
CALL CW_PAUSE
CALL CW_PAUSE
CALL CW_PAUSE
CALL CW_PAUSE
CALL CW_PAUSE
CALL CW_PAUSE
CALL CW_PAUSE
CALL CW_PAUSE
CALL CW_PAUSE
CALL CW_PAUSE
CALL CW_PAUSE
CALL CW_PAUSE
CALL CW_PAUSE
CALL CW_PAUSE
CALL CW_PAUSE
CALL CW_PAUSE
RETLW 0
END
![[image]](https://www.pa3hcm.nl/wp-content/uploads/2013/12/enh-logo1.jpg)