Morse Code.

I just got my arduino (counterfeit..more on that in a new thread...) today!

i've got a few projects in mind, but i dont have any of the parts yet :frowning:

so i wanted to play around, to see how much my knowledge of Java and C++ would help me here.

Also, my projects will all involve serial communications with a PC, so knowing how to do this is going to be very important!


So lets get to it, shall we?

I wanted to go above and beyond the hello world (pin 13 LED). So i wrote this.

I call it BlinkSoS. Or blink sauce.

Basically, it listens for new serial packets then if they are any of the standard 26 letters it will blink led 13 as if it were a morse code signaler.

there isint much to it (you dont even have to build a circuit!)

The code is attached below. But for now, can i get some feedback / commentary / criticisms on my code / coding style.. etc?

i want to become a more efficient programmer, so if you guys see ways i can trim the fat, please let me know!

/* 
 BlinkSos.  Goes great on waffles...Mmmm...
 
 A stimple test of serial and LED.  since i dont have *any* other componenets to play with right now :/
 
 */


// SETUP

int ledPin = 13; // The defaults
int Long = 700; // 70% of a second for a —
int Short = 200; // 30% of a second for a · (dot)
int incomingByte = 0;


// Mmm.  constructors :)
void setup(){
  pinMode(ledPin, OUTPUT); // Duh.
  Serial.begin(9600);  // Yeah, i'd say this is important.
  Serial.flush();
}

void blink(int L){
  digitalWrite(ledPin, LOW);    // set the LED off incase it wasnt.
  delay(100);

  digitalWrite(ledPin, HIGH);   // set the LED on
  delay(L);                  // wait for l/100 of a second
  digitalWrite(ledPin, LOW);    // set the LED off 
}

void charBlink(int c){

  switch (c) {
  case 65:
    blink(Short);
    blink(Long);
    return;

  case 66:
    blink(Long);
    blink(Short);
    blink(Short);
    blink(Short);
    return;

  case 67:
    blink(Long);
    blink(Short);
    blink(Long);
    blink(Short);
    return;

  case 68:
    blink(Long);
    blink(Short);
    blink(Short);
    return;

  case 69:
    blink(Short);

  case 70:
    blink(Short);
    blink(Short);
    blink(Long);
    blink(Short);
    return;

  case 71:
    blink(Long);
    blink(Long);
    blink(Short);
    return;

  case 72:
    blink(Short);
    blink(Short);
    blink(Short);
    blink(Short);
    return;

  case 73:
    blink(Short);
    blink(Short);
    return;

  case 74:
    blink(Short);
    blink(Long);
    blink(Long);
    blink(Long);
    return;

  case 75:
    blink(Long);
    blink(Short);
    blink(Long);
    return;

  case 76:
    blink(Short);
    blink(Long);
    blink(Short);
    blink(Short);
    return;

  case 77:
    blink(Long);
    blink(Long);
    return;

  case 78:
    blink(Long);
    blink(Short);
    return;    

  case 79:
    blink(Long);
    blink(Long);
    blink(Long);
    return;

  case 80:
    blink(Short);
    blink(Long);
    blink(Long);
    blink(Short);
    return;

  case 81:
    blink(Long);
    blink(Long);
    blink(Short);
    blink(Long);
    return;

  case 82:
    blink(Short);
    blink(Long);
    blink(Short);
    return;

  case 83:
    blink(Short);
    blink(Short);
    blink(Short);
    return;

  case 84:
    blink(Long);
    return;

  case 85:
    blink(Short);
    blink(Short);
    blink(Long);
    return;

  case 86:
    blink(Short);
    blink(Short);
    blink(Short);
    blink(Long);
    return;

  case 87:
    blink(Short);
    blink(Long);
    blink(Long);
    return;

  case 88:
    blink(Long);
    blink(Short);
    blink(Short);
    blink(Long);
    return;

  case 89:
    blink(Long);
    blink(Short);
    blink(Long);
    blink(Long);
    return;

  case 90:
    blink(Long);
    blink(Long);
    blink(Short);
    blink(Short);
    return;

  default: 
    Serial.print("Sorry, i didn't recognize that character "); 
    Serial.println(c);
  }

}

void header(){
  Serial.println("Welcome to BlinkSos.");
  // more will go here!
}


void loop()                     
{

  //  header();
  //  Serial.println("What character would you like me to put in morese code for you?");
  //  Serial.println("Please enter a character: ");

  // we must make sure we have data available!
  if (Serial.available() > 0) {
    // read the incoming byte:
    incomingByte = Serial.read();

    // say what you got:
    Serial.print("I received: ");
    Serial.println(incomingByte, DEC);

    charBlink(incomingByte);
    Serial.println("DONE BLINKING THAT CHARACTER");
    delay(400); // wait a second before going on to our next character.
  }

}

For what it's worth, if you want to show real Morse code:- a dit is your basic unit of timing. A dah is supposed to be three times the length of a dit.

  • Between each dit or dah in a letter, a dits worth of silence is observed.
  • After each letter, three dits of silence is observed.
  • After each word, seven dits of silence is observed although older Morse Code operators
    use five. Current school of thought is seven.
  • The length of a dit is determined by the speed, or words per minute, that you intend to send at.
    t_dit = 1200/wpm;when using seven dits between words.
    For five dits use:
t_dit = 1250/wpm;

t_dit will be in units of milliseconds, just right for delay().

When you get done flashing LEDs, try using the tone() function with a
piezo speaker! 600 Hz is a good pitch for Morse Code.

Programming-wise: Don't write so much code, like your loooonng switch()
statement, when you can build a data structure to control your code. In
other words, create an array with two pieces of data in each element --
the sequence of dits and dahs, and how many dits/dahs are to be used
for each letter. Let a zero bit represent a dit and a 1 represent a dah.
Let your code select the data element you need per the character input.
Next have your code loop over the data element selected to decide to
display a dit or a dah. End result is that code might be a little more
complex but it will be much shorted and easier to work on.

73 de AE5AE

I posted this: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1274292639/12#10 only yesterday. I haven't tested it, but it shouldn't take long to get working.

I'm no Morse expert, but this demonstrates character coding, and also handles numerals and digraphs.

One comment about your "switch/case" - to make it more readable, include the character itself as the constant - we don't all carry a round an ASCII chart! Instead of case 97: use case 'a':

Others: "ledPin" is probably a constant (you're not going to change the LED during running), so declare it as one:const byte ledPin = 13;
and "incomingByte" is only referenced inside "loop", so it doesn't need global scope, you could even declare it thusly:

if (Serial.available() > 0) {
    // read the incoming byte:
    int incomingByte = Serial.read();

@Groove. i tried that.

but i couldnt figure out how to convert the ascii numerical value back into a char. i looked around at the atoi() function, but couldnt find it documented very well.

@ Rusty in Texas:

wow. i had no idea there was so much to it :/.

i'll go back and change the timing to be 'proper' :slight_smile:

I like your arrays idea, i'll look into that!

(see, this is why i posed... thanks for the help/feedback!)

Ok, i need your help again.

How can i take a series of bytes and turn them into a single int?

As of now, i have my program asking the user for how many words per min they want to send at, and they enter some number like 128. as my program is now, this will be read as 3 separate bytes! this is no good, i need the byte 1 the byte 2 and the byte 8 to be read as one and converted into a single integer.

relevant code below

void timing(){
  Serial.println("Before transmission, we must establish a few things.  How many Words Per Min would you like to send at?");
  Serial.println("Enter the number fo Words Per Min : ");
  while(Serial.available() <=0){
    // do *nothing*
  }

  //as soon as we have serial data
  if(Serial.available() >0){
    wordsPM = Serial.read() - '0';    
  }

  // set us up our timings
  Short = (1200/wordsPM);
  Long = (3*Short);

... etc.

Thanks!

i looked around at the atoi() function, but couldnt find it documented very well.

http://www.lmgtfy.com/?q=atoi

this is no good, i need the byte 1 the byte 2 and the byte 8 to be read as one and converted into a single integer

This comes up at least once a week on this forum. Did you use the search facilities?

Oh how helpful, someone asks for help and is sent to google. If all you want to do is crap on people why are you here?

atoi sucks for beginners

A simple implementation and an equally simple C++ test driver 'main'

#include <cmath>
#include <iostream>

// psz  - null terminated buffer of ascii numerals

int ascii_to_int(const char* psz)
{
    int     value   = 0;
    size_t  cch     = strlen(psz);
    while ( cch-- )
    {
        value += ((*psz++ - '0') * pow(10, cch));
    }
    
    return value;
}

int main(int argc, const char* argv[])
{
    const char  buffer[4] = { '1', '2', '0', 0 };
    std::cout << ascii_to_int(buffer) << std::endl;

    return 0;
}
/* =============================================================================
 * File - morse.pde
 * -----------------------------------------------------------------------------
 * Code formatted assuming 80 characters screen width
 *
 * Naming Convention
 *  e_      enumeration
 *  g_      global
 *  k_      constant
 *
 *  dt      delta time
 */


/* =============================================================================
 * -----------------------------------------------------------------------------
 */

#include "WProgram.h"

#include <ctype.h>


/* =============================================================================
 * -----------------------------------------------------------------------------
 */

struct encoding_t
{
    const char              ascii;
    const unsigned short    encoding;
};


/* =============================================================================
 * -----------------------------------------------------------------------------
 */

enum { e_EOS = 0, e_DOT, e_DASH, eMASK };


/* =============================================================================
 * -----------------------------------------------------------------------------
 */

static const encoding_t  morse_encodings[] =
{
    // a string of 2-bit values encode the morse sequence, LSb -> MSb
    // 00   end-of-sequence
    // 01   '.'
    // 10   '-'
    // 11   unused

    
    // --- Numeric
      { '0',    0x02AA }    // "-----"
    , { '1',    0x02A9 }    // ".----"
    , { '2',    0x02A5 }    // "..---"
    , { '3',    0x0295 }    // "...--"
    , { '4',    0x0255 }    // "....-"
    , { '5',    0x0155 }    // "....."
    , { '6',    0x0156 }    // "-...."
    , { '7',    0x015A }    // "--..."
    , { '8',    0x016A }    // "---.."
    , { '9',    0x01AA }    // "----."
    
    // --- Alphabetic
    , { 'A',    0x0009 }    // ".-"
    , { 'B',    0x0056 }    // "-..."
    , { 'C',    0x0066 }    // "-.-."
    , { 'D',    0x0016 }    // "-.."
    , { 'E',    0x0001 }    // "."
    , { 'F',    0x0065 }    // "..-."
    , { 'G',    0x001A }    // "--."
    , { 'H',    0x0055 }    // "...."
    , { 'I',    0x0005 }    // ".."
    , { 'J',    0x00A9 }    // ".---"
    , { 'K',    0x0026 }    // "-.-"
    , { 'L',    0x0059 }    // ".-.."
    , { 'M',    0x000A }    // "--"
    , { 'N',    0x0006 }    // "-."
    , { 'O',    0x002A }    // "---"
    , { 'P',    0x0069 }    // ".--."
    , { 'Q',    0x009A }    // "--.-"
    , { 'R',    0x0019 }    // ".-."
    , { 'S',    0x0015 }    // "..."
    , { 'T',    0x0002 }    // "-"
    , { 'U',    0x0025 }    // "..-"
    , { 'V',    0x0095 }    // "...-"
    , { 'W',    0x0029 }    // ".--"
    , { 'X',    0x0096 }    // "-..-"
    , { 'W',    0x00A6 }    // "-.--"
    , { 'Z',    0x005A }    // "--.."
    
    // --- Punctuation
    , { ',',    0x0A5A }    // "--..--"
    , { '.',    0x0999 }    // ".-.-.-"
    , { ':',    0x056A }    // "---..."
    , { '?',    0x05A5 }    // "..--.."
    , { '-',    0x0956 }    // "-....-"
    , { '/',    0x0196 }    // "-..-."
    , { '(',    0x09A6 }    // "-.--.-"
    , { ')',    0x09A6 }    // "-.--.-"
    
    // --- ARDUINO Windows IDE has problems with escaped ascii literals!
#if 0
    , { '\'',   0x06A9 }    // ".----."
    , { '\"',   0x0699 }    // ".-.--."
#endif
};

const int pin = 13;


/* =============================================================================
 * -----------------------------------------------------------------------------
 */

int g_dtDot;
int g_dtDash;
int g_dtChar;
int g_dtWord;


/* =============================================================================
 * -----------------------------------------------------------------------------
 */

static void dot()
{
    digitalWrite(pin, HIGH);
    delay(g_dtDot);
    
    digitalWrite(pin, LOW);
}


/* =============================================================================
 * -----------------------------------------------------------------------------
 */

static void dash()
{
    digitalWrite(pin, HIGH);
    delay(g_dtDash);
    
    digitalWrite(pin, LOW);
}


/* =============================================================================
 * -----------------------------------------------------------------------------
 */

static void blinkSequence(unsigned short encoding)
{
    do
    {
        switch ( encoding bitand eMASK )
        {
            case e_DOT: dot();      break;
            case e_DASH:dash();     break;
            default:                break;
        }
        
        encoding >>= 2;

        if ( encoding ) { delay(g_dtDot); }

    } while ( e_EOS != (encoding bitand eMASK) );
}


/* =============================================================================
 * -----------------------------------------------------------------------------
 */

static void blinkCharactor(char ch)
{
    const int cEntries = sizeof(morse_encodings) / sizeof(morse_encodings[0]);
    
    for ( int i = 0; i < cEntries; i++)
    {
        if ( ch == morse_encodings[i].ascii )
        {
            blinkSequence(morse_encodings[i].encoding);
            return;
        }
    }
}


/* =============================================================================
 * -----------------------------------------------------------------------------
 */

void setTimings(int dt)
{
    g_dtDot     = dt;
    g_dtDash    = 3 * dt;
    g_dtChar    = 3 * dt;
    g_dtWord    = 7 * dt;
}


/* =============================================================================
 * -----------------------------------------------------------------------------
 * Any speed greater than 10-15 words per minute will be hard to read on an LED
 */

void setSpeedWordsPerMinute(int wpm)
{
#define WPM_MAX     (150)
    
    const unsigned long k_MPM           = (60 * 1000);  // millisec's per minute
    
    const unsigned long k_DOT           = 1;
    const unsigned long k_DASH          = 3;
    const unsigned long k_INTRA_SEQ     = 1;
    const unsigned long k_INTRA_CHAR    = 1;
    
    const char          standard[]      = { "PARIS" };
    
    // --- check and enforce words per minute boundries

    if ( wpm < 1 )          { wpm  = 1; }
    if ( wpm > WPM_MAX )    { wpm  = WPM_MAX; }
    

    // --- count 'dot' length of 'standard' word

    const char*         ptr = standard;
    unsigned long       dpw = 0;            // 'dot's per word
    char                ch;
    while ( ch = *ptr++ )
    {
        const int cEntries = sizeof(morse_encodings) / sizeof(morse_encodings[0]);
        
        for ( int i = 0; i < cEntries; i++)
        {
            if ( ch == morse_encodings[i].ascii )
            {
                unsigned short  encoding    = morse_encodings[i].encoding;
                
                do
                {
                    switch ( encoding bitand eMASK )
                    {
                        case e_DOT:     dpw += k_DOT;   break;
                        case e_DASH:    dpw += k_DASH;  break;
                        default:                        break;
                    }

                    encoding >>= 2;

                    if ( encoding ) { dpw += k_INTRA_SEQ; }

                } while ( e_EOS != (encoding bitand eMASK) );
            }
        }
        
        if ( *ptr ) { dpw += k_INTRA_CHAR; }
    }
    
    setTimings(k_MPM / (wpm * dpw));
}


/* =============================================================================
 * -----------------------------------------------------------------------------
 */

void loop()
{
    const char      message[]   = { "ARDUINO ROCKS" };
    const char*     ptr         = message;
    
    char            ch;
    while ( ch = *ptr++ )
    {
        blinkCharactor(((isalpha(ch)) ? toupper(ch) : ch));
        delay(((' ' == *ptr) ? g_dtWord : g_dtChar));
    }
    
    // 3 SECONDS
    const int   dtMessageDelay = (3 * 1000);
    delay(dtMessageDelay);
}


/* =============================================================================
 * -----------------------------------------------------------------------------
 */

void setup()
{
    pinMode(ledPin, OUTPUT);

    setSpeedWordsPerMinute(25);
}

wow, thanks for the examples / help! I've been really busy these past few days, but i hope to get back to the arduino in the next day or two.

I'll be sure to go back through your examples and pick them apart and incorporate parts of them into my original sample program.

If you do so I'd really like to see your resulting source posted back here.

Have fun!

I made some of the suggested improvements, uploaded to my arduino and then put my development stuff away.

I think i forgot to save the changes, because the code i have doesn't match some of the changes i remember making.

Blegh. not sure what happened, but the code i have saved doesn't work as it would as it used to.

So i am sorry to those who had hoped to see me implement some of the above mentioned changes, but the good news is that ive got a new project (much more involved!) coming very soon.

Lloydean,

Really like your coding style, very nice! I've been looking into this as a general output method for a remotely controlled ham station. Your code definitely helps! I will have to post back here when I get a little further along.

Well I'm glad somebody will get some use out of it!

I did it for a friend who does embedded development in assembly only and recently decided to learn C/C++.

As his first application on a new platform is always a morse code generator I chose to do this as an example of C/C++ for him to learn from.

I hope you will post whatever yo come up with as well.

Enjoy!

-.-. --- --- .-.. :smiley: