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

cwkeyer_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

Leave a Reply