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