Project showcase
Morse Keyboard

Morse Keyboard © GPL3+

A novel input device implemented with a binary tree.

  • 731 views
  • 1 comment
  • 3 respects

Components and supplies

Apps and online services

About this project

Description:

Some years ago I saw a neat little device(1) which used 3 keys (dot, space, dash) to record Morse code onto tape for high speed transmission; I was quite taken by the idea of using this as a computer keyboard but, at the time, had no idea how to do the hardware or software.

The hardware problem was solved by the advent of chips with built in USB human interface device (HID) support.

The software problem was solved when I noticed the similarity between a binary tree and a Morse code dichotomic search table.

The dichotomic search table is one way of learning Morse, part of such a table is shown in Figure 1. You start with either a dot or dash and keep adding until you have spelt out the letter you want. For example, if you want the letter a, you send a dot then a dash.

Figure 2 shows a binary tree, it looks, structurally, remarkably similar to our dichotomic search table.

Binary tree

A binary tree is implemented as an array; we ignore array position 0 and use the numbers on each node as the index for the data (Figure 3).

We can traverse the indexes of a binary tree using simple math either forward, as in our case, or backwards.

  • To traverse forward to a left hand node we multiply the current index by 2.
  • To traverse forward to a right hand node we multiply the current index by 2 and then add 1.

So my thinking was that I copy the dichotomic search table into the binary tree as its data then use each press of a dot or dash button to advance through the tree index numbers, left for dot, right for dash and when the space button is pressed send the appropriate character out via the USB port.

Additional detail:

We make node 0 a null value, node 1 the space character and start filling in the letters from node 2 (Figure 4).

We must also add in null values at the positions where there are no letters; you cannot compact a binary tree by removing the empty spaces and still have it work correctly.

I added 2 extra buttons to the design to directly output the backspace and return characters.

Constraint:

We should not exceed the array limit.

Design decision:

If a button push would take us over the array limit we print out the character at the last legal array position.

The circuit:

5 switches with capacitor resistor debounce circuit feeding to a Schmitt trigger NOT gate of a 74HCT14 chip.

Each gate output is connected to an Arduino external interrupt pin.

Starting from the right the buttons are space/enter, dot, dash, backspace and return.

The software:

Setup:

  • We set up the required port pins as input and attach the interrupt handlers.

Loop:

Check do_new_line flag, if true

  • Send return character
  • Reset do_new_line flag to false

Check do_bk_space flag, if true

  • Send delete character
  • Reset do_bk_space flag to false

Check do_character flag, if true

  • Send character at the current character array index
  • Reset character array index to 1
  • Reset do_character flag to false

Check increment_dot flag, if true

  • Compute and check the next array position against the array limit, if we exceed the limit set do_character flag to print the last legal character else update the character array index.
  • Either way reset increment_dot flag to false

Check increment_dash flag, if true

  • Compute and check the next array position against the array limit, if we exceed the limit set do_character flag to print the last legal character else update the character array index.
  • Either way reset increment_dash flag to false

Interrupts:

An interrupt occurs each time a button is pressed, there is a separate interrupt service routine for each button which sets a flag for the loop code to recognize then exits.

Notes:

I have tried to encode the special characters into the array but I have had no success outputting them. I did read a comment on the Arduino help pages “Note: Not every possible ASCII character, particularly the non-printing ones, can be sent with the Keyboard library.”(3)

I initially failed to get the debounce circuit working with the stated resistor, capacitor values because I was using the 74LS14 version of the Schmitt NOT gate chip.

The 74HCT14 chip could support 6 buttons but the Atmel 32U4 chip will only support 5 external interrupts (these are easier to code up than the pin change interrupt).

References:

(1) I later found that this device is a US Dot-dash coder (CO-3B, MX-4495). Source - http://www.cryptomuseum.com/burst/gra71/index.htm (retrieved 27/Feb/2017)

(2) Source - http://www.cryptomuseum.com/radio/morse/index.htm (retrieved 27/Feb/-2017)

(3) Source – https://www.arduino.cc/en/Reference/MouseKeyboard (retrieved 30/May/2017)

Code

Morse keyboard codeC/C++
    
#include "Keyboard.h"
/*
//left handed -- checked
const int delete_buttonPin = 0;          // input pin for delete pushbutton
const int dash_buttonPin = 3;            // input pin for dash pushbutton
const int dot_buttonPin = 2;             // input pin for dot pushbutton
const int space_buttonPin = 7;           // input pin for space pushbutton
const int new_line_buttonPin = 1;          // input pin for new line pushbutton
*/

//right handed
const int delete_buttonPin = 2;          // input pin for delete pushbutton
const int dash_buttonPin = 3;            // input pin for dash pushbutton
const int dot_buttonPin = 0;             // input pin for dot pushbutton
const int space_buttonPin = 1;           // input pin for space pushbutton
const int new_line_buttonPin=7 ;          // input pin for new line pushbutton


volatile static bool do_new_line=false;
volatile static bool do_bk_space=false;
volatile static bool do_character=false;
volatile static bool increment_dot=false;
volatile static bool increment_dash=false;

const unsigned char characters_array[]={
0x00,' ',//positions 0 not used position 1 returns space character
'e','t',//2
'i','a','n','m',//4
's','u','r','w','d','k','g','o',//8
'h','v','f',252,'l',228,'p','j','b','x','c','y','z','q',246,154,//16
'5','4','S','3',233,0x00,208,'2',0x00,232,'+',0x00,254,224,'J','1','6','=','/',0x00,231,0x00,'(',0x00,'7',0x00,'G',241,'8',0x00,'9','0',//32
0x00,0x00,0x00,0x00,'$',0x00,0x00,0x00,0x00,0x00,0x00,0x00,'?','_',0x00,0x00,0x00,0x00,'"',0x00,0x00,'.',0x00,0x00,0x00,0x00,'@',0x00,0x00,0x00,39,0x00,//64 part 1
0x00,'-',0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,';','!',0x00,')',0x00,0x00,0x00,0x00,0x00,',',0x00,0x00,0x00,0x00,':',0x00,0x00,0x00,0x00,0x00,0x00,0x00,//64 part 2
};
const int characters_array_limit=127;//128 characters so 0-127


void setup() {
  
// make the button pins input:
pinMode(delete_buttonPin, INPUT);
pinMode(dash_buttonPin, INPUT);
pinMode(dot_buttonPin, INPUT);
pinMode(space_buttonPin, INPUT);
pinMode(new_line_buttonPin,INPUT);
//assign interrupt handlers
attachInterrupt(digitalPinToInterrupt(delete_buttonPin), bk_space,RISING );
attachInterrupt(digitalPinToInterrupt(dash_buttonPin), dash, RISING);
attachInterrupt(digitalPinToInterrupt(dot_buttonPin), dot, RISING);
attachInterrupt(digitalPinToInterrupt(space_buttonPin), space, RISING);
attachInterrupt(digitalPinToInterrupt(new_line_buttonPin), new_line, RISING);        
// initialize control over the keyboard:
Keyboard.begin();
}

void loop() {

static int characters_array_index=1;

if (do_new_line){Keyboard.write('\n');do_new_line=false;}//new line character

if (do_bk_space){Keyboard.write('\b');do_bk_space=false;}//backspace character (for deletion)

if (do_character){Keyboard.write((unsigned char)characters_array[characters_array_index]);characters_array_index=1;do_character=false; }

if(increment_dot){if ((characters_array_index*2)>characters_array_limit){increment_dot=false;do_character=true;} 
                        else {characters_array_index=characters_array_index*2;increment_dot=false;} }

if(increment_dash){if (((characters_array_index*2)+1)>characters_array_limit){increment_dash=false;do_character=true;} 
                        else {characters_array_index=(characters_array_index*2)+1;increment_dash=false;} }
                        
}

//my_interrupt_functions 
void dot(void) {increment_dot=true;}
void dash(void) {increment_dash=true;}
void space(void) {do_character=true;}
void bk_space(void) {do_bk_space=true;}
void new_line(void) {do_new_line=true;}

Schematics

Breadboard layout morse keyboard
Morse keypad 5 button bb vmmhjm3uws
Debounce circuit schematic

Comments

Similar projects you might like

Ternary Chord Keyboard

Project tutorial by Mr_Glenn

  • 3,401 views
  • 4 comments
  • 9 respects

Morse Code Transmitter - Light Signal

Project showcase by Alireza Karkon

  • 1,343 views
  • 1 comment
  • 7 respects

Morse Code Translator

Project showcase by Team ONYX

  • 10,936 views
  • 2 comments
  • 16 respects

A Pocket-Sized Touch Keyboard

Project tutorial by Amal Mathew

  • 3,645 views
  • 3 comments
  • 16 respects

Morse Code Receiver

Project showcase by Alireza Karkon

  • 3,473 views
  • 5 comments
  • 23 respects

Wireless Keyboard from TV Remote

Project tutorial by Amal Mathew

  • 2,945 views
  • 2 comments
  • 16 respects
Add projectSign up / Login