At this year's OSCON, I attended an Arduino workshop (by Philip Lindsay with help from Brian Jepson) and in the process I wrote a simple Morse code transcoder for Arduino. Is it very useful? No. Is it fun to play with? I think so :-)
Assuming you know how to wire an Arduino board (e.g. hook up a button to D7 and a LED to D13) and you have access to the SDK, you can run this sketch to try it out (though I cannot be held responsible if this breaks/fries your board):
Code:
/* About: This is a simple Arduino-compatible "sketch" that is meant to do two things: * 1) Convert ASCII chars from the serial port to Morse Code by flashing an * LED (connected to digital pin 13) * 2) Interpret presses on button (connected to digital pin 7) as Morse Code * inputs and send as ASCII chars to serial port * Author: Aleksandar Gargenta, Marakana * License: Apache License, Version 2.0 * Disclaimer: This is my very first Arduino sketch, so expect bugs :-) */ #define DOT_DURATION 200 // Duration of a Morse Code "dot" (in milliseconds) #define DASH_DURATION DOT_DURATION * 3 // Duration of a Morse Code "dash" (in milliseconds) #define SIGNAL_GAP DOT_DURATION // Gap between dots/dashes of a single letter (in ms) #define LETTER_GAP DOT_DURATION * 3 // Gap between two letters (in milliseconds) #define WORD_GAP DOT_DURATION * 7 // Gap between two words (in milliseconds) #define LED 13 // The digital connector port to LED anode #define BUTTON 7 // The diginal connector port to the button #define DOT 1 // DOT identifier #define DASH 2 // DASH identifier #define NONE 0 // Neither DOT nor DASH boolean buttonWasPressed = false; // Indicator of whether button was pressed in the last cycle long lastTimestamp = 0; // Last recorded timestamp (used for mesuring duration) byte inputSignal[5]; // Input signal buffer int inputSignalIndex = 0; // Index into the input signal buffer void resetInputSignal() { // Reset the input signal buffer and index inputSignal[0] = NONE; inputSignal[1] = NONE; inputSignal[2] = NONE; inputSignal[3] = NONE; inputSignal[4] = NONE; inputSignalIndex = 0; } void setup() { pinMode(LED, OUTPUT); // Set the LED output pinMode(BUTTON, INPUT); // Set the button input digitalWrite(LED, LOW); // Turn off the LED Serial.begin(9600); // Init the serial port resetInputSignal(); // Reset input signal buffer } // return true if s0-s4 match input signal boolean matchInputSignal(byte s0, byte s1, byte s2, byte s3, byte s4) { return ((inputSignal[0] == s0) && (inputSignal[1] == s1) && (inputSignal[2] == s2) && (inputSignal[3] == s3) && (inputSignal[4] == s4)); } // convert input signal to letter or ? if not found char currentInputSignalToLetter() { if (matchInputSignal(DOT, DASH, NONE, NONE, NONE)) { return 'A'; } if (matchInputSignal(DASH, DOT, DOT, DOT, NONE)) { return 'B'; } if (matchInputSignal(DASH, DOT, DASH, DOT, NONE)) { return 'C'; } if (matchInputSignal(DASH, DOT, DOT, NONE, NONE)) { return 'D'; } if (matchInputSignal(DOT, NONE, NONE, NONE, NONE)) { return 'E'; } if (matchInputSignal(DOT, DOT, DASH, DOT, NONE)) { return 'F'; } if (matchInputSignal(DASH, DASH, DOT, NONE, NONE)) { return 'G'; } if (matchInputSignal(DOT, DOT, DOT, DOT, NONE)) { return 'H'; } if (matchInputSignal(DOT, DOT, NONE, NONE, NONE)) { return 'I'; } if (matchInputSignal(DOT, DASH, DASH, DASH, NONE)) { return 'I'; } if (matchInputSignal(DASH, DOT, DASH, NONE, NONE)) { return 'K'; } if (matchInputSignal(DOT, DASH, DOT, DOT, NONE)) { return 'L'; } if (matchInputSignal(DASH, DASH, NONE, NONE, NONE)) { return 'M'; } if (matchInputSignal(DASH, DOT, NONE, NONE, NONE)) { return 'N'; } if (matchInputSignal(DASH, DASH, DASH, NONE, NONE)) { return 'O'; } if (matchInputSignal(DOT, DASH, DASH, DOT, NONE)) { return 'P'; } if (matchInputSignal(DASH, DASH, DOT, DASH, NONE)) { return 'Q'; } if (matchInputSignal(DOT, DASH, DOT, NONE, NONE)) { return 'R'; } if (matchInputSignal(DOT, DOT, DOT, NONE, NONE)) { return 'S'; } if (matchInputSignal(DASH, NONE, NONE, NONE, NONE)) { return 'T'; } if (matchInputSignal(DOT, DOT, DASH, NONE, NONE)) { return 'U'; } if (matchInputSignal(DOT, DOT, DOT, DASH, NONE)) { return 'V'; } if (matchInputSignal(DOT, DASH, DASH, NONE, NONE)) { return 'W'; } if (matchInputSignal(DASH, DOT, DOT, DASH, NONE)) { return 'X'; } if (matchInputSignal(DASH, DOT, DASH, DASH, NONE)) { return 'Y'; } if (matchInputSignal(DASH, DASH, DOT, DOT, NONE)) { return 'Z'; } if (matchInputSignal(DOT, DASH, DASH, DASH, DASH)) { return '1'; } if (matchInputSignal(DOT, DOT, DASH, DASH, DASH)) { return '2'; } if (matchInputSignal(DOT, DOT, DOT, DASH, DASH)) { return '3'; } if (matchInputSignal(DOT, DOT, DOT, DOT, DASH)) { return '4'; } if (matchInputSignal(DOT, DOT, DOT, DOT, DOT)) { return '5'; } if (matchInputSignal(DASH, DOT, DOT, DOT, DOT)) { return '6'; } if (matchInputSignal(DASH, DASH, DOT, DOT, DOT)) { return '7'; } if (matchInputSignal(DASH, DASH, DASH, DOT, DOT)) { return '8'; } if (matchInputSignal(DASH, DASH, DASH, DASH, DOT)) { return '9'; } if (matchInputSignal(DASH, DASH, DASH, DASH, DASH)) { return '0'; } return '?'; } // turn on the LED for the specified duration in milliseconds void showLightForDuration(long duration) { digitalWrite(LED, HIGH); delay(duration); digitalWrite(LED, LOW); } // show signal (DOT or DASH) via LED boolean showSignal(byte dotDashNone) { switch(dotDashNone) { case DOT: showLightForDuration(DOT_DURATION); return true; case DASH: showLightForDuration(DASH_DURATION); return true; default: return false; } } // show letter from signals (DOTs and DASHes) via LED void showLetterForSignals(byte s0, byte s1, byte s2, byte s3, byte s4) { if (showSignal(s0)) { delay(SIGNAL_GAP); if (showSignal(s1)) { delay(SIGNAL_GAP); if (showSignal(s2)) { delay(SIGNAL_GAP); if (showSignal(s3)) { delay(SIGNAL_GAP); showSignal(s4); } } } } delay(LETTER_GAP); } // show letter from byte via LED void showLetter(byte letter) { if (97 <= letter && letter <= 122) { // if a-z letter -= 32; // map to A-Z } switch(letter) { case 'A': showLetterForSignals(DOT, DASH, NONE, NONE, NONE); break; case 'B': showLetterForSignals(DASH, DOT, DOT, DOT, NONE); break; case 'C': showLetterForSignals(DASH, DOT, DASH, DOT, NONE); break; case 'D': showLetterForSignals(DASH, DOT, DOT, NONE, NONE); break; case 'E': showLetterForSignals(DOT, NONE, NONE, NONE, NONE); break; case 'F': showLetterForSignals(DOT, DOT, DASH, DOT, NONE); break; case 'G': showLetterForSignals(DASH, DASH, DOT, NONE, NONE); break; case 'H': showLetterForSignals(DOT, DOT, DOT, DOT, NONE); break; case 'I': showLetterForSignals(DOT, DOT, NONE, NONE, NONE); break; case 'J': showLetterForSignals(DOT, DASH, DASH, DASH, NONE); break; case 'K': showLetterForSignals(DASH, DOT, DASH, NONE, NONE); break; case 'L': showLetterForSignals(DOT, DASH, DOT, DOT, NONE); break; case 'M': showLetterForSignals(DASH, DASH, NONE, NONE, NONE); break; case 'N': showLetterForSignals(DASH, DOT, NONE, NONE, NONE); break; case 'O': showLetterForSignals(DASH, DASH, DASH, NONE, NONE); break; case 'P': showLetterForSignals(DOT, DASH, DASH, DOT, NONE); break; case 'Q': showLetterForSignals(DASH, DASH, DOT, DASH, NONE); break; case 'R': showLetterForSignals(DOT, DASH, DOT, NONE, NONE); break; case 'S': showLetterForSignals(DOT, DOT, DOT, NONE, NONE); break; case 'T': showLetterForSignals(DASH, NONE, NONE, NONE, NONE); break; case 'U': showLetterForSignals(DOT, DOT, DASH, NONE, NONE); break; case 'V': showLetterForSignals(DOT, DOT, DOT, DASH, NONE); break; case 'W': showLetterForSignals(DOT, DASH, DASH, NONE, NONE); break; case 'X': showLetterForSignals(DASH, DOT, DOT, DASH, NONE); break; case 'Y': showLetterForSignals(DASH, DOT, DASH, DASH, NONE); break; case 'Z': showLetterForSignals(DASH, DASH, DOT, DOT, NONE); break; case '1': showLetterForSignals(DOT, DASH, DASH, DASH, DASH); break; case '2': showLetterForSignals(DOT, DOT, DASH, DASH, DASH); break; case '3': showLetterForSignals(DOT, DOT, DOT, DASH, DASH); break; case '4': showLetterForSignals(DOT, DOT, DOT, DOT, DASH); break; case '5': showLetterForSignals(DOT, DOT, DOT, DOT, DOT); break; case '6': showLetterForSignals(DASH, DOT, DOT, DOT, DOT); break; case '7': showLetterForSignals(DASH, DASH, DOT, DOT, DOT); break; case '8': showLetterForSignals(DASH, DASH, DASH, DOT, DOT); break; case '9': showLetterForSignals(DASH, DASH, DASH, DASH, DOT); break; case '0': showLetterForSignals(DASH, DASH, DASH, DASH, DASH); break; case ' ': delay(WORD_GAP); break; default: Serial.print("Don't understand ["); Serial.print((char) letter); Serial.print("]"); showLightForDuration(50); delay(50); showLightForDuration(50); delay(50); showLightForDuration(50); } } void loop() { // loop forever long currentTimestamp = millis(); // get the current timestamp long duration = currentTimestamp - lastTimestamp; // get elapsed time if (digitalRead(BUTTON) == HIGH) { // if the button is pressed if (!buttonWasPressed) { // if the button was previously not pressed buttonWasPressed = true; // remember the button press digitalWrite(LED, HIGH); // turn on the LED lastTimestamp = currentTimestamp; // record the time of the button press if (duration > LETTER_GAP) { Serial.print(' '); } } // end of if (button was not pressed) } else { // the button is not pressed if (buttonWasPressed) { // the button was just released if (duration < DOT_DURATION) { // if the button was pressed for up to DOT cutoff inputSignal[inputSignalIndex] = DOT; // remember the current signal as a DOT } else { // if the button was pressed for longer than DOT cutoff inputSignal[inputSignalIndex] = DASH; // remember the current signal as a DASH } inputSignalIndex++; // advance the index to the input signal buffer digitalWrite(LED, LOW); // turn off the LED buttonWasPressed = false; // consume previous button press lastTimestamp = currentTimestamp; // record the time the button was released } else { // the button was not just released if (inputSignalIndex > 0) { // if there is data in the input signal buffer if (duration > SIGNAL_GAP || inputSignalIndex >= 4) { // if we have a complete letter Serial.print(currentInputSignalToLetter()); // parse the letter and send it via serial resetInputSignal(); // reset the input signal buffer } } } // end of else (button was not previously pressed) } // end of else (button is not pressed) if (Serial.available() > 0) { // if there is data availalbe on the serial port showLetter(Serial.read()); // read the next byte and output it as morse code via LED } } // end of loop
You can also download Morse code transcoder for Arduino.
Any feedback is welcome :-)