Arduino-Morsekeyboard        

Von Ralf Beesner                    

Elektronik-Labor   Projekte   AVR 






Mit einem Arduino Leonardo oder einem Arduino Micro kann man mit wenig Aufwand ein inverses Morsekeyboard bauen (also ein virtuelles Eintasten-USB-Keyboard, das eingegebene Morsezeichen in Tastendrücke umsetzt). Mit ihm kann man in beliebige PC-Anwendungen mit der Morsetaste hineinschreiben.

Das Ursprungsprogramm wurde von Burkhard Kainka für das AVR Butterfly geschrieben,
www.elo-web.de/mikrocontroller-und-programmierung/avr-anwendungen/butterfly-morse-dekoder
ich hatte es bereits für den AtMega8 umgeschrieben und um einige Kleinigkeiten ergänzt
www.elektronik-labor.de/AVR/Morsedecoder.html
und in eine Bascom-Software-USB-Keyboard-Beispielimplementation "hineinverpflanzt"
www.elektronik-labor.de/AVR/USBbascomCW.html


Nun ist es auf den Arduino portiert, und verglichen mit der Bascom-Lösung ist die Komplexität dramatisch geringer:
Die Keyboard-Ausgabe lässt sich sehr simpel mit den Funktionen Keyboard.init() und Keyboard.write() erledigen. Das ist genau so einfach wie der Zugriff auf die serielle Schnittstelle des Mikrocontrollers - die Komplexität des USB wird weitgehend hinter den beiden schlichten Befehlen verborgen. Etwas lästig ist lediglich, dass ein US-Keyboard simuliert wird.
Aber die Funktion usToDE() ordnet die ASCII-Zeichen des Morsedecoders vor der Übergabe an keyboard.write() so um, dass die deutsche Tastaturbelegung "herauskommt".
Um den Programmcode übersichtlicher zu halten, sind die Morsetabelle und die Übersetzungstabelle in die Header-Dateien morsedec.h und usToDE.h ausgelagert. Sie werden zu Beginn des Ardunino-Quelltextes mit #include eingebunden.


Die externe Beschaltung des Arduino Micro bzw. des Arduino Leonardo (Numerierung gemäß Bestückungsaufdruck der Arduinos)
Mithörton: DigitalPin 11
Taste: DigitalPin 10
Geschwindigkeitsvorwahl: DigitalPin 9  (60 or 90 Zeichen pro Minute)
Leerzeichenautomatik: DigitalPin 8  (Leerzeichen werden wahlweise per Zeitablauf oder das Sonderzeichen <AS> eingefügt)
Die Return-Taste wird durch das Sonderzeichen <KN> nachgebildet.
Der Fangbereich des Decoders reicht durch die zweistufige Geschwindigkeitsvorwahl von etwa 50 Zeichen / Minute bis etwa 120 Zeichen pro Minute.


Download: MorseKB.zip
 

// Arduino Morse Decoder
// Software bases on:
// Burkhard Kainka
// morse.bas
// morse code decoder with Mega169 and LCD butterfly driver
// and
// http://www.arduino.cc/en/Tutorial/KeyboardSerial



// screwed up by Ralf Beesner, DK5BU

// ported to Arduino Leonardo and changed for output via virtual USB keyboard
// some keycodes have been added, e.g. + - ? ( ) . ,
// and, most important keycode: space between words ;-)
// all timing constants are derived from the duration of a short morse element
// ("dit"), so its easier to change speed

// there are two ways to insert spaces: by simply waiting (look at mainloop for
// variable "iconst") or by a dedicated character (morsecode <AS>; wait a
// second) which is better for talking to a computer

// Return (ASCII 13) is generated by the morsecode <KN>
// Backspace (ASCII 8) is generated by morsecode Error (...... and .......).
// Only 6 or 7 dots are recognized as error character (maximum possible length
// of a character is 7)

// Buzzer is attached to DigitalPin 11
// Keyer is attached to DigitalPin 10
// Speed switch is attached to DigitalPin 9 (60 or 90 characters per minute)
// Space switch is attached to DigitalPin 8 (inserts space by idling time or
// only by character <AS>)



#include "usToDE.h"
#include "morsedec.h"

static unsigned char key;
static unsigned char keystrokeDE;
static unsigned char morsechar;
static unsigned int timepressed;
static unsigned int timenotpressed;
static unsigned char charactercode;
static unsigned int idling;

static unsigned int dithalf;
static unsigned int tpconst;
static unsigned int tnpconst;
static unsigned int iconst;


void setup() {

Keyboard.begin();

#define Buzzer 11
#define Keyer 10
#define Speedsw 9
#define Spacesw 8
#define Freq 700

pinMode(Buzzer, OUTPUT);
pinMode(Keyer, INPUT_PULLUP);
pinMode(Speedsw, INPUT_PULLUP);
pinMode(Spacesw, INPUT_PULLUP);
}

//......................................................



void printdisplay(void){

morsechar = morsetable[charactercode];
// Keyboard.print(morsechar);
// if (morsechar > 123){
// Keyboard.write(morsechar);
// }
// else{
//if (morsechar < 123){
keystrokeDE = (usToDE[morsechar]);
Keyboard.write(keystrokeDE);
// }


}


void getkey(void){

key = !( digitalRead(Keyer) ); //if key pressed: key = 1
if (key > 0){
tone(Buzzer, Freq);
}
else{
noTone(Buzzer);
}
}


void getkeytimes(void){

timepressed = 0;
timenotpressed = 0;
idling = 0;
do {
getkey();
delay (1);
idling++;
} while (key == 0);

do {
delay (1);
timepressed++;
getkey();
} while (key > 0);

do {
delay (1);
timenotpressed++;
getkey();
} while ((key == 0) & (timenotpressed < tnpconst));

}


//-----------------------------------------------------



void loop() {

if ( !( digitalRead(Speedsw))) { //Speedswitch Low
dithalf = 33; // duration of half a dit in ms; speed is 90 characters / min.
}
else{
dithalf = 50; // duration of half a dit in ms; speed is 60 characters / min.
}

tpconst = dithalf * 3; // 1.5 * Dit; maximum tinme for a dit
tnpconst = dithalf * 4; // 2 * Dit; minimum time for a dah
iconst = dithalf * 6; // space between words
charactercode = 1;

do {

getkeytimes();
if ((idling > iconst) & ( !(digitalRead (Spacesw)))){ // inserts space between morse words
printdisplay(); // may be deactivated if you want to insert spaces only by <AS>
}
charactercode = charactercode << 1;
if (timepressed > tpconst){
charactercode++;
}
} while (timenotpressed < tnpconst);
printdisplay();

}


Datei morsedec.h:

unsigned char morsetable[129] = {
0,
32, // "space" 00000001 ASCII 32
101, // "E", . , 00000010, ASCII 69
116, // "T", - , 00000011, ASCII 84
105, // "I", .. , 00000100, ASCII 73
97, // "A", .- , 00000110, ASCII 65
110, // "N", -. , 00000110, ASCII 78
109, // "M", -- , 00000111, ASCII 77
115, // "S", ... , 00001000, ASCII 83
117, // "U", ..- , 00001001, ASCII 85
114, // "R", .-. , 00001010, ASCII 82
119, // "W", .-- , 00001011, ASCII 87
100, // "D", -.. , 00001100, ASCII 68
107, // "K", -.- , 00001101, ASCII 75
103, // "G", --. , 00001110, ASCII 71
111, // "O", --- , 00001111, ASCII 79
104, // "H", .... , 00010000, ASCII 72
118, // "V", ...- , 00010001, ASCII 86
102, // "F", ..-. , 00010010, ASCII 70
183, // "Ü", ..-- , 00010011, ASCII 183
108, // "L", .-.. , 00010100, ASCII 76
188, // "Ä" .-.- , 00010101, ASCII 188
112, // "P", .--. , 00010110, ASCII 80
106, // "J", .--- , 00010111, ASCII 74
98, // "B", -... , 00011000, ASCII 66
120, // "X", -..- , 00011001, ASCII 88
99, // "C", -.-. , 00011010, ASCII 67
121, // "Y", -.-- , 00011011, ASCII 89
122, // "Z", --.. , 00011100, ASCII 90
113, // "Q", --.- , 00011101, ASCII 81
187, // "Ö", ---. , 00011110, ASCII 187
0,
53, // "5", ..... , 00100000, ASCII 53
52, // "4", ....- , 00100001, ASCII 52
0,
51, // "3", ...-- , 00100011, ASCII 51
0,
0,
0,
50, // "2", ..--- , 00100111, ASCII 50
32, // "as" .-... , 00101000, ASCII 32
0,
43, // "+" .-.-. , 00101010 ASCII 43
0,
0,
0,
0,
49, // "1", .---- , 00101111, ASCII 49
54, // "6", -.... , 00110000, ASCII 54
61, // "=" -...- , 00110001, ASCII 61
47, // "/" -..-. , 00110010, ASCII 47
0,
0,
0,
13, // "kn" -.--. , 00110110 ASCII 13 (Return)
0,
55, // "7", --... , 00111000, ASCII 55
0,
0,
0,
56, // "8", ---.. , 00111100, ASCII 56
0,
57, // "9", ----. , 00111110, ASCII 57
48, // "0", ----- , 00111111, ASCII 48
8, // "......" , 01000000, ASCII 8 (Backspace)
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
63, // "?", ..--.. , 01001100, ASCII 63
0,
0,
0,
0,
0,
34, // "/" .-..-. , 01010010, ASCII 34
0,
0,
46, // ".", .-.-.- , 01010101, ASCII 46
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
45, // "-", -....- , 01100001, ASCII 45
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
41, // ")", -.--.- , 01101101, ASCII 41
0,
0,
0,
0,
0,
44, // ",", --..-- , 01110011, ASCII 44
0,
0,
0,
0,
58, // ":", ---... , 01111000, ASCII 58
0,
0,
0,
0,
0,
0,
0,
8, // "......." , 10000000, ASCII 8 (Backspace)
};


Elektronik-Labor   Projekte   AVR