' ' Koch Method Morse Trainer ' ' Copyright (C) 2007 by David Gwillim, KB2TQX ' Email contact: kb2tqx at verizon.net ' ' 26 March 2007 08:15 ' ' Compiled size = 255 bytes ' ' ===================================================================== ' ' Reference: "Morse Code: Breaking The Barrier" by Dave Finley, N1IRZ ' ISBN 1-891237-19-5 Published by MFJ Catalog# MFJ-3400 ' http://www.mfjenterprises.com/products.php?prodid=MFJ-3400 ' ' ================================================================================================== ' ' Koch Method Morse Code Trainer ' ============================== ' ' This program is an implementation of the Koch Training Method for learning the Morse code. It is ' recommended that you read Dave Finley's book, if at all possible, to get an idea of the principles ' that this method is based on. ' ' In the Koch Method the Morse characters are learnt in a specific order, working with a steadily ' increasing pool of characters. The effective WPM is left constant at as high a level as possible. ' ' After the 08M program has started, the size of the character pool is retrieved from non-volatile ' (EEPROM) storage, so even if you remove power the 08M chip will remember where you were in the ' Koch character pool. Initially this value will be 2, so when you start the training session the ' program will randomly select groups of 5 characters from that pool of two - the letters ' "K" and "M". The training session is started by pushing PB1, which on the recycled 1st generation ' ROOKEY PC board, is the button mounted in the "C5" position. PB2 is mounted in the U1 space ' between pins 1 and 3. PB3 is mounted in the U1 space between pins 6 and 8. ' ' While a training session is running, to increase the size of the pool press PB3. The current ' training session will be paused and the character group count reset. You will hear a bleep sound ' followed by the last letter in the new, larger character group sounded out in Morse. ' The training session will then restart. ' ' If you hold down PB3 you will hear a bleep followed by the new last character in the pool sounded ' out in Morse, incrementing over and over. When you hear the character you want to have as the ' new last character just let go of PB3. ' ' If you press PB2 the character pool size will be decreased with similar announcements. ' ' The total number of characters and prosigns in the entire Koch pool is 43, ordered in the following ' sequence. ' ' K M R S U A P T L O ' W I PERIOD N J E F 0 Y V ' COMMA G 5 / Q 9 Z H 3 8 ' B ? 4 2 7 C 1 D 6 X ' =(BT) *(SK) +(AR) ' ' ' ' When you press PB1, you will hear a bleep followed by the highest character in the current sized ' group, then the training session will start. ' ' Pressing PB1 while a training session is in progress will halt the session. You may have to hold ' down PB1 for a few seconds for this to happen, especially at the slower speeds. This puts you in ' the speed set mode and you will get the feedback of 7 Morse dits to confirm you have entered the ' mode. ' ' The characters are ALWAYS sent at fixed WPM rate. In the source code this is set at 17 WPM, but ' could be made higher by changing the value for "dit_length" in the constants section. The ' character speed table below equates the dit_length and character WPM values. ' ' In speed set mode, you can adjust the inter-character/inter-group delay, to give you and effective ' speed of between 5 WPM to 17 WPM, in roughly 1 WPM steps. There are in fact 13 steps altogether. ' Initially the delay is set at an effective WPM of about 8.5 WPM. Pressing PB3 will shorten the ' delay (higher WPM), and PB2 will lengthen the delay (lower WPM). The feedback for the change is ' provided as a high pitched beep, which is approximately one-half the actual delay length. This was ' done to make the speed change process less time consuming. Unfortunately there was not enough ' program memory to write code for saving and recalling the speed setting, but the essence of the ' Koch method ' ' When you are done setting the speed, press PB1 to start your training session. ' ' The Morse tone frequency is fixed at 604 Hz in the constants section. Change the value of ' "def_pitch" to another value if you wish. The pitch table below equates the pitch values ' with their frequency in Hz. ' ' ===================================================================== ' ' PICAXE 08M Chip Leg Assignments ' ------------------------------- ' ' ___ ' +5v--1-[o ]-8--GND ' SerIn--2-[ ]-7--SerOut/Out0 ' In4/Out4/ADC4--3-[08M]-6--In1/Out1/ADC1 ' In3/InfraIn--4-[___]-5--In2/Out2/ADC2 ' ' ' Hardware hookup for Koch Method Morse Trainer ' --------------------------------------------- ' ' ___ NOTE: ' +5v--1-[o ]-8--GND pin1, pin2, pin3 and pin4 are the program ' GND--2-[ ]-7--[1K ]-[LED]-GND names for the chip's physical connections. ' GND--[piezo]--3-[08M]-6----+ ' +--4-[___]-5--+ | ' | | | If you want to reprogram the 08M in the circuit, then ' +5v-[10K]--+ +5v-[10K]--+ +--[10K]-+5v the hardware requires standard minimum hookup for Serin ' | | | and Serout. See the PICAXE 08M docs in the PDF that ' ___ | ___ | | ___ comes with the the compiler for details. Otherwise ' GND--o o---+ GND--o o---+ +---o o--GND just connect leg 2 of the chip (Serin) to GND. ' [PB1] [PB2] [PB3] ' START/STOP DECREMENT INCREMENT ' TRAINING CHARACTER CHARACTER ' SESSION COUNT COUNT ' ' ================================================================================================== ' ' Character Keying Speeds Available ' --------------------------------- ' ' This table assumes the standard PARIS character timings. NOTE dit_length is in 10 mS units ' ' dah_length = 3 * dit_length ' element_delay (mS) = 10 * dit_length ' ' ' dit_length WPM dit_length WPM ' ---------- ---- ---------- ---- ' 2 68.2 17 8.0 ' 3 45.5 18 7.6 ' 4 34.1 19 7.2 ' 5 27.3 20 6.8 ' 6 22.7 21 6.5 ' 7 19.5 22 6.2 ' 8 17.0 23 5.9 ' 9 15.2 24 5.7 ' 10 13.6 25 5.5 ' 11 12.4 26 5.2 ' 12 11.4 27 5.1 ' 13 10.5 28 4.9 ' 14 9.7 ' 15 9.1 ' 16 8.5 ' ' ' =============================================================== ' ' ' Pitch table ' ----------- ' ' pitch_value Frequency Hz pitch_value Frequency Hz ' ----------- ------------ ----------- ------------ ' 67 199 92 336 ' 68 202 93 346 ' 69 205 94 357 ' 70 209 95 367 ' 71 213 96 379 ' 72 216 97 390 ' 73 221 98 404 ' 74 225 99 417 ' 75 229 100 433 ' 76 233 101 448 ' 77 238 102 466 ' 78 242 103 484 ' 79 247 104 503 ' 80 253 105 526 ' 81 258 106 549 ' 82 263 107 575 ' 83 269 108 604 ' 84 275 109 635 ' 85 282 110 671 ' 86 289 111 710 ' 87 296 112 754 ' 88 303 113 803 ' 89 310 114 861 ' 90 319 115 926 ' 91 328 116 1001 ' ' =============================================================== ' #picaxe 08m ' constants symbol def_pitch = 108 ' frequency used for dit and dah in sound command (108 = 604 Hz) symbol sound_pin = 4 ' pin use for sound output symbol morse_led = 0 ' pin that Morse LED is attached to for visual output symbol koch_num = 43 ' number of characters in Koch table ' symbol mode_set_speed = 0 symbol mode_play = 1 ' symbol dit_length = 8 ' dit length in 10mS units ( 8 = 80 mS = approx 17 WPM) symbol dah_length = 24 ' dah length in 10mS units (24 = 240 mS = approx 17 WPM) symbol element_delay = 80 ' inter-element delay in mS ( 80 mS = approx 17 WPM) symbol def_char_delay = 750 ' inter-character delay in mS ( 750 mS makes for approx 8.5 WPM) ' NOTE: morse_bits MUST be assigned b0 as bit7 is used symbol morse_bits = b0 ' w0 symbol morse_bit7 = bit7 symbol koch_index = b1 symbol startbit_flag = b2 ' w1 symbol bit_count = b3 symbol char_count = b4 ' w2 symbol koch_limit = b5 symbol mode = b6 ' w3 ' current mode symbol pitch = b7 ' symbol tmp = w4 symbol char_delay = w5 symbol random_word = w6 symbol random_byte0 = b12 symbol random_byte1 = b13 symbol PB_1 = pin1 symbol PB_2 = pin2 symbol PB_3 = pin3 ' read last character setting from EEPROM read 44,koch_limit let pitch = def_pitch let char_delay = def_char_delay '******************** play_loop: '******************** if PB_1 = 0 then let mode = mode xor 1 if mode = 0 then koch_index = 43 ' no character morse string - 7 dits goto start3 endif goto start2 end if branch mode,(set_speed,start) #rem '******************** set_tone: '******************** if PB_3 = 0 then pitch = pitch + 1 'max 120 elseif PB_2 = 0 then pitch = pitch - 1 'min 67 endif goto play_loop #endrem '******************** set_speed: '******************** '#rem if PB_3 = 0 then char_delay = char_delay - 100 min 200 ' 200 = 17 wpm effective speed with dit_length = 8 elseif PB_2 = 0 then char_delay = char_delay + 100 max 1500 ' 1500 = 5 wpm effective speed with dit_length = 8 else goto play_loop endif tmp = char_delay / 20 sound sound_pin,(118,tmp,0,50) '#endrem goto play_loop '******************** start: '******************** if PB_2 = 0 or PB_3 = 0 then if PB_3 = 0 then koch_limit = koch_limit + 1 max koch_num elseif PB_2 = 0 then koch_limit = koch_limit - 1 min 2 endif ' save last character setting to EEPROM write 44,koch_limit '******************** start2: '******************** koch_index = koch_limit - 1 '******************** start3: '******************** sound sound_pin,(120,30,0,30) gosub koch_morse_out ' announce the highest character in the Koch table that will be used if PB_2 = 0 or PB_3 = 0 then start goto start_delay endif random random_word if mode != mode_play then play_loop ' pick from first koch_limit characters in the Koch table 'koch_index = random_byte0 or random_byte1 // koch_limit koch_index = random_byte0 // koch_limit 'koch_index = random_byte1 // koch_limit gosub koch_morse_out inc char_count if char_count = 5 then '******************** start_delay: '******************** char_count = 0 tmp = char_delay * 3 pause tmp endif goto play_loop '******************** koch_morse_out: ' gosub ' enter with koch_index set to character table index (0-42) '******************** ' Get Morse bit pattern. koch_index contains 0-42 which points to character in table, ' morse_bits contains Morse bit pattern. ' First 1=start bit, then 1=dit and 0=dah, read bit7 through bit0. read koch_index,morse_bits ' if morse_bits = 0 then out '******************** morse_out: ' gosub ' enter with morse_bits set to character bits to output '******************** 'Play Morse Letter - morse_bits contains the Morse bit pattern let bit_count = 8 ' initialize the bit counter let startbit_flag = 0 ' initialize startbit found flag ' find the start bit and play Morse character '******************** nextbit: '******************** if morse_bit7 = 1 and startbit_flag = 0 then let startbit_flag = 1 ' set the start bit flag goto skip endif if startbit_flag = 0 then skip ' still looking for start bit low morse_led ' turn morse LED on if morse_bit7 = 1 then ' output element of Morse bit pattern sound sound_pin,(pitch,dit_length) else sound sound_pin,(pitch,dah_length) endif high morse_led ' turn morse LED off pause element_delay ' inter-element delay '******************** skip: '******************** dec bit_count ' can only process 8 bits if bit_count = 0 then out let morse_bits = morse_bits * 2 ' shift left to see next Morse bit goto nextbit '******************** out: '******************** pause char_delay return ' preload Morse bit patterns lookup table in Koch training order into EEPROM ' There are 43 entries in the table, so valid koch_index range = 0 to 42. ' ' (NOTE: the eeprom commands (without the location parameter) are cumulative so you can ' the source look nicer by not having the whole table on one line.) ' K M R S U A P T L O eeprom 0,(%1010,%100,%1101,%1111,%1110,%110,%11001,%10,%11011,%1000) ' W I PERIOD N J E F 0 Y V eeprom (%1100,%111,%1101010,%101,%11000,%11,%11101,%100000,%10100,%11110) ' COMMA G 5 / Q 9 Z H 3 8 eeprom (%1001100,%1001,%111111,%101101,%10010,%100001,%10011,%11111,%111100,%100011) ' B ? 4 2 7 C 1 D 6 X eeprom (%10111,%1110011,%111110,%111000,%100111,%10101,%110000,%1011,%101111,%10110) ' = (BT) * (SK) + (AR) eeprom (%101110,%1111010,%110101) ' Special signal character - 7 dits eeprom 43,(%11111111) ' koch_limit eeprom 44,(2)