Simplified Morse Code ID/Beacon Generator 08M2

radiosparks

Member
The ease at which to program the PICAXE is truly astounding. I thought a Morse code generator would be a “NO BRAINER” but was caught off guard. There are so many different ways to create this type of code.

Most programs need the user to map the ASCII to a binary code to create the data string. “That hurt my head.” I just wanted to enter a string of ASCII and let the MCU handle the mapping.

This was cobbled together from some interesting snippets of code found by scanning around the forum and READING all things of interest.

QUOTE: mrburnette: “It is by evolving concepts and existing code bases that code evolution occurs”

Discovering new ways to optimize my code to fit in a restricted microcontroller environment, like the PICAXE, is helping me to become a better programmer.

The RC network you see on the breadboard acts as a low pass filter to remove the harmonics and is just to soften the harsh tone from the piezo transducer.

There is more than enough memory to add more features. All the code doesn't fit in the post see part 2.


Code:
#REM
-----------------------------------------------------------------------

    PICAXE-08M2 Simplified Morse Code Generator - rhb.20230913

     NOTE: Only alpha and numerals are used in this demonstration.
          Other characters included are commented out.

          This was to made to fit into an old 08M,
          which was the original CW IDer for my 1W QRP rig.

-----------------------------------------------------------------------

    NOTES: Physical Connections

        pin C.1 LED output, or TR key out with transistor (2N3904) driver
        pin C.2 SIDE-TONE output is a simple piezo speaker

-----------------------------------------------------------------------
    Morse Code Alphanumeric Character Encoding
-----------------------------------------------------------------------

    Each character to be generated is programmed as a number whose
    binary equivalent then generates Morse code.

    Test the MSB (Most Significant Bit) to represent dits and dahs.

     dot = dit = 0
    dash = dah = 1

    One (1) bit on the end of the Morse Character to detect a stop
    shifting left until the byte equals 128 ($80)

    Example Letter Conversion:

      k = -.-         Morse pattern
      k = 101         Replace dash and dots with binary 1 and 0
      k = 1011        Add 1 bit to end
      k = 10110000    Pad with 0 bits to make a 8 bit BYTE
      k = %10110000   Defined data as binary value
      k = $B0         Defined data as HEX value
      k = 176         Defined data as Decimal value

-----------------------------------------------------------------------
    Visual Table of Morse Code HEX Values
-----------------------------------------------------------------------

  ASCII             Shift-Left Code
  Letter   Morse    Binary       HEX

    A      .-       0110 0000    $60
    B      -...     1000 1000    $88
    C      -.-.     1010 1000    $A8
    D      -..      1001 0000    $90
    E      .        0100 0000    $40
    F      ..-.     0010 1000    $28
    G      --.      1101 0000    $D0
    H      ....     0000 1000    $08
    I      ..       0010 0000    $20
    J      .---     0111 1000    $78
    K      -.-      1011 0000    $B0
    L      .-..     0100 1000    $48
    M      --       1110 0000    $E0
    N      -.       1010 0000    $A0
    O      ---      1111 0000    $F0
    P      .--.     0110 1000    $68
    Q      --.-     1101 1000    $D8
    R      .-.      0101 0000    $50
    S      ...      0001 0000    $10
    T      -        1100 0000    $C0
    U      ..-      0011 0000    $30
    V      ...-     0001 1000    $18
    W      .--      0111 0000    $70
    X      -..-     1001 1000    $98
    Y      -.--     1011 1000    $B8
    Z      --..     1100 1000    $C8

-----------------------------------------------------------------------

  ASCII             Shift-Left Code
  Number   Morse    Binary       HEX

    0      -----    1111 1100    $FC
    1      .----    0111 1100    $7C
    2      ..---    0011 1100    $3C
    3      ...--    0001 1100    $1C
    4      ....-    0000 1100    $0C
    5      .....    0000 0100    $04
    6      -....    1000 0100    $84
    7      --...    1100 0100    $C4
    8      ---..    1110 0100    $E4
    9      ----.    1111 0100    $F4

-----------------------------------------------------------------------
    Punctuation
-----------------------------------------------------------------------

    e.g. (SK) Digraph are sent together without a character space

    word space           [space key]    1000 0000    $80
    exclamation mark (KW)[!]  -.-.--    1010 1110    $AE
    quotation mark       ["]  .-..-.    0100 1010    $4A
    hashtag              [#]
    dollar sign      (SX)[$]  ...-..-   0001 0011    $13
    percent              [%]
    ampersand        (AS)[&]  .-...     0100 0100    $44
    apostrophe           [']  .----.    0111 1010    $7A
    parenthesis open (KN)[(]  -.--.     1011 0100    $B4
    parenthesis closed   [)]  -.--.-    1011 0110    $B6
    asterisk             [*]
    plus             (RN)[+]  .-.-.     0101 0100    $54
    comma                [,]  --..--    1100 1110    $CE
    hyphen minus         [-]  -....-    1000 0110    $86
    full stop (period)   [.]  .-.-.-    0101 0110    $56
    forward slash    (DN)[/]  -..-.     1001 0100    $94

    colon                [:]  ---...    1110 0010    $E2
    semicolon            [;]  -.-.-.    1010 1010    $AA
    less than            [<]
    equal sign       (BT)[=]  -...-     1000 1100    $8C
    greater than         [>]
    question mark        [?]  ..--..    0011 0010    $32

    at-sign (commat) (AC)[@]  .--.-.    0110 1010    $6A
    underscore           [_]  ..--.-    0011 0110    $36

-----------------------------------------------------------------------
    Procedural
-----------------------------------------------------------------------

    Start of work        (CT)  -.-.-    1010 1010    $AA
    End of work          (SK)  ...-.-   0001 0110    $16

    Invitation to transmit (K)  -.-     1011 0000    $B0

    Invitation for a particular
    station to transmit
                         (KN)  -.--.    1011 0100    $B4

    End of message       (AR)  .-.-.    0101 0100    $54
    Wait                 (AS)  .-...    0100 0100    $44

    Understood           (SN)  ...-.    0001 0100    $14
    Error (8 dits)       (HH)  ........ 1111 1111    $FF

-----------------------------------------------------------------------
    Traditional Timing
-----------------------------------------------------------------------

           1 dit = 1 dit
           1 dah = 3 dits
    letter space = 3 dits
    word spacing = 7 dits

-----------------------------------------------------------------------
    Farnsworth Timing
-----------------------------------------------------------------------

    letter space = 9 dits
    word spacing = 21 dits

-----------------------------------------------------------------------

#ENDREM
PICAXE_08M2_Simplified_Morse_Code_Generator_20230823.JPG
 

radiosparks

Member
Code:
#REM
-----------------------------------------------------------------------

    PICAXE-08M2 Simplified Morse Code Generator - rhb.20230913

     NOTE: Only alpha and numerals are used in this demonstration.
          Other characters included are commented out.

          This was to made to fit into an old 08M,
          which was the original CW IDer for my 1W QRP rig.

-----------------------------------------------------------------------

    NOTES: Physical Connections

        pin C.1 LED output, or TR key out with transistor (2N3904) driver
        pin C.2 SIDE-TONE output is a simple piezo speaker
-----------------------------------------------------------------------
#ENDREM

#PICAXE 08M2

;#terminal 4800     ; Used only for Morse speed test ; remove to save bytes
;pause 3000         ; Used only for Morse speed test ; remove to save bytes

' ---------------------------------------------------------------------
'     Constants
' ---------------------------------------------------------------------

symbol        tone = 96                ; sets the tone frequency ( ~750 Hz )
symbol      silent = 0                 ; set silent tone (or QRSS tone 118/122)
symbol    dit_time = 9                 ; set length of a dot (mS) approx. ~12wpm
                                       ; tone timing and overhead of interpreted BASIC

symbol    dah_time = dit_time * 3      ; set length of a dash (3 dits)
symbol letter_time = dit_time * 3      ; set space between letters (3 dits)
symbol   word_time = dit_time * 7      ; set space between words (7 dits)
                                       ; NOTE:
                                       ; Because after each letter is a letter_time (3 dits),
                                       ; the actual word_time is (10 dits)

' ---------------------------------------------------------------------
'     Port Assignments
' ---------------------------------------------------------------------

symbol    LED_TR_OUT = c.1             ; LED output or TR key out
symbol SIDE_TONE_OUT = c.2             ; SIDE-TONE output is a simple piezo speaker

' ---------------------------------------------------------------------
'     Variables
' ---------------------------------------------------------------------

symbol    character = b0               ; BIT register for Morse Code character

symbol            i = b4               ; ASCII value from MESSAGE string
symbol            j = b5               ; pointer to ASCII character in MESSAGE string
symbol            k = b6               ; pointer Morse Code offset in defined string MORSE_A2Z

symbol            m = b7               ; use only for speed test ; remove or reuse variable
symbol            z = b8               ; use only for speed test ; remove or reuse variable

' ---------------------------------------------------------------------
'     MACRO Directives
' ---------------------------------------------------------------------

' STANDARD Message
#DEFINE MESSAGE_0 "CQ CQ CQ DX DE VE3XRM VE3XRM VE3XRM [ K"
' Note: The [ is an extended character to send End of message (AR)

' SPEED TEST - put in a loop and count how many in a minute
#DEFINE MESSAGE_2 "PARIS "

' PANGRAM Holoalphabetic Sentence
#DEFINE MESSAGE_Z "A QUICK BROWN FOX JUMPS OVER THE LAZY DOG 1234567890 "
#DEFINE MESSAGE_Y "ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789 "

#DEFINE MORSE_A2Z $80,$FC,$7C,$3C,$1C,$0C,$04,$84,$C4,$E4,$F4,$60,$88,$A8,$90,$40,$28,$D0,$08,$20,$78,$B0,$48,$E0,$A0,$F0,$68,$D8,$50,$10,$C0,$30,$18,$70,$98,$B8,$C8,$54

#MACRO SendMORSE( string )
    
    j = 0
    do
        lookup j, ( string, 0 ), i
        if i = 0 then exit
        call MORSE
    loop

#ENDMACRO

' ---------------------------------------------------------------------
'     Main Program Start
' ---------------------------------------------------------------------

MAIN:     

    ' e.g. Send Morse from a quoted string
    'SendMORSE("CQ CQ CQ DX DE VE3XRM VE3XRM VE3XRM AR K")
    
    #REM This is what is placed inline everytime you use SendMORSE()

        j = 0
        do
            lookup j, ( string, 0 ), i
            if i = 0 then exit
            call MORSE
        loop

    #ENDREM

    ' Send Morse from a pre-defined symbol
    'SendMORSE(MESSAGE_0)

    ' All letters and numbers
    'SendMORSE(MESSAGE_Y)

    ' Sample Morse Pangram
    SendMORSE(MESSAGE_Z)

    ' Used only to estimate PICAXE timing ; remove to save bytes
    ' call MORSE_SPEED_TEST

    ' IDer Timer - use with a short message as above e.g.
    'for i = 0 to 9     ; wait ten (10) minutes for next CW ID
    '    pause 60000    ; wait a minute, then repeat bacon message
    'next i

goto MAIN

'----------------------------------------------------------------------
'   Subroutines
'----------------------------------------------------------------------

MORSE_SPEED_TEST:  ' NOTE: remove subroutine to save bytes

    ' Morse Speed Test - Effect of increased clock speed

    ' The time function will increment
    ' at 4 MHz or 16 MHz once every second
    ' at 2 MHz and 8 MHz will be 2s
    ' at 32 MHz will be 0.5s

    ' e.g.
    ' 32 MHz     0.5s     
    ' 16 MHz     1s     
    ' 8  MHz     2s     
    ' 4  MHz     1s

    z = 0
    m = time + 60
    sertxd ("START: ", #time, CR, LF)
    do
        SendMORSE(MESSAGE_2)
        inc z
    loop until time > m
    sertxd ("END: ", #time, CR, LF)
    sertxd ("WPM: ", #z, CR, LF)

return

MORSE:

    if i = 32 then
        k = 0   
    elseif i < "A" then     ; maybe a number if less than 65
        k = i - 47          ; i - 48 + 1 calc offset to numbers
    else   
        k = i - 54          ; calc offset to letters
    end if

    lookup k, ( MORSE_A2Z ), character

    if character = $80 then
        gosub word_space
    else
        do until character = $80

            ' Testing a bit is equivalent to
            ' bit_value = character & %10000000 ; mask left most bit to test
            ' Then Test MSB of element
            ' if bit_value = $80 then
            ' character variable must be in one of the bit registers - here using b0

            if bit7 = 1 then
                gosub dah       ; if bit 1 do dah sub-routine
            else
                gosub dit       ; else it's 0 do dit sub-routine
            endif

            ' Left shift on all the bits in character.
            ' 08M & 08M2 doesn't have a shift function.

            'character = character * 2           ; multiply shift
            character = character + character    ; addition shift

        loop
        gosub char_space
    end if

    inc j    ; same as j = j + 1 ; inc counter to point at next character

return

dit:
    high LED_TR_OUT
    sound SIDE_TONE_OUT,(tone,dit_time)       ; sound tone for dit length
    low LED_TR_OUT
    sound SIDE_TONE_OUT,(silent,dit_time)     ; silence for dit length
return

dah:
    high LED_TR_OUT
    sound SIDE_TONE_OUT,(tone,dah_time)       ; sound tone for dah length
    low LED_TR_OUT
    sound SIDE_TONE_OUT,(silent,dit_time)     ; silence for dit length
return

char_space:
    sound SIDE_TONE_OUT,(silent,letter_time)  ; send silence for dah length after char completely sent
return

word_space:
    sound SIDE_TONE_OUT,(silent,word_time)     ; send silence for break between words
return

'----------------------------------------------------------------------
;EOF;
 
Last edited:

hippy

Technical Support
Staff member
Excellent. When it comes to optimising ...
Code:
MORSE:

    if i = 32 then
        k = 0  
    elseif i < "A" then     ; maybe a number if less than 65
        k = i - 47          ; i - 48 + 1 calc offset to numbers
    else  
        k = i - 54          ; calc offset to letters
    end if

    lookup k, ( MORSE_A2Z ), character
Where 'i' is an ASCII character value, you can use DATA definitions and compact that down to a simple -
Code:
MORSE:
  Read i, character
The nice thing about that is it allows the correlation of ASCII to Morse to be more easily defined, such as -
Code:
Data "A" , ( %01100000 ) ;  .-
That can also make it easier to define non A-Z ones like -
Code:
Data "," , ( %11001110 ) ; --..--    comma
Data "-" , ( %10000110 ) ; -....-    hyphen minus
The DATA will sort out the charcater ordering automatically so you don't need to know ASCII values for characters. That is "," can come before or after "-" in the above and it it will still work out right.
 
Top