Texas
Offline
Newbie
Karma: 0
Posts: 8
KE5CPU
|
 |
« on: February 10, 2013, 06:35:12 pm » |
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
Online
Brattain Member
Karma: 311
Posts: 35478
Seattle, WA USA
|
 |
« Reply #1 on: February 10, 2013, 06:40:32 pm » |
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
Newbie
Karma: 0
Posts: 8
KE5CPU
|
 |
« Reply #2 on: February 10, 2013, 06:57:25 pm » |
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. 
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
God Member
Karma: 37
Posts: 974
Get Bitlash: http://bitlash.net
|
 |
« Reply #3 on: February 10, 2013, 07:18:40 pm » |
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.pdeGood luck with your project, -br
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Sr. Member
Karma: 15
Posts: 463
|
 |
« Reply #4 on: February 10, 2013, 07:36:14 pm » |
I've seen the various morse code flashers, but none like I want.
I made a Morse lookup table using ascii - example: 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
|
|
|
|
|
Texas
Offline
Newbie
Karma: 0
Posts: 8
KE5CPU
|
 |
« Reply #5 on: February 10, 2013, 07:46:30 pm » |
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
Full Member
Karma: 11
Posts: 103
|
 |
« Reply #6 on: February 10, 2013, 08:07:19 pm » |
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
Newbie
Karma: 0
Posts: 8
KE5CPU
|
 |
« Reply #7 on: February 10, 2013, 08:27:36 pm » |
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
Full Member
Karma: 11
Posts: 103
|
 |
« Reply #8 on: February 10, 2013, 10:02:17 pm » |
Here is a example that only recognizes a or b or c (either case). 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
Online
God Member
Karma: 21
Posts: 703
|
 |
« Reply #9 on: February 10, 2013, 11:03:22 pm » |
There's morse code all around us ... #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
Full Member
Karma: 2
Posts: 128
W9LZ
|
 |
« Reply #10 on: February 10, 2013, 11:06:43 pm » |
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. 
|
|
|
|
« Last Edit: February 10, 2013, 11:14:07 pm by Learning »
|
Logged
|
|
|
|
|
Southern California
Offline
Full Member
Karma: 0
Posts: 105
|
 |
« Reply #11 on: February 10, 2013, 11:51:37 pm » |
You can try this code I wrote last May, it's tested and works on my Uno rev3. // 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
Newbie
Karma: 0
Posts: 8
KE5CPU
|
 |
« Reply #12 on: February 11, 2013, 01:17:25 pm » |
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. 
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Sr. Member
Karma: 15
Posts: 463
|
 |
« Reply #13 on: February 11, 2013, 08:14:44 pm » |
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: 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
|
|
|
|
|
Texas
Offline
Newbie
Karma: 0
Posts: 8
KE5CPU
|
 |
« Reply #14 on: February 11, 2013, 11:28:04 pm » |
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
|
|
|
|
|
|