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