Pages: [1] 2   Go Down
Author Topic: morse code flasher - lookup table question  (Read 2367 times)
0 Members and 1 Guest are viewing this topic.
Texas
Offline Offline
Newbie
*
Karma: 0
Posts: 8
KE5CPU
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Disclaimer:  Ok.  It's been a while since college programming classes and although coding used to be my "thing", I've forgotten quite a bit.

I've seen the various morse code flashers, but none like I want.  I want to be able to hard code a message into a string or feed it via serial interface, then have the Arduino lookup each character and flash an LED appropriately.  For example, if the text is "Hello", the Arduino should lookup "H" in a lookup table and execute "dot dot dot dot".  For "e" is should find "0" and execute "dash". 

My trouble is the actual two-dimensional array.  The first element in each set is a single character or digit.  The second, corresponding, element is 1 to 4 binary digits.  A zero indicates a morse code "dot" and a 1 indicates a "dash".  So...

[pseudocode]

LED is set as an OUTPUT on pin 13.

MyString="Hello"

dot {
  digitalWrite(OUTPUT, high);
  delay(500);                            //holding LED high for this count; dots are half as long as dashes
  digitalWrite(OUTPUT, low);
}

dash {
  digitalWrite(OUTPUT, high);
  delay(1000);                          //holding LED high for this count
  digitalWrite(OUTPUT, low);
}

lookup_table[][] =
  A=01
  B=1000
  C=1010
  D=100
  E=0
  F=0010
  G=110
  H=0000
  I=00
  J=0111
  K=101
  L=0100
  M=11
  N=10
  O=111
  P=0110
  ...

FOR loop to iterate thru the characters and send a respective dot or dash to LED.

[/pseudocode]
[/color]

If I remember correctly, an array in C can't be of multiple types, correct or not?  If I'm correct, how should I tackle the lookup table?

Thanks in advance for any help!
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
If I remember correctly, an array in C can't be of multiple types, correct or not?
Correct. However an array of struct instances can be used to do what you want.
Logged

Texas
Offline Offline
Newbie
*
Karma: 0
Posts: 8
KE5CPU
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the quick reply!

So, how would I iterate thru the individual characters of the string?  Will I be able to grab each character this way? 

Sorry.  I pre-warned ya that it's been a while.   smiley
Logged

0
Offline Offline
God Member
*****
Karma: 39
Posts: 988
Get Bitlash: http://bitlash.net
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Interesting project.  I use a slightly different approach in the example morse transmitter that ships with Bitlash that may be worth considering. 

In this implementation, the morse data is encoded as a table of bytes, bit-packed.  Three bits of length and five bits of morse data for each character, with a little overflow table for symbols that don't fit.  All in PROGMEM, of course.

Code is here for the taking: https://github.com/billroy/bitlash/blob/master/examples/morse2/morse2.pde

Good luck with your project,

-br
Logged

Worst state in America
Offline Offline
God Member
*****
Karma: 32
Posts: 792
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I've seen the various morse code flashers, but none like I want. 

I made a Morse lookup table using ascii - example:

Code:
const char *table[] = {
    ".-",
    "-...",
    "-.-.",
    "-..",
    ".",
    "..-.",
// etc......
};

Then parse the string I want to send as Morse code, use the number as an array index (i.e. table[c]), then parse the "-" and "." from the string until the null terminator.

Make sense?
Logged

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

Texas
Offline Offline
Newbie
*
Karma: 0
Posts: 8
KE5CPU
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Billroy - Thanks for the response and example.  I'm impressed.  When I looked at the code, I was immediately overwelmed.  LOL!  Too complex for me at this juncture.  Thanks none the less.

Krupski - yeah, this is more what I had in mind.  So, are you telling me that I can literally use the individual characters for the index??  I had no idea.  That makes things simpler.  Is that * a reference to pointer in this instance?  If so, you're shifting thru the symbols, correct?
Logged

Lost Wages
Offline Offline
Full Member
***
Karma: 11
Posts: 103
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here is some ideas:

"e" should be a dit, not a dah, yes?

In Morse code the length of a dah is usually three times a dit, I believe.

I would use three values for the dit and dah values: 1 = dit, 3 = dah, and 0 = no blink.  The need for the third value is to allow you to pad the unused array elements with a value since some only use one like "e", while others like "1" use five

Use a two-dimensional array and initialize the second element with your dit and dah data.  The offset into the first element of the array can be the character's ASCII value.  Thus, if you have an int array named didah, then didah[65] = "1","3","0","0","0" which represents "A" (ascii 65) and would return dit dah 0 0 0

You could then use a function that is passed the value from each of the values in didah[65]. The value could then be multiplied by 500 to achieve the delay time.

I'm sure you get the idea...

read a character from the Serial object
convert character to ASCII and store in a variable
then pass the variable into a function that enters a for/loop to read each of the elements at that offset and passes the array value to your blink function
the blink function turns ON the LED for 500 * the number milliseconds -- 1/2 second for a dit, 1.5 seconds for a dah, and 0 seconds for the padding
don't forget the pause between letters

I hope I've been clear.

Good luck, and ask if you have further question.
Logged

Texas
Offline Offline
Newbie
*
Karma: 0
Posts: 8
KE5CPU
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks MaJiG!  I think you were clear, but it's a little more complicated than I can comprehend at this point.  It's been a long time since I coded anything.  I think what Krupski said is more what I had in mind, although you have given me some ideas to make it even simpler.

Thanks!
Logged

Lost Wages
Offline Offline
Full Member
***
Karma: 11
Posts: 103
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here is a example that only recognizes a or b or c (either case).

Code:
const int spd = 300;    // milliseconds for a dit

// the character array (only holds abc)
int didah[3][5] =
{
  { 1, 3, 0, 0, 0 },
  { 3, 1, 1, 1, 0 },
  { 3, 1, 3, 1, 0 }
};

void setup()
{
  pinMode(13, OUTPUT);    // pin 13 has the onboard LED, so no external parts
  
  Serial.begin(9600);
  Serial.println("---==START==---");
}

void loop()
{
  int mychar = 0;
  
  // check for a character
  if (Serial.available() > 0)
  {
     //here: there is a char coming in, so let's read it in
     mychar  = Serial.read();    // mychar now holds an ASCII value of the typed char
    
     if( mychar > 96 )
     {
       mychar -= 97 ;
     }
     else
     {
       mychar -= 65 ;
     }
    
     // we need to keep within the array's limits
     if( (mychar >= 0) && (mychar <= 3) )
     {
        morsechar( mychar );
     }
  }
}

void morsechar( int x )
{
     for(int i = 0 ; i < 5 ; i++ )
     {
        Serial.println(didah[x][i]);
        blip( didah[x][i] );
     }  
}

void blip( int d )
{
  if( (d == 1) || (d == 3) )
  {
    d *= spd ;
    
    digitalWrite(13, HIGH);
    delay( d );
  
    digitalWrite(13, LOW);
    delay(spd * 5);       // arbitrary 5 dit off delay
  }
}

you would need to expand the array to accommodate all the chars and adjust or eliminate the -= adjustment.

It runs on a bare Arduino UNO so it is easy to see.

Try it and let me know.
« Last Edit: February 10, 2013, 11:26:28 pm by MaJiG » Logged

Des Moines, WA - USA
Offline Offline
God Member
*****
Karma: 25
Posts: 779
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

There's morse code all around us ...

Code:
#if defined(ARDUINO) && ARDUINO >= 100
  #include "Arduino.h"
#else
  #include "WProgram.h"
#endif

#include <ctype.h>

#if   defined(_BOARD_CEREBOT_MX4CK_)
const uint8_t       pinLED          = 64;               // ON-BOARD LED1
#elif defined(_BOARD_UNO_)
const uint8_t       pinLED          = 13;               // ON-BOARD LED1
#else
#error "!!!Target is unknown board!!!"
#endif


const unsigned long DELAY_CASE      = 150UL;

const unsigned long DELAY_DOT       = DELAY_CASE;       // MILLISECONDS
const unsigned long DELAY_DOT       = DELAY_INTRA;
const unsigned long DELAY_DASH      = 3 * DELAY_CASE;
const unsigned long DELAY_CHAR      = 3 * DELAY_CASE;
const unsigned long DELAY_WORD      = 7 * DELAY_CASE;
const unsigned long DELAY_MESSAGE   = 3 * 1000;         // 3 SECONDS

const uint8_t       LED_OFF         = LOW;              // SYNONYMN FOR READABILITY
const uint8_t       LED_ON          = HIGH;             // SYNONYMN FOR READABILITY


#define SIZEOF_ARRAY(ARRAY)         (sizeof(ARRAY) / sizeof(ARRAY[0]))

enum { EOS, DOT, DASH, MASK = 3 };

struct sequence_pair_t
{
    const char      character;                          // character
    const uint16_t  encoding;                           // sequence, zero terminated 'C' string
};

const sequence_pair_t  morse_lookup[] =
{
    // STRING OF 2-BIT VALUES ENCODE THE MORSE SEQUENCE, LSB -> MSB
    //
    // 00   END-OF-SEQUENCE
    // 01   '.'
    // 10   '-'
    // 11   UNUSED

    // EXAMPLES:
    //
    //  { 'A',    0b0000000000001101 }    // ".-"     EOS  EOS  EOS  EOS  EOS  EOS DASH  DOT
    //, { '0',    0b0000001010101010 }    // "-----"  EOS  EOS  EOS DASH DASH DASH DASH DASH

   
    // --- Numeric
      { '0',    0b0000001010101010 }    // "-----"
    , { '1',    0b0000001010101001 }    // ".----"
    , { '2',    0b0000001010100101 }    // "..---"
    , { '3',    0b0000001010010101 }    // "...--"
    , { '4',    0b0000001001010101 }    // "....-"
    , { '5',    0b0000000101010101 }    // "....."
    , { '6',    0b0000000101010110 }    // "-...."
    , { '7',    0b0000000101011010 }    // "--..."
    , { '8',    0b0000000101101010 }    // "---.."
    , { '9',    0b0000000110101010 }    // "----."
   
    // --- Alphabetic
    , { 'A',    0b0000000000001001 }    // ".-"
    , { 'B',    0b0000000001010110 }    // "-..."
    , { 'C',    0b0000000001100110 }    // "-.-."
    , { 'D',    0b0000000000010110 }    // "-.."
    , { 'E',    0b0000000000000001 }    // "."
    , { 'F',    0b0000000001100101 }    // "..-."
    , { 'G',    0b0000000000011010 }    // "--."
    , { 'H',    0b0000000001010101 }    // "...."
    , { 'I',    0b0000000000000101 }    // ".."
    , { 'J',    0b0000000010101001 }    // ".---"
    , { 'K',    0b0000000000100110 }    // "-.-"
    , { 'L',    0b0000000001011001 }    // ".-.."
    , { 'M',    0b0000000000001010 }    // "--"
    , { 'N',    0b0000000000000110 }    // "-."
    , { 'O',    0b0000000000101010 }    // "---"
    , { 'P',    0b0000000001101001 }    // ".--."
    , { 'Q',    0b0000000010011010 }    // "--.-"
    , { 'R',    0b0000000000011001 }    // ".-."
    , { 'S',    0b0000000000010101 }    // "..."
    , { 'T',    0b0000000000000010 }    // "-"
    , { 'U',    0b0000000000100101 }    // "..-"
    , { 'V',    0b0000000010010101 }    // "...-"
    , { 'W',    0b0000000000101001 }    // ".--"
    , { 'X',    0b0000000010010110 }    // "-..-"
    , { 'W',    0b0000000010100110 }    // "-.--"
    , { 'Z',    0b0000000001011010 }    // "--.."
   
    // --- Punctuation
    , { ',',    0b0000101001011010 }    // "--..--"
    , { '.',    0b0000100110011001 }    // ".-.-.-"
    , { ':',    0b0000010101101010 }    // "---..."
    , { '?',    0b0000010110100101 }    // "..--.."
    , { '-',    0b0000100101010110 }    // "-....-"
    , { '/',    0b0000000110010110 }    // "-..-."
    , { '(',    0b0000100110100110 }    // "-.--.-"
    , { ')',    0b0000100110100110 }    // "-.--.-"
   
//  , { '\'', ".----." }  // the windows IDE has problem with escaped character literals!
//  , { '\"', ".-..-." }  // the windows IDE has problem with escaped character literals!
};


void blinkDot()
{
    digitalWrite(pinLED, LED_ON);

    delay(DELAY_DOT);

    digitalWrite(pinLED, LED_OFF);
}


void blinkDash()
{
    digitalWrite(pinLED, LED_ON);

    delay(DELAY_DASH);

    digitalWrite(pinLED, LED_OFF);
}


void blinkCharacterSequence(uint16_t encoding)
{
    do
    {
        switch ( encoding & MASK )
        {
            case DOT:   blinkDot();      break;
            case DASH:  blinkDash();     break;
        }

        if ( encoding >>= 2 )
        {
            delay(DELAY_INTRA);
        }

    } while ( EOS != (encoding & MASK) );
}


void blinkCharactor(char ch)
{
    const int cEntries = SIZEOF_ARRAY(morse_lookup);
   
    for ( int i = cEntries; i--; )
    {
        if ( ch == morse_lookup[i].character )
        {
            blinkCharacterSequence(morse_lookup[i].encoding);

            return;
        }
    }
}


void loop()
{
    // Initialize message using "string" syntax which has invisible
    // terminating 0

    static const char  szMessage[] = { "Hello AlphaTango" };

    for ( int i = 0; szMessage[i]; )
    {
        blinkCharactor(toupper(szMessage[i++]));
       
        delay(((' ' != szMessage[i]) ? DELAY_CHAR : DELAY_WORD));
    }
   
    delay(DELAY_MESSAGE);
}


void setup()
{
    pinMode(pinLED, OUTPUT);
    digitalWrite(pinLED, LED_OFF);
   
    delay(DELAY_MESSAGE);
}
Logged

Offline Offline
Full Member
***
Karma: 2
Posts: 138
W9LZ
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Your 'B' is actually a "D". B is dah dit dit dit.  A listening ratio of 1.0 for a dit to 1.5 for a dah, is more pleasing. Visually you might try 1.0 to 2.0.  Once you get to 23-25 words per minute, it all sounds like music. smiley-wink
« Last Edit: February 10, 2013, 11:14:07 pm by Learning » Logged

Southern California
Offline Offline
Full Member
***
Karma: 0
Posts: 108
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You can try this code I wrote last May, it's tested and works on my Uno rev3.

Code:
// flashes  morse code from text on serial port
// special characters to adjust wpm and frequency

char c;                  // read off serial port
int pin = 8;
float dot = 200.0;       // duration of dot for 5 wpm
void setup() {
  pinMode(8, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  while(Serial.available()) {
    c = Serial.read();
    switch(c) {
      case '!' : dot*=1.1; break;        // slower by 10%
      case '@' : dot*=.9; break;         // faster by 10%
      case '%' : report(); break;        // show status
      case ' ' : delay(7*dot); break;
      case 'a' : flash("01"); break;
      case 'b' : flash("1000"); break;
      case 'c' : flash("1010"); break;
      case 'd' : flash("100"); break;
      case 'e' : flash("0"); break;
      case 'f' : flash("0010"); break;
      case 'g' : flash("110"); break;
      case 'h' : flash("0000"); break;
      case 'i' : flash("00"); break;
      case 'j' : flash("0111"); break;
      case 'k' : flash("101"); break;
      case 'l' : flash("0100"); break;
      case 'm' : flash("11"); break;
      case 'n' : flash("10"); break;
      case 'o' : flash("111"); break;
      case 'p' : flash("0110"); break;
      case 'q' : flash("1101"); break;
      case 'r' : flash("010"); break;
      case 's' : flash("000"); break;
      case 't' : flash("1"); break;
      case 'u' : flash("001"); break;
      case 'v' : flash("0001"); break;
      case 'w' : flash("011"); break;
      case 'x' : flash("1001"); break;
      case 'y' : flash("1011"); break;
      case 'z' : flash("1100"); break;
      case 'A' : flash("01"); break;
      case 'B' : flash("1000"); break;
      case 'C' : flash("1010"); break;
      case 'D' : flash("100"); break;
      case 'E' : flash("0"); break;
      case 'F' : flash("0010"); break;
      case 'G' : flash("110"); break;
      case 'H' : flash("0000"); break;
      case 'I' : flash("00"); break;
      case 'J' : flash("0111"); break;
      case 'K' : flash("101"); break;
      case 'L' : flash("0100"); break;
      case 'M' : flash("11"); break;
      case 'N' : flash("10"); break;
      case 'O' : flash("111"); break;
      case 'P' : flash("0110"); break;
      case 'Q' : flash("1011"); break;
      case 'R' : flash("010"); break;
      case 'S' : flash("000"); break;
      case 'T' : flash("1"); break;
      case 'U' : flash("001"); break;
      case 'V' : flash("0001"); break;
      case 'W' : flash("011"); break;
      case 'X' : flash("1001"); break;
      case 'Y' : flash("1011"); break;
      case 'Z' : flash("1100"); break;
      case '0' : flash("11111"); break;
      case '1' : flash("01111"); break;
      case '2' : flash("00111"); break;
      case '3' : flash("00011"); break;
      case '4' : flash("00001"); break;
      case '5' : flash("00000"); break;
      case '6' : flash("10000"); break;
      case '7' : flash("11000"); break;
      case '8' : flash("11100"); break;
      case '9' : flash("11110"); break;
      case '.' : flash("010101"); break;
      case ',' : flash("110011"); break;
      default  : delay(7*dot); break;
    }
  }
}

void flash(char x[]) {
  for(int i=0; i<strlen(x); i++) {
    if(x[i]=='1') {
      digitalWrite(pin, HIGH);        // dash
      delay(3*dot);
      digitalWrite(pin, LOW);
    }
    else {
      digitalWrite(pin, HIGH);        // dot
      delay(dot);
      digitalWrite(pin, LOW);
    }
  delay(dot);               // end of flash
  }
  delay(3*dot);             // end of character
}

void report() {
  Serial.print(1000/dot);
  Serial.print(" wpm, ");
}
 
Logged

Texas
Offline Offline
Newbie
*
Karma: 0
Posts: 8
KE5CPU
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks guys!  I was hoping to avoid typing all the crazy-long lookup tables.  That was the reason for my "S=000" to make 'S" transmit "dot dot dot".  I like simple.  smiley
Logged

Worst state in America
Offline Offline
God Member
*****
Karma: 32
Posts: 792
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Krupski - yeah, this is more what I had in mind.  So, are you telling me that I can literally use the individual characters for the index??  I had no idea.  That makes things simpler.  Is that * a reference to pointer in this instance?  If so, you're shifting thru the symbols, correct?

Yes.

A simplified example: Imagine you only want to do Morse letters "A" through "E".

Take the character, subtract 'A' from it (makes A == 0, B == 1, etc...) then use it to index into the Morse array:

Code:
const char *morse[5] = {
    ".-", // A = 0
    "-...", // B = 1
    "-.-.", // C = 2
    "-..", // D = 3
    "." // E = 4
    // etc......
};

int m = 'C'; // canned letter C

m -= 'A'; // normalize to 0

for (int i = 0; i < strlen(morse[m]); i++) {
    if (morse[m][i] == "." {
        // generate a dot
    } else {
        // generate a dash
    }
}

Of course, you need to do the entire range, and save yourself grief by uppercasing the letters so you can handle lowercase input seamlessly.

Hope this helps.
Logged

Gentlemen may prefer Blondes, but Real Men prefer Redheads!

Texas
Offline Offline
Newbie
*
Karma: 0
Posts: 8
KE5CPU
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks Krupski!  That's definitely what I had in mind, though I was going to use binary (0s for dits, 1s for dahs) for the pattern.

Can you explain why you're subtracting 'A' from each character?  I don't quite understand that.
Logged

Pages: [1] 2   Go Up
Jump to: