Last active
July 1, 2024 21:14
-
-
Save flybd5/27fd8bfbf66f409ad3150b6a8d1a6765 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "BluetoothSerial.h" | |
// This code will implement a International Morse Code keyer using bluetooth. | |
// The code implements all international morse code characters except the digraph 'ch' | |
// which was deprecated some time ago from the Spanish language. | |
// It requires an Arduino device and a 5v relay (can be mechanical or solid state). | |
// I used an ESP32 DevBoard and a simple 5v relay. | |
// The relay is powered from the Arduino, and the trigger comes from one of the pio pins | |
// (26 is the default). On the relay you connect the NO and center contacts to a 1/4" or 1/8" male plug | |
// (depending which one your radio uses) and connect that to the CW key jack on your radio. That's it. | |
// Written by Juan Jimenez, K1CPR/AE, June 2023 | |
// Released to the public domain. Use as you wish but please give credit. | |
const int relay_pin = 26; // Change to the PIO pin you use to trigger the relay | |
const int dotTime = 50; // Time for a dot, dashes are always 3x this value | |
// const int pin = "0000" // Uncomment if using a pin for pairing. See below. | |
BluetoothSerial SerialBT; | |
void setup() { | |
Serial.begin(115200); | |
Serial.setTimeout(1000); | |
pinMode(relay_pin, OUTPUT); | |
SerialBT.begin("JJCWKeyBT"); //Bluetooth device name | |
Serial.printf("\"JJCWKeyBT\" is started, pair it with Bluetooth!"); | |
// If you want to use a pin code for pairing, uncomment and set the pin code. | |
// #ifdef USE_PIN | |
// SerialBT.setPin(pin); | |
// Serial.println("Using PIN"); | |
// #endif | |
} | |
// For dot and dash the relay is activated to close, triggering the key on your radio | |
// Spacing between letters same as a dash. | |
void space(){ | |
delay(dotTime*3); | |
} | |
// Spacing between words is 7x the dot time | |
void wordSpace(){ | |
delay(dotTime*7); | |
} | |
void dot(){ | |
digitalWrite(relay_pin, HIGH); | |
delay(dotTime); | |
digitalWrite(relay_pin, LOW); | |
delay(dotTime); | |
} | |
void dash(){ | |
digitalWrite(relay_pin, HIGH); | |
delay(dotTime*3); | |
digitalWrite(relay_pin, LOW); | |
delay(dotTime); | |
} | |
void symbol(char theSymbol){ | |
if (isAlpha(theSymbol)){ | |
switch(toupper(theSymbol)){ | |
case 'A': | |
dot(); dash(); | |
break; | |
case 'B': | |
dash(); dot(); dot(); dot(); | |
break; | |
case 'C': | |
dash(); dot(); dash(); dot(); | |
break; | |
case 'D': | |
dash(); dot(); dot(); | |
break; | |
case 'E': | |
dot(); | |
break; | |
case 'F': | |
dot(); dot(); dash(); dot; | |
break; | |
case 'G': | |
dash(); dash(); dot(); | |
break; | |
case 'H': | |
dot(); dot(); dot(); dot(); | |
break; | |
case 'I': | |
dot(); dot(); | |
break; | |
case 'J': | |
dot(); dash(); dash(); dash(); | |
break; | |
case 'K': | |
dash(); dot(); dash(); | |
break; | |
case 'L': | |
dot(); dash(); dot(); dot(); | |
break; | |
case 'M': | |
dash(); dash(); | |
break; | |
case 'N': | |
dash(); dot(); | |
break; | |
case 'O': | |
dash(); dash(); dash(); | |
break; | |
case 'P': | |
dot(); dash(); dash(); dot(); | |
break; | |
case 'Q': | |
dash(); dash(); dot(); dash(); | |
break; | |
case 'R': | |
dot(); dash(); dot(); | |
break; | |
case 'S': | |
dot(); dot(); dot(); | |
break; | |
case 'T': | |
dash(); | |
break; | |
case 'U': | |
dot(); dot(); dash(); | |
break; | |
case 'V': | |
dot(); dot(); dot(); dash(); | |
break; | |
case 'W': | |
dot(); dash(); dash(); | |
break; | |
case 'X': | |
dash(); dot(); dot(); dash(); | |
break; | |
case 'Y': | |
dash(); dot(); dash(); dash(); | |
break; | |
case 'Z': | |
dash(); dash(); dot(); dot(); | |
default: | |
// Do nothing | |
break; | |
} | |
} else if(isdigit(theSymbol)){ | |
switch(theSymbol){ | |
case '1': | |
dot(); dash(); dash(); dash(); dash(); | |
break; | |
case '2': | |
dot(); dot(); dash(); dash(); dash(); | |
break; | |
case '3': | |
dot(); dot(); dot(); dash(); dash(); | |
break; | |
case '4': | |
dot(); dot(); dot(); dot(); dash(); | |
break; | |
case '5': | |
dot(); dot(); dot(); dot(); dot(); | |
break; | |
case '6': | |
dash(); dot(); dot(); dot(); dot(); | |
break; | |
case '7': | |
dash(); dash(); dot(); dot(); dot(); | |
break; | |
case '8': | |
dash(); dash(); dash(); dot(); dot(); | |
break; | |
case '9': | |
dash(); dash(); dash(); dash(); dot(); | |
break; | |
case '0': | |
dash(); dash(); dash(); dash(); dash(); | |
break; | |
default: | |
// Do nothing | |
break; | |
} | |
} else switch(theSymbol){ | |
case '.': | |
dot(); dash(); dot(); dash(); dot(); dash(); | |
break; | |
case ',': | |
dash(); dash(); dot(); dot(); dash(); dash(); | |
break; | |
case '?': | |
dot(); dot(); dash(); dash(); dot(); dot(); | |
break; | |
case '\'': | |
dot(); dash(); dash(); dash(); dash(); dot(); | |
break; | |
case '!': | |
dash(); dot(); dash(); dot(); dash(); dash(); | |
break; | |
case '/': | |
dash(); dot(); dot(); dash(); dot(); | |
break; | |
case '(': | |
dash(); dot(); dash(); dash(); dot(); | |
break; | |
case ')': | |
dash(); dot(); dash(); dash(); dot(); dash(); | |
break; | |
case '&': | |
dot(); dash(); dot(); dot(); dot(); | |
break; | |
case ':': | |
dash(); dash(); dash(); dot(); dot(); dot(); | |
break; | |
case ';': | |
dash(); dot(); dash(); dot(); dash(); dot(); | |
break; | |
case '=': | |
dash(); dot(); dot(); dot(); dash(); | |
break; | |
case '+': | |
dot(); dash(); dot(); dash(); dot(); | |
break; | |
case '-': | |
dash(); dot(); dot(); dot(); dot(); dash(); | |
break; | |
case '_': | |
dot(); dot(); dash(); dash(); dot(); dash(); | |
break; | |
case '"': | |
dot(); dash(); dot(); dot(); dash(); dot(); | |
break; | |
case '$': | |
dot(); dot(); dot(); dash(); dot(); dot(); dash(); | |
break; | |
case '@': | |
dot(); dash(); dash(); dot(); dash(); dot(); | |
break; | |
// Don't forget the non-latin symbols | |
case 'Ä': | |
case 'ä': | |
dot(); dash(); dot(); dash(); | |
break; | |
case 'À': | |
case 'à': | |
dot(); dash(); dash(); dot(); dash(); | |
break; | |
case 'Ç': | |
case 'ç': | |
dash(); dot(); dash(); dot(); dot(); | |
break; | |
// Special case, digraph ch, not implemented due to no input code possible | |
case 'Ð': | |
dot(); dot(); dash(); dash(); dot(); | |
break; | |
case 'È': | |
case 'è': | |
dot(); dash(); dot(); dot(); dash(); | |
break; | |
case 'É': | |
case 'é': | |
dot(); dot(); dash(); dot(); dot(); | |
break; | |
case 'Ĝ': | |
case 'ĝ': | |
dash(); dash(); dot(); dash(); dot(); | |
break; | |
case 'Ĵ': | |
case 'ĵ': | |
dot(); dash(); dash(); dash(); dot(); | |
break; | |
case 'Ñ': | |
case 'ñ': | |
dash(); dash(); dot(); dash(); dash(); | |
break; | |
case 'Ö': | |
case 'ö': | |
dash(); dash(); dash(); dot(); | |
break; | |
case 'Š': | |
case 'š': | |
dot(); dot(); dot(); dash(); dot(); | |
break; | |
case 'þ': | |
dot(); dash(); dash(); dot(); dot(); | |
break; | |
case 'Ü': | |
case 'ü': | |
dot(); dot(); dash(); dash(); | |
break; | |
default: | |
// Do nothing | |
break; | |
} | |
space(); | |
} | |
void loop() { | |
Serial.println("Enter data:"); | |
while (Serial.available() == 0) {} // Wait for data available | |
String aString = Serial.readString(); // Read until timeout | |
aString.trim(); // remove any \r \n or whitespace at the end of the string | |
if (aString.length()>0) { | |
Serial.println("Sending: "+aString); | |
for (int i = 0; i < aString.length(); i++) { | |
symbol(aString.charAt(i)); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment