/*
* Gray_MorseEncoder.ino
*
* Code by: Gray Mack
* Created: 1/9/2024
* Description: Was looking for a particular style of Morse code
* and couldn't find what I was looking for, so created it.
* Not the most efficient solution but more for fun
*/
const byte PIN_SPEAKER = 7;
const byte PIN_LED = LED_BUILTIN;
const byte PIN_SPEED_POT = A0;
const byte PIN_TONE_FREQ_POT = A1;
const char* MorseAlphaTable[] = {
".-", // a
"-...", // b
"-.-.", // c
"-..", // d
".", // e
"..-.", // f
"--.", // g
"....", // h
"..", // i
".---", // j
"-.-", // k
".-..", // l
"--", // m
"-.", // n
"---", // o
".--.", // p
"--.-", // q
".-.", // r
"...", // s
"-", // t
"..-", // u
"...-", // v
".--", // w
"-..-", // x
"-.--", // y
"--..", // z
};
const char* MorseNumberTable[] = {
"-----", // 0
".----", // 1
"..---", // 2
"...--", // 3
"....-", // 4
".....", // 5
"-....", // 6
"--...", // 7
"---..", // 8
"----.", // 9
};
// speed calculation. If we aim for 5 words per minute and to send 5,7,10, or 12 words per minute
// 60sec / (typical word 5 letters *(letters have about 4 digits, say -.-. is 3+1+1+1+3+1+1+1+1+2)=15 ) + word pause 6)
// 60000msec / (5*15+6) = 133 for about 5 words per minute
// 60000msec / (10*15+6) = 67 for about 10 words per minute
// converted the constants to variables set by analog pots
uint16_t DotLengthMs = 133;
#define DashLengthMs() (DotLengthMs*3)
#define PauseBetweenDDLengthMs() (DotLengthMs) // pause between parts of the same letter
#define LetterSpaceLengthMs() (DotLengthMs*2) // pause between leters/numbers is 3 but we already added one after the ./- so use 2
#define WordSpaceLengthMs() (DotLengthMs*6) // pause between words is 7 but we already added one after the digit, so use 6
uint16_t ToneFrequency = 500; // some go as low as 50Hz
void setup() {
Serial.begin(9600);
pinMode(PIN_SPEED_POT, INPUT);
pinMode(PIN_TONE_FREQ_POT, INPUT);
pinMode(PIN_LED, OUTPUT);
digitalWrite(PIN_LED, LOW);
SendMorseString("Hello, world. How did I get here?");
Serial.println("Enter a string to convert to Morse:");
Serial.setTimeout(-1);
}
void loop() {
String str = Serial.readStringUntil('\n');
SendMorseString(str.c_str());
Serial.println();
}
void SendMorseString(const char *str)
{
Serial.println(str);
const char* codePointer;
for(uint8_t i=0; i<strlen(str); i++)
{
char ch = str[i];
if(isAlpha(ch))
{
codePointer = MorseAlphaTable[toLowerCase(ch)-'a'];
SendMorseAlphaNumeric(codePointer);
}
else if(isDigit(ch))
{
codePointer = MorseNumberTable[ch-'0'];
SendMorseAlphaNumeric(codePointer);
}
else if(isWhitespace(ch))
{
Serial.print(' ');
delay(WordSpaceLengthMs());
}
else if(ch=='.' || ch=='?')
{
Serial.println();
}
}
}
void SendMorseAlphaNumeric(const char* codeStr)
{
DotLengthMs = UpdateSpeed();
ToneFrequency = UpdateToneFreq();
for(uint8_t i=0; i<strlen(codeStr); i++)
{
char dd = codeStr[i]; // grab our current dot or dash
Serial.print(dd);
digitalWrite(PIN_LED, HIGH);
tone(PIN_SPEAKER, ToneFrequency);
delay(dd == '-' ? DashLengthMs() : DotLengthMs);
digitalWrite(PIN_LED, LOW);
noTone(PIN_SPEAKER);
delay(PauseBetweenDDLengthMs());
}
Serial.print(' ');
delay(LetterSpaceLengthMs());
}
uint16_t UpdateSpeed()
{
uint16_t speed = analogRead(PIN_SPEED_POT);
return map(speed, 0, 1023, 400, 20);
}
uint16_t UpdateToneFreq()
{
uint16_t freq = analogRead(PIN_TONE_FREQ_POT);
return map(freq, 0, 1023, 35, 2000);
}