KG6HAF

Embedded Morse

This site will look much better in a browser that supports web standards, but it is accessible to any browser or Internet device.

Home ]
Kenwood 520S ]
Station Log ]
Beacon Program ]
CW Interface ]
EV Charger ]
Station Log Software ]
History ]
KG6HAF Logo
Home ] [ Kenwood 520S ] [ Station Log ] [ Beacon Program ] [ CW Interface ] [ EV Charger ] [ Station Log Software ] [ History ] 

Using Morse Code to Signal From Embedded Systems

In my day job, I do work with embedded systems. Often these systems, especially non-debug versions, don't have any UI at all, perhaps just a single LED that can be flashed or a speaker that can be beeped.

Luckily, as Hams, we can use such a "one bit channel" to send morse code. I have found this invaluable for sending myself short (3-6 letter) error codes when exceptional conditions occur.

The C code below implements such a system. Just #define the macros DELAY_MS (for millisecond delays on your platform), and LED_ON and LED_OFF (or change to BEEP_ON, BEEP_OFF, etc) and you're all set.

These routines will play messages with capital letters (no lower case, numbers or prosigns). In the interest of space, I don't even check the input, so be careful. You'll also notice I also stretched the correct PARIS letter timing a little as I found the slowness of LED switching made decoding the message difficult unless I did this. You might want to experiement here.

Hope you find this useful. Good luck with your projects.


//
// Playing Morse Code on an LED
//
#define DWORD unsigned long    /* Set this up as appropriate for your platform */
#define BYTE unsigned char     /* Set this up as appropriate for your platform */

// Character Data Table
//   high nibble is element count (number of dits and dahs in the character)
//   low nibble is reversed bit pattern for char with 1 == dah, 0 == dit
static const BYTE morse_data[26] =
{ 0x22,0x41,0x45,0x31,0x10,0x44,0x33,0x40,0x20,0x4E,
  0x35,0x42,0x23,0x21,0x37,0x46,0x4B,0x32,0x30,0x11,
  0x34,0x48,0x36,0x49,0x4D,0x43 
};

// Timings
#define WPM       13
#define T_MS_UNIT ((DWORD) ( 1200UL / WPM ))
#define T_DIT     ( T_MS_UNIT * 1 )
#define T_DAH     ( T_MS_UNIT * 3 )

#define T_INTRA   ( T_MS_UNIT * 1 + ( T_MS_UNIT >> 1 ))     /* stretch by 1/2 unit */
#define T_LETTER  ( T_MS_UNIT * 3 + ( T_MS_UNIT * .075 ))   /* stretch by 7.5%, think I meant to do 3/4! */
#define T_SPACE   ( T_MS_UNIT * 7 + ( T_MS_UNIT >> 1 ))     /* stretch by 1/2 unit */

static void morse_char_play( const char c )
{
    const BYTE byProgram = morse_data[ c - 'A' ];
    const BYTE nLen = ( byProgram >> 4 );   // char length in high nibble
    BYTE mask;
    BYTE ii;

    for( mask = 1, ii = 0 ; ii < nLen ; ii++, mask <<= 1 )
    {
        if ( ii != 0 )
            DELAY_MS( T_INTRA );
        LED_ON();
        DELAY_MS( ( mask & byProgram ) ? T_DAH : T_DIT ); 
        LED_OFF();
    }
}

static void morse_string_play( const char * psz )
{
    for( /**/ ; *psz ; psz++ )
    {
        if ( *psz == ' ' )
            DELAY_MS( T_SPACE );            
        else
        {
            morse_char_play( *psz );
            DELAY_MS( T_LETTER );
        }
    }
}

void morseStop( const char * psz ) 
{
    // Play string infinitely on LED in morse and stop app
    // Maybe turn of interrupts or call debugger here in debug builds

    while( 1 )
    {
        morse_string_play( psz );
        DELAY_MS( T_SPACE * 2 );
    }
}

void morsePlay( const char * psz )
{
    morse_string_play( psz );
}

// You can setup up a "halt" macro:

#define HLT( M ) morseStop( M )

Updated 02 Nov 09