' Random Morse code generator (actually, pseudo random) ' David Gwillim, KB2TQX (kb2tqx at verizon.net) ' ' 13 March 2007 14:05 hrs ' ' Compiled size = 225 bytes no #define's used ' 226 bytes with #define LED_SINK ' 226 bytes with #define TEST_PITCH ' ' =============================================================== ' ' 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 Random Morse Generator ' ------------------------------------------ ' ' ___ 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--+ | ' | | | Hardware requires standard minimum hookup for Serin ' +5v-[10K]--+ +5v-[10K]--+ +--[10K]-+5v and Serout, if you want to reprogram the 08M in the ' | | | the circuit. 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. ' "A" "N" "L" ' ' Press button "L" plays A-Z Morse characters randomly selected (10 groups of 5 characters) ' Press button "N" plays 0-9 Morse characters " " " " ' Press button "A" plays ALL Morse characters " " " " ' ' Push buttons must be held down for about 0.5 seconds, until you hear the ' feedback chirp to start play. ' ' Durinf play, pressing any push button until the feedback chirp is heard ' will cancel play. ' ' The optional LED attached to pin0 (leg 7) of the 08M will flash in time ' with the Morse output. If you plan on programming the 08M in your final ' circuit, you will need to have a jumper and 3-pin header to switch between ' the connection to the SerOut circuitry to the PC and the 1K+LED. This is ' already there on the PH Anderson 08M development board. ' ' NOTE: You can change the number of groups sent and the size of a group ' in the "constants" section of the source code below. ' ' =============================================================== ' ' Speed setting calculations ' --------------------------. ' ' Standard speed in WPM is based on the famous PARIS word. ' ' .^_^_^.^^^.^_^^^.^_^.^^^.^.^^^.^.^.^^^^^^^^^ = 44 dit sized elements ' ' including the inter-element, inter-character and inter-word spaces. ' ' 20 "words" would then be 20*44 = 880 dit sized elements. So for 20 WPM ' this would equate to 60000/880 = 68.2 mS per dit. ' ' ******* ' FORMULA: WPM = 60000/(dit_length * 440) ' ******* ' ' The SOUND command uses 10mS increments, so 20 WPM should equate ' to a value of approximately 7. ' ' So a table of WPM speeds against dit_length for exact PARIS sending would be: ' ' ' dit_length WPM ' ---------- ---- ' 2 68.2 This table assumes the standard PARIS timing. NOTE dit_length is in 10 mS units ' 3 45.5 ' 4 34.1 dah_length = 3 * dit_length ' 5 27.3 element_delay (mS) = 10 * dit_length ' 6 22.7 char_delay (mS) = 3 * dit_length ' 7 19.5 word_delay (mS) = 9 * dit_length ' 8 17.0 ' 9 15.2 4.9 WPM 9.7 WPM 15.2 WPM 19.5 WPM:22.7 WPM 27.3 WPM 34.1 WPM ' 10 13.6 ------- ------- -------- -------- -------- -------- -------- ' 11 12.4 dit_length = 280 mS 140 mS 90 mS 70 mS 60 mS 50 mS 40 mS ' 12 11.4 element_delay = 280 mS 140 mS 90 mS 70 mS 60 mS 50 mS 40 mS ' 13 10.5 dah_length = 840 mS 420 mS 270 mS 210 mS 180 mS 150 mS 80 mS ' 14 9.7 char_delay = 840 mS 420 mS 270 mS 210 mS 180 mS 150 mS 80 mS ' 15 9.1 word_delay = 2520 mS 1260 mS 810 mS 630 mS 540 mS 450 mS 240 mS ' 16 8.5 ' 17 8.0 ' 18 7.6 ' 19 7.2 ' 20 6.8 ' 21 6.5 ' 22 6.2 ' 23 5.9 ' 24 5.7 ' 25 5.5 ' 26 5.2 ' 27 5.1 ' 28 4.9 ' ' ' Farnsworth Sending Computations ' ------------------------------- ' ' .^_^_^.#.^_#.^_^.#.^.#.^.^.### = 23 dit sized elements + 7 character space sized elements ' ' ******* ' FORMULA: Effective_WPM = 60000/(dit_length * 230 + char_delay * 7) ' ******* ' ' 15.2/4.9 = 7.5 EWPM 19.5/9.7 = 13.2 EWPM 27.3/9.7 = 14.7 EWPM ' -------------------- -------------------- -------------------- ' dit_length = 9 dit_length = 7 dit_length = 5 ' element_delay = 90 element_delay = 70 element_delay = 50 ' dah_length = 27 dah_length = 21 dah_length = 15 ' char_delay = 840 char_delay = 420 char_delay = 420 ' word_delay = 2520 word_delay = 1260 word_delay = 1260 ' ' ================================================================= ' ' ******* ' FORMULA: char_delay (mS) = ((60000/Effective_WPM) - dit_length * 230)/7 ' ******* ' ' Sample calculations: ' ' Effective_WPM desired=10 WPM, Character WPM selected = 15.2 (ditlength=9) ' char_delay = (60000/10 - 9*230)/7 = 561 mS. Then word_delay = char_delay*3 = 561*3 = 1683 ' ' Effective_WPM desired=5 WPM, Character WPM selected = 15.2 (ditlength=9) ' char_delay = (60000/5 - 9*230)/7 = 1419 mS. Then word_delay = char_delay*3 = 1419*3 = 4257 ' ' =============================================================== ' ' 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 ' ' =============================================================== ' ' Testing Pitch For Best Tone ' --------------------------- ' ' Uncomment the following #define for TEST_PITCH and instead of sending random ' characters, the program will send the string "PARIS" as Morse over and over. ' If PB_1 is pressed then pitch_value will be incremented, accompanied by a beep ' and the pitch_value will be sent to the PC via SerOut and the serial cable. ' If PB_2 is pressed then pitch_value will be decremented, accompanied by a beep ' and the pitch_value will be sent to the PC. ' ' If PB_1 or PB2 is held down, the Morse output loop will be skipped and the ' pitch_value will be incremented/decremented more quickly. ' ' Pressing PB_3 resets pitch_value to its start value of 67 (199 Hz).. ' ' In order to see the pitch_value sent to the PC, you should be running the terminal ' that is available under the PICAXE menu in the IDE. Set the baud rate to 4800 which ' is what PC communications uses. ' ' When it gets to 127, the next values (128 - 255) are white noise values which ' might work if you are using a piezo sounder disk to "hear with your fingers" ' (where a deaf person uses an unencapsulated piezo disk to feel the pulses). ' When pitch_value reaches 255 it will wrap around to 0 (silence) and then run ' through all values again. While TEST_PITCH is #define the LED code is disabled ' as pin0 is being used for serial communications with the PC, sending the pitch ' value to the terminal. Don't forget to have your jumper in the right position. ' '#define TEST_PITCH ' ' #picaxe 08m ' preload Morse bit patterns lookup table into EEPROM ' ' (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.) ' ! " # $ % & ' ( eeprom 0,(%01101100,%01101101,%00000000,%11110110,%00000000,%00000000,%01100001,%00101001) ' ) * + comma - period / 0 eeprom (%01010010,%00000000,%00110101,%01001100,%01011110,%01101010,%00101101,%00100000) ' 1 2 3 4 5 6 7 8 eeprom (%00110000,%00111000,%00111100,%00111110,%00111111,%00101111,%00100111,%00100011) ' 9 : ; < = > ? @ eeprom (%00100001,%01000111,%01010101,%00000000,%00101110,%00000000,%01110011,%01100101) ' A B C D E F G H eeprom (%00000110,%00010111,%00010101,%00001011,%00000011,%00011101,%00001001,%00011111) ' I J K L M N O P eeprom (%00000111,%00011000,%00001010,%00011011,%00000100,%00000101,%00001000,%00011001) ' Q R S T U V W X eeprom (%00010010,%00001101,%00001111,%00000010,%00001110,%00011110,%00001100,%00010110) ' Y Z [ \ ] ^ _ eeprom (%00010100,%00010011,%00000000,%00000000,%00000000,%0000000,%01110010) ' '#define LED_SINK ' if Morse LED connects to +5v instead of GND and Out0 sinks the current ' ' constants #ifndef TEST_PITCH symbol pitch_value = 108 ' frequency used for dit and dah in sound command (108 = 604 Hz) symbol group_size = 5 ' number of characters sent in each group symbol group_plays = 10 ' number of groups to play #else symbol group_size = 5 ' number of characters sent in each group #endif 'TEST_PITCH symbol sound_pin = 4 ' pin use for sound output symbol morse_led = 0 ' pin that Morse LED is attached to for visual output ' symbol ack_pitch1 = 118 ' 1st pitch of feedback sound when pressing a button symbol ack_pitch1_len = 8 ' length of above tone in 10mS units symbol ack_pitch2 = 120 ' 2nd pitch of feedback sound when pressing a button symbol ack_pitch2_len = 8 ' length of above tone in 10mS units symbol ack_delay = 100 ' delay after ack tones in 10mS units ' symbol dit_length = 7 ' dit length in 10mS units ( 7 = 90 mS = approx 20 WPM) symbol dah_length = 21 ' dah length in 10mS units (21 = 270 mS = approx 20 WPM) symbol element_delay = 70 ' inter-element delay in mS ( 70 mS = approx 20 WPM) symbol char_delay = 420 ' inter-character delay in mS ( 1419 mS makes for approx 5 WPM) symbol word_delay = 1260 ' inter-word delay in mS ( 4257 mS makes for approx 5 WPM) ' variables symbol PB_1 = pin1 ' push button 1 symbol PB_2 = pin2 ' push button 2 symbol PB_3 = pin3 ' push button 3 ' ' NOTE: morse_bits MUST be assigned b0 as bitN variables are used symbol morse_bits = b0 ' w0 symbol morse_bit7 = bit7 symbol ascii_char = b1 symbol char_count = b2 ' w1 symbol bit_count = b3 symbol startbit_flag = b4 ' w2 symbol char_group = b5 symbol new_group = b6 ' w3 symbol play_count = b7 #ifndef TEST_PITCH symbol buttons = b8 ' w4 #else 'TEST_PITCH symbol pitch_value = b8 ' w4 symbol msg_index = b9 symbol beep_wait = b10 ' w5 #endif 'TEST_PITCH symbol random_word = w6 symbol random_byte = b12 #ifdef TEST_PITCH let pitch_value = 67 let beep_wait = 24 #else 'TEST_PITCH #ifdef LED_SINK high morse_led #endif 'LED_SINK #endif 'TEST_PITCH '******************** play_loop: '******************** #ifndef TEST_PITCH ' check if PB_1, PB2 or PB_3 has been pressed #ifdef LED_SINK char_group = pins xor %00001111 ' when Out0 is used it looks like there's an In0 high #else 'LED_SINK char_group = pins xor %00001110 #endif 'LED_SINK ' if PB_1 was pressed then char_group = 2 (%00000010) ' if PB_2 was pressed then char_group = 4 (%00000100) ' if PB_3 was pressed then char_group = 8 (%00001000) if char_group = 0 then random random_word ' keep the random number generator "all shook up" nap 5 ' try and save a little power - sleep for ~0.5 seconds goto play_loop endif let play_count = group_plays goto beep #else 'TEST_PITCH if PB_1 = 0 then ' push button 1 pressed - pitch_value incremented inc pitch_value goto beep_tp endif if PB_2 = 0 then ' push button 2 pressed - pitch_value decremented dec pitch_value goto beep_tp endif if PB_3 = 0 then ' push button 3 pressed - pitch_value reset to 67 let pitch_value = 67 goto beep_tp endif goto continue '******************** beep_tp: '******************** sound sound_pin,(ack_pitch1,5,0,beep_wait) sertxd (#pitch_value,CR,LF) if PB_1 = 0 or PB_2 = 0 then ' if PB_1 or PB_2 is held down, skip Morse loop if beep_wait != 0 then let beep_wait = beep_wait - 2 ' speed up inc/dec loop endif goto play_loop endif let beep_wait = 24 #endif 'TEST_PITCH '******************** continue: '******************** #ifndef TEST_PITCH random random_word ascii_char = random_byte ' byte random variable = lower 8 bits of random_word if char_group = 2 then if ascii_char < "A" OR ascii_char > "Z" then check_play_count elseif char_group = 4 then if ascii_char < "0" OR ascii_char > "9" then check_play_count end if #else 'TEST_PITCH lookup msg_index,("PARIS"),ascii_char inc msg_index #endif 'TEST_PITCH ' Get Morse bit pattern. ascii_char contains ASCII, ' morse_bits contains Morse bit pattern. ' First 1=start bit, then 1=dit and 0=dah, read bit7 through bit0. if ascii_char >= "!" or ascii_char <= "Z" then let ascii_char = ascii_char - "!" read ascii_char,morse_bits else morse_bits = 0 end if if morse_bits = 0 then check_play_count 'Play Morse Letter - morse_bits contains the Morse bit pattern let bit_count = 0 ' 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 #ifndef TEST_PITCH #ifdef LED_SINK ' visual output ON low morse_led #else 'LED_SINK high morse_led #endif 'LED_SINK #endif 'TEST_PITCH if morse_bit7 = 1 then ' output element of Morse bit pattern sound sound_pin,(pitch_value,dit_length) else sound sound_pin,(pitch_value,dah_length) endif #ifndef TEST_PITCH #ifdef LED_SINK ' visual output OFF high morse_led #else 'LED_SINK low morse_led #endif 'LED_SINK #endif 'TEST_PITCH pause element_delay ' inter-element delay '******************** skip: '******************** inc bit_count ' can only process 8 bits if bit_count = 8 then out let morse_bit7 = 0 ' clear top bit let morse_bits = morse_bits * 2 ' shift left goto nextbit '******************** out: '******************** inc char_count if char_count = group_size then pause word_delay char_count = 0 dec play_count #ifdef TEST_PITCH msg_index = 0 #endif 'TEST_PITCH else pause char_delay end if #ifndef TEST_PITCH #ifdef LED_SINK buttons = pins xor %00001111 ' when pin0 used as LED output it shows up as a "high" pin0, ' even though it's NOT an input. Go figure! #else 'LED_SINK buttons = pins xor %00001110 ' mask In1, In2 and In3 attached to PB_1, PB_2 and PB_3 #endif 'LED_SINK if buttons != 0 then ' PB_1, PB_2 or PB_3 pressed play_count = 0 '******************** beep: '******************** ' the third tone (0) is silence. this is a sneaky way of generating ' a "pause nx10mS" without adding another line of code. sound sound_pin,(ack_pitch1,ack_pitch1_len,ack_pitch2,ack_pitch2_len,0,ack_delay) end if #endif 'TEST_PITCH '******************** check_play_count: '******************** #ifndef TEST_PITCH if play_count > 0 then continue ' we have more groups to send char_group = 0 #endif 'TEST_PITCH goto play_loop ' **************************************************** ' **************** END OF SOURCE CODE **************** ' ****************************************************